aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-10-23 13:56:16 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-10-23 13:56:16 +0200
commitff67a6b9aaddb2dea6ed4a3f7df8a0c6acf131c2 (patch)
tree34d81901340c14191fab6e0c5a424f45385ae2aa
parente7549b926dd3ceec048f5689df90d4ec970c9419 (diff)
downloadkernel_samsung_smdk4412-ff67a6b9aaddb2dea6ed4a3f7df8a0c6acf131c2.zip
kernel_samsung_smdk4412-ff67a6b9aaddb2dea6ed4a3f7df8a0c6acf131c2.tar.gz
kernel_samsung_smdk4412-ff67a6b9aaddb2dea6ed4a3f7df8a0c6acf131c2.tar.bz2
last driver import from 3.2.72 for now
-rw-r--r--drivers/cpufreq/Kconfig116
-rw-r--r--drivers/cpufreq/Makefile18
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq.c22
-rw-r--r--drivers/cpufreq/cpufreq_adaptive.c952
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c4
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c1003
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c475
-rw-r--r--drivers/cpufreq/cpufreq_pegasusq.c1520
-rw-r--r--drivers/cpufreq/cpufreq_stats.c26
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c40
-rw-r--r--drivers/cpufreq/dvfs_monitor.c236
-rw-r--r--drivers/cpufreq/e_powersaver.c135
-rw-r--r--drivers/cpufreq/powernow-k6.c147
-rw-r--r--drivers/cpufreq/powernow-k8.c56
-rw-r--r--drivers/cpufreq/speedstep-lib.c3
-rw-r--r--drivers/cpufreq/speedstep-smi.c12
-rw-r--r--drivers/crypto/Kconfig58
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/ace.c2651
-rw-r--r--drivers/crypto/ace.h103
-rw-r--r--drivers/crypto/ace_sfr.h497
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c5
-rw-r--r--drivers/crypto/hifn_795x.c6
-rw-r--r--drivers/crypto/ixp4xx_crypto.c1
-rw-r--r--drivers/crypto/mv_cesa.c1
-rw-r--r--drivers/crypto/n2_core.c37
-rw-r--r--drivers/crypto/omap-sham.c180
-rw-r--r--drivers/crypto/padlock-aes.c6
-rw-r--r--drivers/crypto/padlock-sha.c8
-rw-r--r--drivers/crypto/picoxcell_crypto.c121
-rw-r--r--drivers/crypto/talitos.c66
-rw-r--r--drivers/edac/Kconfig16
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/amd64_edac.c37
-rw-r--r--drivers/edac/cell_edac.c2
-rw-r--r--drivers/edac/cpc925_edac.c67
-rw-r--r--drivers/edac/edac_core.h350
-rw-r--r--drivers/edac/edac_mc.c11
-rw-r--r--drivers/edac/edac_mce.c61
-rw-r--r--drivers/edac/edac_stub.c2
-rw-r--r--drivers/edac/i7300_edac.c95
-rw-r--r--drivers/edac/i7core_edac.c421
-rw-r--r--drivers/edac/i82975x_edac.c11
-rw-r--r--drivers/edac/mce_amd.c46
-rw-r--r--drivers/edac/mce_amd.h6
-rw-r--r--drivers/edac/mce_amd_inj.c1
-rw-r--r--drivers/edac/mpc85xx_edac.c18
-rw-r--r--drivers/edac/ppc4xx_edac.c2
-rw-r--r--drivers/gpu/vga/vgaarb.c65
-rw-r--r--drivers/hwspinlock/Kconfig27
-rw-r--r--drivers/hwspinlock/Makefile1
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c165
-rw-r--r--drivers/hwspinlock/hwspinlock_internal.h40
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c127
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c24
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c6
-rw-r--r--drivers/i2c/busses/Kconfig30
-rw-r--r--drivers/i2c/busses/Makefile6
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c61
-rw-r--r--drivers/i2c/busses/i2c-au1550.c282
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c4
-rw-r--r--drivers/i2c/busses/i2c-cpm.c7
-rw-r--r--drivers/i2c/busses/i2c-davinci.c8
-rw-r--r--drivers/i2c/busses/i2c-designware.c847
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c335
-rw-r--r--drivers/i2c/busses/i2c-gpio.c4
-rw-r--r--drivers/i2c/busses/i2c-highlander.c4
-rw-r--r--drivers/i2c/busses/i2c-i801.c6
-rw-r--r--drivers/i2c/busses/i2c-imx.c46
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c96
-rw-r--r--drivers/i2c/busses/i2c-nuc900.c4
-rw-r--r--drivers/i2c/busses/i2c-omap.c166
-rw-r--r--drivers/i2c/busses/i2c-piix4.c27
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c6
-rw-r--r--drivers/i2c/busses/i2c-pxa.c7
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c244
-rw-r--r--drivers/i2c/busses/i2c-s6000.c5
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c3
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c2
-rw-r--r--drivers/i2c/busses/i2c-stu300.c2
-rw-r--r--drivers/i2c/busses/i2c-tegra.c102
-rw-r--r--drivers/i2c/busses/scx200_acb.c6
-rw-r--r--drivers/i2c/i2c-boardinfo.c1
-rw-r--r--drivers/i2c/i2c-core.c9
-rw-r--r--drivers/i2c/i2c-dev.c2
-rw-r--r--drivers/ide/Kconfig32
-rw-r--r--drivers/ide/at91_ide.c2
-rw-r--r--drivers/ide/au1xxx-ide.c46
-rw-r--r--drivers/ide/buddha.c1
-rw-r--r--drivers/ide/cmd640.c1
-rw-r--r--drivers/ide/cy82c693.c6
-rw-r--r--drivers/ide/icside.c2
-rw-r--r--drivers/ide/ide-acpi.c1
-rw-r--r--drivers/ide/ide-atapi.c1
-rw-r--r--drivers/ide/ide-cd.c1
-rw-r--r--drivers/ide/ide-disk_proc.c1
-rw-r--r--drivers/ide/ide-dma-sff.c1
-rw-r--r--drivers/ide/ide-dma.c1
-rw-r--r--drivers/ide/ide-eh.c1
-rw-r--r--drivers/ide/ide-floppy.c1
-rw-r--r--drivers/ide/ide-floppy_proc.c1
-rw-r--r--drivers/ide/ide-io-std.c1
-rw-r--r--drivers/ide/ide-ioctls.c1
-rw-r--r--drivers/ide/ide-legacy.c1
-rw-r--r--drivers/ide/ide-lib.c1
-rw-r--r--drivers/ide/ide-pnp.c1
-rw-r--r--drivers/ide/ide-tape.c1
-rw-r--r--drivers/ide/ide-taskfile.c1
-rw-r--r--drivers/ide/ide-xfer-mode.c1
-rw-r--r--drivers/ide/ide_platform.c6
-rw-r--r--drivers/ide/macide.c1
-rw-r--r--drivers/ide/palm_bk3710.c2
-rw-r--r--drivers/ide/piix.c18
-rw-r--r--drivers/ide/pmac.c1
-rw-r--r--drivers/ide/q40ide.c1
-rw-r--r--drivers/ide/setup-pci.c1
-rw-r--r--drivers/ide/tc86c001.c1
-rw-r--r--drivers/ide/triflex.c16
-rw-r--r--drivers/ide/tx4939ide.c4
-rw-r--r--drivers/media/video/pwc/Kconfig1
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c803
-rw-r--r--drivers/media/video/pwc/pwc-dec1.c28
-rw-r--r--drivers/media/video/pwc/pwc-dec1.h8
-rw-r--r--drivers/media/video/pwc/pwc-dec23.c22
-rw-r--r--drivers/media/video/pwc/pwc-dec23.h10
-rw-r--r--drivers/media/video/pwc/pwc-if.c1259
-rw-r--r--drivers/media/video/pwc/pwc-ioctl.h323
-rw-r--r--drivers/media/video/pwc/pwc-kiara.c1
-rw-r--r--drivers/media/video/pwc/pwc-misc.c4
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c17
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.h40
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c1237
-rw-r--r--drivers/media/video/pwc/pwc.h409
-rw-r--r--drivers/mtd/Kconfig23
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/afs.c4
-rw-r--r--drivers/mtd/ar7part.c3
-rw-r--r--drivers/mtd/cmdlinepart.c8
-rw-r--r--drivers/mtd/ftl.c41
-rw-r--r--drivers/mtd/inftlcore.c69
-rw-r--r--drivers/mtd/inftlmount.c116
-rw-r--r--drivers/mtd/maps/Kconfig26
-rw-r--r--drivers/mtd/maps/Makefile2
-rw-r--r--drivers/mtd/maps/bcm963xx-flash.c1
-rw-r--r--drivers/mtd/maps/bfin-async-flash.c18
-rw-r--r--drivers/mtd/maps/ceiva.c341
-rw-r--r--drivers/mtd/maps/dc21285.c13
-rw-r--r--drivers/mtd/maps/edb7312.c134
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c16
-rw-r--r--drivers/mtd/maps/h720x-flash.c23
-rw-r--r--drivers/mtd/maps/impa7.c28
-rw-r--r--drivers/mtd/maps/intel_vr_nor.c7
-rw-r--r--drivers/mtd/maps/ixp2000.c22
-rw-r--r--drivers/mtd/maps/ixp4xx.c32
-rw-r--r--drivers/mtd/maps/lantiq-flash.c20
-rw-r--r--drivers/mtd/maps/latch-addr-flash.c24
-rw-r--r--drivers/mtd/maps/pcmciamtd.c124
-rw-r--r--drivers/mtd/maps/physmap.c38
-rw-r--r--drivers/mtd/maps/physmap_of.c80
-rw-r--r--drivers/mtd/maps/plat-ram.c35
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c22
-rw-r--r--drivers/mtd/maps/rbtx4939-flash.c24
-rw-r--r--drivers/mtd/maps/sa1100-flash.c30
-rw-r--r--drivers/mtd/maps/solutionengine.c30
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c33
-rw-r--r--drivers/mtd/mtd_blkdevs.c7
-rw-r--r--drivers/mtd/mtdblock.c18
-rw-r--r--drivers/mtd/mtdblock_ro.c1
-rw-r--r--drivers/mtd/mtdchar.c215
-rw-r--r--drivers/mtd/mtdconcat.c10
-rw-r--r--drivers/mtd/mtdcore.c70
-rw-r--r--drivers/mtd/mtdcore.h3
-rw-r--r--drivers/mtd/mtdoops.c2
-rw-r--r--drivers/mtd/mtdpart.c67
-rw-r--r--drivers/mtd/mtdsuper.c21
-rw-r--r--drivers/mtd/mtdswap.c31
-rw-r--r--drivers/mtd/nand/Kconfig55
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/ams-delta.c2
-rw-r--r--drivers/mtd/nand/atmel_nand.c34
-rw-r--r--drivers/mtd/nand/au1550nd.c35
-rw-r--r--drivers/mtd/nand/autcpu12.c4
-rw-r--r--drivers/mtd/nand/bcm_umi_nand.c59
-rw-r--r--drivers/mtd/nand/cafe_nand.c22
-rw-r--r--drivers/mtd/nand/cmx270_nand.c24
-rw-r--r--drivers/mtd/nand/cs553x_nand.c15
-rw-r--r--drivers/mtd/nand/davinci_nand.c39
-rw-r--r--drivers/mtd/nand/denali.c6
-rw-r--r--drivers/mtd/nand/diskonchip.c9
-rw-r--r--drivers/mtd/nand/edb7312.c203
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c75
-rw-r--r--drivers/mtd/nand/fsl_upm.c16
-rw-r--r--drivers/mtd/nand/fsmc_nand.c77
-rw-r--r--drivers/mtd/nand/h1910.c19
-rw-r--r--drivers/mtd/nand/jz4740_nand.c18
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c24
-rw-r--r--drivers/mtd/nand/mxc_nand.c38
-rw-r--r--drivers/mtd/nand/nand_base.c1148
-rw-r--r--drivers/mtd/nand/nand_bbt.c693
-rw-r--r--drivers/mtd/nand/nand_bch.c4
-rw-r--r--drivers/mtd/nand/nand_ecc.c10
-rw-r--r--drivers/mtd/nand/nandsim.c4
-rw-r--r--drivers/mtd/nand/ndfc.c22
-rw-r--r--drivers/mtd/nand/nomadik_nand.c1
-rw-r--r--drivers/mtd/nand/nuc900_nand.c1
-rw-r--r--drivers/mtd/nand/omap2.c23
-rw-r--r--drivers/mtd/nand/orion_nand.c16
-rw-r--r--drivers/mtd/nand/pasemi_nand.c3
-rw-r--r--drivers/mtd/nand/plat_nand.c25
-rw-r--r--drivers/mtd/nand/ppchameleonevb.c47
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c463
-rw-r--r--drivers/mtd/nand/r852.c6
-rw-r--r--drivers/mtd/nand/rtc_from4.c5
-rw-r--r--drivers/mtd/nand/s3c2410.c27
-rw-r--r--drivers/mtd/nand/sharpsl.c13
-rw-r--r--drivers/mtd/nand/sm_common.c3
-rw-r--r--drivers/mtd/nand/socrates_nand.c28
-rw-r--r--drivers/mtd/nand/tmio_nand.c17
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c8
-rw-r--r--drivers/mtd/nftlcore.c37
-rw-r--r--drivers/mtd/nftlmount.c26
-rw-r--r--drivers/mtd/ofpart.c112
-rw-r--r--drivers/mtd/redboot.c14
-rw-r--r--drivers/mtd/rfd_ftl.c1
-rw-r--r--drivers/mtd/sm_ftl.c26
-rw-r--r--drivers/mtd/ssfdc.c46
-rw-r--r--drivers/nfc/Kconfig44
-rw-r--r--drivers/nfc/Makefile5
-rw-r--r--drivers/nfc/pn65n.c496
233 files changed, 5955 insertions, 16788 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 8112af3..e24a2a1 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -99,30 +99,6 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
Be aware that not all cpufreq drivers support the conservative
governor. If unsure have a look at the help section of the
driver. Fallback governor will be the performance governor.
-
-config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
- bool "interactive"
- select CPU_FREQ_GOV_INTERACTIVE
- help
- Use the CPUFreq governor 'interactive' as default. This allows
- you to get a full dynamic cpu frequency capable system by simply
- loading your cpufreq low-level hardware driver, using the
- 'interactive' governor for latency-sensitive workloads.
-
-config CPU_FREQ_DEFAULT_GOV_ADAPTIVE
- bool "adaptive"
- select CPU_FREQ_GOV_ADAPTIVE
- help
- Use the CPUFreq governor 'adaptive' as default. This allows
- you to get a full dynamic cpu frequency capable system by simply
- loading your cpufreq low-level hardware driver, using the
- 'adaptive' governor for latency-sensitive workloads and demanding
- performance.
-
-config CPU_FREQ_DEFAULT_GOV_PEGASUSQ
- bool "pegasusq"
- select CPU_FREQ_GOV_PEGASUSQ
-
endchoice
config CPU_FREQ_GOV_PERFORMANCE
@@ -180,45 +156,6 @@ config CPU_FREQ_GOV_ONDEMAND
If in doubt, say N.
-config CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- bool "flexrate interface for 'ondemand' cpufreq policy governor"
- depends on CPU_FREQ_GOV_ONDEMAND
- help
- Flexrate for 'ondemand' governor provides an interface to request
- faster polling temporarily. This is to let it react quickly to
- load changes when there is high probablity of load increase
- in short time. For example, when a user event occurs, we have
- use this interface. It does not increase the frequency
- unconditionally; however, it allows ondemand to react fast
- by temporarily decreasing sampling rate. Flexrate provides both
- sysfs interface and in-kernel interface.
-
-config CPU_FREQ_GOV_ONDEMAND_FLEXRATE_MAX_DURATION
- int "flexrate's maximum duration of sampling rate override"
- range 5 500
- depends on CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- default "100"
- help
- The maximum number of ondemand sampling whose rate is
- overriden by Flexrate for ondemand.
-
-config CPU_FREQ_GOV_INTERACTIVE
- tristate "'interactive' cpufreq policy governor"
- help
- 'interactive' - This driver adds a dynamic cpufreq policy governor
- designed for latency-sensitive workloads.
-
- This governor attempts to reduce the latency of clock
- increases so that the system is more responsive to
- interactive workloads.
-
- To compile this driver as a module, choose M here: the
- module will be called cpufreq_interactive.
-
- For details, take a look at linux/Documentation/cpu-freq.
-
- If in doubt, say N.
-
config CPU_FREQ_GOV_CONSERVATIVE
tristate "'conservative' cpufreq governor"
depends on CPU_FREQ
@@ -242,53 +179,20 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N.
-config CPU_FREQ_GOV_ADAPTIVE
- tristate "'adaptive' cpufreq policy governor"
- help
- 'adaptive' - This driver adds a dynamic cpufreq policy governor
- designed for latency-sensitive workloads and also for demanding
- performance.
-
- This governor attempts to reduce the latency of clock
- increases so that the system is more responsive to
- interactive workloads in loweset steady-state but to
- to reduce power consumption in middle operation level level up
- will be done in step by step to prohibit system from going to
- max operation level.
-
- To compile this driver as a module, choose M here: the
- module will be called cpufreq_adaptive.
-
- For details, take a look at linux/Documentation/cpu-freq.
-
- If in doubt, say N.
-
-config CPU_FREQ_GOV_PEGASUSQ
- tristate "'pegasusq' cpufreq policy governor"
-
-config CPU_FREQ_GOV_SLP
- tristate "'slp' cpufreq policy governor"
-
-config SLP_CHECK_CPU_LOAD
- bool "check load and frequency of cpu"
- depends on CPU_FREQ_GOV_SLP
-
-config SLP_GOV_DYNAMIC_PARAMS
- bool "check SLP GOV. Dynamic Params feature"
- depends on CPU_FREQ_GOV_SLP
-
-config CPU_FREQ_DVFS_MONITOR
- bool "dvfs monitor"
- depends on CPU_FREQ
- help
- This option adds a proc node for dvfs monitoring.
- /proc/dvfs_mon
-
-
menu "x86 CPU frequency scaling drivers"
depends on X86
source "drivers/cpufreq/Kconfig.x86"
endmenu
+menu "ARM CPU frequency scaling drivers"
+depends on ARM
+source "drivers/cpufreq/Kconfig.arm"
+endmenu
+
+menu "PowerPC CPU frequency scaling drivers"
+depends on PPC32 || PPC64
+source "drivers/cpufreq/Kconfig.powerpc"
+endmenu
+
endif
endmenu
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 101c6ed..a48bc02 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -8,18 +8,12 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
-obj-$(CONFIG_CPU_FREQ_GOV_SLP) += cpufreq_slp.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
-obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o
-obj-$(CONFIG_CPU_FREQ_GOV_ADAPTIVE) += cpufreq_adaptive.o
-obj-$(CONFIG_CPU_FREQ_GOV_PEGASUSQ) += cpufreq_pegasusq.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
-obj-$(CONFIG_CPU_FREQ_DVFS_MONITOR) += dvfs_monitor.o
-
-##################################################################################d
+##################################################################################
# x86 drivers.
# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
# K8 systems. ACPI is preferred to all other hardware-specific drivers.
@@ -43,7 +37,13 @@ obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
-##################################################################################d
-
+##################################################################################
# ARM SoC drivers
obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
+obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
+obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
+
+##################################################################################
+# PowerPC platform drivers
+obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 596d5dd..56c6c6b 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -655,7 +655,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
acpi_processor_notify_smm(THIS_MODULE);
/* Check for APERF/MPERF support in hardware */
- if (cpu_has(c, X86_FEATURE_APERFMPERF))
+ if (boot_cpu_has(X86_FEATURE_APERFMPERF))
acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 9785cf7..987a165 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -189,7 +189,7 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
* systems as each CPU might be scaled differently. So, use the arch
* per-CPU loops_per_jiffy value wherever possible.
*/
-#if !defined CONFIG_SMP || defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#ifndef CONFIG_SMP
static unsigned long l_p_j_ref;
static unsigned int l_p_j_ref_freq;
@@ -1199,6 +1199,26 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_quick_get);
+/**
+ * cpufreq_quick_get_max - get the max reported CPU frequency for this CPU
+ * @cpu: CPU number
+ *
+ * Just return the max possible frequency for a given CPU.
+ */
+unsigned int cpufreq_quick_get_max(unsigned int cpu)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ unsigned int ret_freq = 0;
+
+ if (policy) {
+ ret_freq = policy->max;
+ cpufreq_cpu_put(policy);
+ }
+
+ return ret_freq;
+}
+EXPORT_SYMBOL(cpufreq_quick_get_max);
+
static unsigned int __cpufreq_get(unsigned int cpu)
{
diff --git a/drivers/cpufreq/cpufreq_adaptive.c b/drivers/cpufreq/cpufreq_adaptive.c
deleted file mode 100644
index ad7f7de..0000000
--- a/drivers/cpufreq/cpufreq_adaptive.c
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
- * drivers/cpufreq/cpufreq_adaptive.c
- *
- * Copyright (C) 2001 Russell King
- * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
- * Jun Nakajima <jun.nakajima@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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/kernel_stat.h>
-#include <linux/mutex.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <linux/ktime.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-
-#include <mach/ppmu.h>
-
-/*
- * dbs is used in this file as a shortform for demandbased switching
- * It helps to keep variable names smaller, simpler
- */
-
-#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
-#define DEF_FREQUENCY_UP_THRESHOLD (80)
-#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
-#define MICRO_FREQUENCY_UP_THRESHOLD (95)
-#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
-#define MIN_FREQUENCY_UP_THRESHOLD (11)
-#define MAX_FREQUENCY_UP_THRESHOLD (100)
-#define MIN_ONDEMAND_THRESHOLD (4)
-/*
- * The polling frequency of this governor depends on the capability of
- * the processor. Default polling frequency is 1000 times the transition
- * latency of the processor. The governor will work on any processor with
- * transition latency <= 10mS, using appropriate sampling
- * rate.
- * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
- * this governor will not work.
- * All times here are in uS.
- */
-#define MIN_SAMPLING_RATE_RATIO (2)
-
-static unsigned int min_sampling_rate;
-
-#define LATENCY_MULTIPLIER (1000)
-#define MIN_LATENCY_MULTIPLIER (100)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
-
-static void (*pm_idle_old)(void);
-static void do_dbs_timer(struct work_struct *work);
-static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event);
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_adaptive = {
- .name = "adaptive",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
-};
-
-/* Sampling types */
-enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
-
-struct cpu_dbs_info_s {
- cputime64_t prev_cpu_idle;
- cputime64_t prev_cpu_iowait;
- cputime64_t prev_cpu_wall;
- cputime64_t prev_cpu_nice;
- struct cpufreq_policy *cur_policy;
- struct delayed_work work;
- struct cpufreq_frequency_table *freq_table;
- unsigned int freq_hi_jiffies;
- int cpu;
- unsigned int sample_type:1;
- bool ondemand;
- /*
- * percpu mutex that serializes governor limit change with
- * do_dbs_timer invocation. We do not want do_dbs_timer to run
- * when user is changing the governor or limits.
- */
- struct mutex timer_mutex;
-};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
-
-static unsigned int dbs_enable; /* number of CPUs using this policy */
-
-/*
- * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
- * different CPUs. It protects dbs_enable in governor start/stop.
- */
-static DEFINE_MUTEX(dbs_mutex);
-static struct task_struct *up_task;
-static struct workqueue_struct *down_wq;
-static struct work_struct freq_scale_down_work;
-static cpumask_t up_cpumask;
-static spinlock_t up_cpumask_lock;
-static cpumask_t down_cpumask;
-static spinlock_t down_cpumask_lock;
-
-static DEFINE_PER_CPU(cputime64_t, idle_in_idle);
-static DEFINE_PER_CPU(cputime64_t, idle_exit_wall);
-
-static struct timer_list cpu_timer;
-static unsigned int target_freq;
-static DEFINE_MUTEX(short_timer_mutex);
-
-/* Go to max speed when CPU load at or above this value. */
-#define DEFAULT_GO_MAXSPEED_LOAD 60
-static unsigned long go_maxspeed_load;
-
-#define DEFAULT_KEEP_MINSPEED_LOAD 30
-static unsigned long keep_minspeed_load;
-
-#define DEFAULT_STEPUP_LOAD 10
-static unsigned long step_up_load;
-
-static struct dbs_tuners {
- unsigned int sampling_rate;
- unsigned int up_threshold;
- unsigned int down_differential;
- unsigned int ignore_nice;
- unsigned int io_is_busy;
-} dbs_tuners_ins = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
- .ignore_nice = 0,
-};
-
-static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall)
-{
- u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
-
- if (iowait_time == -1ULL)
- return 0;
-
- return iowait_time;
-}
-
-static void adaptive_init_cpu(int cpu)
-{
- struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
- dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
-}
-
-/************************** sysfs interface ************************/
-
-static ssize_t show_sampling_rate_max(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- printk_once(KERN_INFO "CPUFREQ: adaptive sampling_rate_max "
- "sysfs file is deprecated - used by: %s\n", current->comm);
- return sprintf(buf, "%u\n", -1U);
-}
-
-static ssize_t show_sampling_rate_min(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", min_sampling_rate);
-}
-
-define_one_global_ro(sampling_rate_max);
-define_one_global_ro(sampling_rate_min);
-
-/* cpufreq_adaptive Governor Tunables */
-#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", dbs_tuners_ins.object); \
-}
-show_one(sampling_rate, sampling_rate);
-show_one(io_is_busy, io_is_busy);
-show_one(up_threshold, up_threshold);
-show_one(ignore_nice_load, ignore_nice);
-
-/*** delete after deprecation time ***/
-
-#define DEPRECATION_MSG(file_name) \
- printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \
- "interface is deprecated - " #file_name "\n");
-
-#define show_one_old(file_name) \
-static ssize_t show_##file_name##_old \
-(struct cpufreq_policy *unused, char *buf) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return show_##file_name(NULL, NULL, buf); \
-}
-
-/*** delete after deprecation time ***/
-
-static ssize_t store_sampling_rate(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;
-
- mutex_lock(&dbs_mutex);
- dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
- mutex_unlock(&dbs_mutex);
-
- return count;
-}
-
-static ssize_t store_io_is_busy(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;
-
- mutex_lock(&dbs_mutex);
- dbs_tuners_ins.io_is_busy = !!input;
- mutex_unlock(&dbs_mutex);
-
- return count;
-}
-
-static ssize_t store_up_threshold(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 || input > MAX_FREQUENCY_UP_THRESHOLD ||
- input < MIN_FREQUENCY_UP_THRESHOLD) {
- return -EINVAL;
- }
-
- mutex_lock(&dbs_mutex);
- dbs_tuners_ins.up_threshold = input;
- mutex_unlock(&dbs_mutex);
-
- return count;
-}
-
-static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int input;
- int ret;
-
- unsigned int j;
-
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
-
- if (input > 1)
- input = 1;
-
- mutex_lock(&dbs_mutex);
- if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
- mutex_unlock(&dbs_mutex);
- return count;
- }
- dbs_tuners_ins.ignore_nice = input;
-
- /* we need to re-evaluate prev_cpu_idle */
- for_each_online_cpu(j) {
- struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(od_cpu_dbs_info, j);
- dbs_info->prev_cpu_idle = get_cpu_idle_time_us(j,
- &dbs_info->prev_cpu_wall);
- if (dbs_tuners_ins.ignore_nice)
- dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
-
- }
- mutex_unlock(&dbs_mutex);
-
- return count;
-}
-
-define_one_global_rw(sampling_rate);
-define_one_global_rw(io_is_busy);
-define_one_global_rw(up_threshold);
-define_one_global_rw(ignore_nice_load);
-
-static struct attribute *dbs_attributes[] = {
- &sampling_rate_max.attr,
- &sampling_rate_min.attr,
- &sampling_rate.attr,
- &up_threshold.attr,
- &ignore_nice_load.attr,
- &io_is_busy.attr,
- NULL
-};
-
-static struct attribute_group dbs_attr_group = {
- .attrs = dbs_attributes,
- .name = "adaptive",
-};
-
-/*** delete after deprecation time ***/
-
-#define write_one_old(file_name) \
-static ssize_t store_##file_name##_old \
-(struct cpufreq_policy *unused, const char *buf, size_t count) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core adaptive sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return store_##file_name(NULL, NULL, buf, count); \
-}
-
-static void cpufreq_adaptive_timer(unsigned long data)
-{
- cputime64_t cur_idle;
- cputime64_t cur_wall;
- unsigned int delta_idle;
- unsigned int delta_time;
- int short_load;
- unsigned int new_freq;
- unsigned long flags;
- struct cpu_dbs_info_s *this_dbs_info;
- struct cpufreq_policy *policy;
- unsigned int j;
- unsigned int index;
- unsigned int max_load = 0;
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, 0);
-
- policy = this_dbs_info->cur_policy;
-
- for_each_online_cpu(j) {
- cur_idle = get_cpu_idle_time_us(j, &cur_wall);
-
- delta_idle = (unsigned int) cputime64_sub(cur_idle,
- per_cpu(idle_in_idle, j));
- delta_time = (unsigned int) cputime64_sub(cur_wall,
- per_cpu(idle_exit_wall, j));
-
- /*
- * If timer ran less than 1ms after short-term sample started, retry.
- */
- if (delta_time < 1000)
- goto do_nothing;
-
- if (delta_idle > delta_time)
- short_load = 0;
- else
- short_load = 100 * (delta_time - delta_idle) / delta_time;
-
- if (short_load > max_load)
- max_load = short_load;
- }
-
- if (this_dbs_info->ondemand)
- goto do_nothing;
-
- if (max_load >= go_maxspeed_load)
- new_freq = policy->max;
- else
- new_freq = policy->max * max_load / 100;
-
- if ((max_load <= keep_minspeed_load) &&
- (policy->cur == policy->min))
- new_freq = policy->cur;
-
- if (cpufreq_frequency_table_target(policy, this_dbs_info->freq_table,
- new_freq, CPUFREQ_RELATION_L,
- &index)) {
- goto do_nothing;
- }
-
- new_freq = this_dbs_info->freq_table[index].frequency;
-
- target_freq = new_freq;
-
- if (new_freq < this_dbs_info->cur_policy->cur) {
- spin_lock_irqsave(&down_cpumask_lock, flags);
- cpumask_set_cpu(0, &down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
- queue_work(down_wq, &freq_scale_down_work);
- } else {
- spin_lock_irqsave(&up_cpumask_lock, flags);
- cpumask_set_cpu(0, &up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- wake_up_process(up_task);
- }
-
- return;
-
-do_nothing:
- for_each_online_cpu(j) {
- per_cpu(idle_in_idle, j) =
- get_cpu_idle_time_us(j,
- &per_cpu(idle_exit_wall, j));
- }
- mod_timer(&cpu_timer, jiffies + 2);
- schedule_delayed_work_on(0, &this_dbs_info->work, 10);
-
- if (mutex_is_locked(&short_timer_mutex))
- mutex_unlock(&short_timer_mutex);
- return;
-}
-
-/*** delete after deprecation time ***/
-
-/************************** sysfs end ************************/
-
-static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
-{
-#ifndef CONFIG_ARCH_EXYNOS4
- if (p->cur == p->max)
- return;
-#endif
- __cpufreq_driver_target(p, freq, CPUFREQ_RELATION_H);
-}
-
-static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
-{
- unsigned int max_load_freq;
-
- struct cpufreq_policy *policy;
- unsigned int j;
-
- unsigned int index, new_freq;
- unsigned int longterm_load = 0;
-
- policy = this_dbs_info->cur_policy;
-
- /*
- * 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 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 happens at minimum steps of
- * 5% (default) of current frequency
- */
-
- /* Get Absolute Load - in terms of freq */
- max_load_freq = 0;
-
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
- cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
- unsigned int idle_time, wall_time, iowait_time;
- unsigned int load, load_freq;
- int freq_avg;
-
- j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
-
- cur_idle_time = get_cpu_idle_time_us(j, &cur_wall_time);
- cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time);
-
- wall_time = (unsigned int) cputime64_sub(cur_wall_time,
- j_dbs_info->prev_cpu_wall);
- j_dbs_info->prev_cpu_wall = cur_wall_time;
-
- idle_time = (unsigned int) cputime64_sub(cur_idle_time,
- j_dbs_info->prev_cpu_idle);
- j_dbs_info->prev_cpu_idle = cur_idle_time;
-
- iowait_time = (unsigned int) cputime64_sub(cur_iowait_time,
- j_dbs_info->prev_cpu_iowait);
- j_dbs_info->prev_cpu_iowait = cur_iowait_time;
-
- if (dbs_tuners_ins.ignore_nice) {
- cputime64_t cur_nice;
- unsigned long cur_nice_jiffies;
-
- cur_nice = cputime64_sub(kstat_cpu(j).cpustat.nice,
- j_dbs_info->prev_cpu_nice);
- /*
- * Assumption: nice time between sampling periods will
- * be less than 2^32 jiffies for 32 bit sys
- */
- cur_nice_jiffies = (unsigned long)
- cputime64_to_jiffies64(cur_nice);
-
- j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
- idle_time += jiffies_to_usecs(cur_nice_jiffies);
- }
-
- /*
- * For the purpose of adaptive, waiting for disk IO is an
- * indication that you're performance critical, and not that
- * the system is actually idle. So subtract the iowait time
- * from the cpu idle time.
- */
-
- if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time)
- idle_time -= iowait_time;
-
- if (unlikely(!wall_time || wall_time < idle_time))
- continue;
-
- load = 100 * (wall_time - idle_time) / wall_time;
-
- if (load > longterm_load)
- longterm_load = load;
-
- freq_avg = __cpufreq_driver_getavg(policy, j);
- if (freq_avg <= 0)
- freq_avg = policy->cur;
-
- load_freq = load * freq_avg;
-
- if (load_freq > max_load_freq)
- max_load_freq = load_freq;
- }
-
- if (longterm_load >= MIN_ONDEMAND_THRESHOLD)
- this_dbs_info->ondemand = true;
- else
- this_dbs_info->ondemand = false;
-
- /* Check for frequency increase */
- if (max_load_freq > (dbs_tuners_ins.up_threshold * policy->cur)) {
- cpufreq_frequency_table_target(policy,
- this_dbs_info->freq_table,
- (policy->cur + step_up_load),
- CPUFREQ_RELATION_L, &index);
-
- new_freq = this_dbs_info->freq_table[index].frequency;
- dbs_freq_increase(policy, new_freq);
- return;
- }
-
- /* Check for frequency decrease */
- /* if we cannot reduce the frequency anymore, break out early */
-#ifndef CONFIG_ARCH_EXYNOS4
- if (policy->cur == policy->min)
- return;
-#endif
- /*
- * The optimal frequency is the frequency that is the lowest that
- * can support the current CPU usage without triggering the up
- * policy. To be safe, we focus 10 points under the threshold.
- */
- if (max_load_freq <
- (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) *
- policy->cur) {
- unsigned int freq_next;
- freq_next = max_load_freq /
- (dbs_tuners_ins.up_threshold -
- dbs_tuners_ins.down_differential);
-
- if (freq_next < policy->min)
- freq_next = policy->min;
-
- __cpufreq_driver_target(policy, freq_next,
- CPUFREQ_RELATION_L);
- }
-}
-
-static void do_dbs_timer(struct work_struct *work)
-{
- struct cpu_dbs_info_s *dbs_info =
- container_of(work, struct cpu_dbs_info_s, work.work);
- unsigned int cpu = dbs_info->cpu;
-
- int delay;
-
- mutex_lock(&dbs_info->timer_mutex);
-
- /* Common NORMAL_SAMPLE setup */
- dbs_info->sample_type = DBS_NORMAL_SAMPLE;
- dbs_check_cpu(dbs_info);
-
- /* We want all CPUs to do sampling nearly on
- * same jiffy
- */
- delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-
- schedule_delayed_work_on(cpu, &dbs_info->work, delay);
-
- mutex_unlock(&dbs_info->timer_mutex);
-}
-
-static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
-{
- /* We want all CPUs to do sampling nearly on same jiffy */
- int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-
- dbs_info->sample_type = DBS_NORMAL_SAMPLE;
- INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
-}
-
-static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
-{
- cancel_delayed_work_sync(&dbs_info->work);
-}
-
-/*
- * Not all CPUs want IO time to be accounted as busy; this dependson how
- * 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.
- * Because of this, whitelist specific known (series) of CPUs by default, and
- * leave all others up to the user.
- */
-static int should_io_be_busy(void)
-{
-#if defined(CONFIG_X86)
- /*
- * For Intel, Core 2 (model 15) andl later have an efficient idle.
- */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
- boot_cpu_data.x86 == 6 &&
- boot_cpu_data.x86_model >= 15)
- return 1;
-#endif
- return 0;
-}
-
-static void cpufreq_adaptive_idle(void)
-{
- int i;
- struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, 0);
- struct cpufreq_policy *policy;
-
- policy = dbs_info->cur_policy;
-
- pm_idle_old();
-
- if ((policy->cur == policy->min) ||
- (policy->cur == policy->max)) {
-
- if (timer_pending(&cpu_timer))
- return;
-
- if (mutex_trylock(&short_timer_mutex)) {
- for_each_online_cpu(i) {
- per_cpu(idle_in_idle, i) =
- get_cpu_idle_time_us(i,
- &per_cpu(idle_exit_wall, i));
- }
-
- mod_timer(&cpu_timer, jiffies + 2);
- cancel_delayed_work(&dbs_info->work);
- }
- } else {
- if (timer_pending(&cpu_timer))
- del_timer(&cpu_timer);
-
- }
-}
-
-static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event)
-{
- unsigned int cpu = policy->cpu;
- struct cpu_dbs_info_s *this_dbs_info;
- unsigned int j;
- int rc;
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
-
- switch (event) {
- case CPUFREQ_GOV_START:
- if ((!cpu_online(cpu)) || (!policy->cur))
- return -EINVAL;
-
- mutex_lock(&dbs_mutex);
-
- rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
- if (rc) {
- mutex_unlock(&dbs_mutex);
- return rc;
- }
-
- dbs_enable++;
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
- j_dbs_info->cur_policy = policy;
-
- j_dbs_info->prev_cpu_idle = get_cpu_idle_time_us(j,
- &j_dbs_info->prev_cpu_wall);
- if (dbs_tuners_ins.ignore_nice) {
- j_dbs_info->prev_cpu_nice =
- kstat_cpu(j).cpustat.nice;
- }
- }
- this_dbs_info->cpu = cpu;
- adaptive_init_cpu(cpu);
-
- /*
- * Start the timerschedule work, when this governor
- * is used for first time
- */
- if (dbs_enable == 1) {
- unsigned int latency;
-
- rc = sysfs_create_group(cpufreq_global_kobject,
- &dbs_attr_group);
- if (rc) {
- mutex_unlock(&dbs_mutex);
- return rc;
- }
-
- /* 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 */
- min_sampling_rate = max(min_sampling_rate,
- MIN_LATENCY_MULTIPLIER * latency);
- dbs_tuners_ins.sampling_rate =
- max(min_sampling_rate,
- latency * LATENCY_MULTIPLIER);
- dbs_tuners_ins.io_is_busy = should_io_be_busy();
- }
- mutex_unlock(&dbs_mutex);
-
- mutex_init(&this_dbs_info->timer_mutex);
- dbs_timer_init(this_dbs_info);
-
- pm_idle_old = pm_idle;
- pm_idle = cpufreq_adaptive_idle;
- break;
-
- case CPUFREQ_GOV_STOP:
- dbs_timer_exit(this_dbs_info);
-
- mutex_lock(&dbs_mutex);
- sysfs_remove_group(&policy->kobj, &dbs_attr_group);
- mutex_destroy(&this_dbs_info->timer_mutex);
- dbs_enable--;
- mutex_unlock(&dbs_mutex);
- if (!dbs_enable)
- sysfs_remove_group(cpufreq_global_kobject,
- &dbs_attr_group);
-
- pm_idle = pm_idle_old;
- break;
-
- case CPUFREQ_GOV_LIMITS:
- mutex_lock(&this_dbs_info->timer_mutex);
- if (policy->max < this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- policy->max, CPUFREQ_RELATION_H);
- else if (policy->min > this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- policy->min, CPUFREQ_RELATION_L);
- mutex_unlock(&this_dbs_info->timer_mutex);
- break;
- }
- return 0;
-}
-
-static inline void cpufreq_adaptive_update_time(void)
-{
- struct cpu_dbs_info_s *this_dbs_info;
- struct cpufreq_policy *policy;
- int j;
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, 0);
- policy = this_dbs_info->cur_policy;
-
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
- cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
-
- j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
-
- cur_idle_time = get_cpu_idle_time_us(j, &cur_wall_time);
- cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time);
-
- j_dbs_info->prev_cpu_wall = cur_wall_time;
-
- j_dbs_info->prev_cpu_idle = cur_idle_time;
-
- j_dbs_info->prev_cpu_iowait = cur_iowait_time;
-
- if (dbs_tuners_ins.ignore_nice)
- j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
-
- }
-
-}
-
-static int cpufreq_adaptive_up_task(void *data)
-{
- unsigned long flags;
- struct cpu_dbs_info_s *this_dbs_info;
- struct cpufreq_policy *policy;
- int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, 0);
- policy = this_dbs_info->cur_policy;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&up_cpumask_lock, flags);
-
- if (cpumask_empty(&up_cpumask)) {
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- schedule();
-
- if (kthread_should_stop())
- break;
-
- spin_lock_irqsave(&up_cpumask_lock, flags);
- }
-
- set_current_state(TASK_RUNNING);
-
- cpumask_clear(&up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
-
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- target_freq,
- CPUFREQ_RELATION_H);
- if (policy->cur != policy->max) {
- mutex_lock(&this_dbs_info->timer_mutex);
-
- schedule_delayed_work_on(0, &this_dbs_info->work, delay);
- mutex_unlock(&this_dbs_info->timer_mutex);
- cpufreq_adaptive_update_time();
- }
- if (mutex_is_locked(&short_timer_mutex))
- mutex_unlock(&short_timer_mutex);
- }
-
- return 0;
-}
-
-static void cpufreq_adaptive_freq_down(struct work_struct *work)
-{
- unsigned long flags;
- struct cpu_dbs_info_s *this_dbs_info;
- struct cpufreq_policy *policy;
- int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-
- spin_lock_irqsave(&down_cpumask_lock, flags);
- cpumask_clear(&down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, 0);
- policy = this_dbs_info->cur_policy;
-
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- target_freq,
- CPUFREQ_RELATION_H);
-
- if (policy->cur != policy->min) {
- mutex_lock(&this_dbs_info->timer_mutex);
-
- schedule_delayed_work_on(0, &this_dbs_info->work, delay);
- mutex_unlock(&this_dbs_info->timer_mutex);
- cpufreq_adaptive_update_time();
- }
-
- if (mutex_is_locked(&short_timer_mutex))
- mutex_unlock(&short_timer_mutex);
-}
-
-static int __init cpufreq_gov_dbs_init(void)
-{
- cputime64_t wall;
- u64 idle_time;
- int cpu = get_cpu();
-
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
- go_maxspeed_load = DEFAULT_GO_MAXSPEED_LOAD;
- keep_minspeed_load = DEFAULT_KEEP_MINSPEED_LOAD;
- step_up_load = DEFAULT_STEPUP_LOAD;
-
- idle_time = get_cpu_idle_time_us(cpu, &wall);
- put_cpu();
- if (idle_time != -1ULL) {
- /* Idle micro accounting is supported. Use finer thresholds */
- dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
- dbs_tuners_ins.down_differential =
- MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
- /*
- * In no_hz/micro accounting case we set the minimum frequency
- * not depending on HZ, but fixed (very low). The deferred
- * timer might skip some samples if idle/sleeping as needed.
- */
- min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
- } else {
- /* For correct statistics, we need 10 ticks for each measure */
- min_sampling_rate =
- MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
- }
-
- init_timer(&cpu_timer);
- cpu_timer.function = cpufreq_adaptive_timer;
-
- up_task = kthread_create(cpufreq_adaptive_up_task, NULL,
- "kadaptiveup");
-
- if (IS_ERR(up_task))
- return PTR_ERR(up_task);
-
- sched_setscheduler_nocheck(up_task, SCHED_FIFO, &param);
- get_task_struct(up_task);
-
- /* No rescuer thread, bind to CPU queuing the work for possibly
- warm cache (probably doesn't matter much). */
- down_wq = alloc_workqueue("kadaptive_down", 0, 1);
-
- if (!down_wq)
- goto err_freeuptask;
-
- INIT_WORK(&freq_scale_down_work, cpufreq_adaptive_freq_down);
-
-
- return cpufreq_register_governor(&cpufreq_gov_adaptive);
-err_freeuptask:
- put_task_struct(up_task);
- return -ENOMEM;
-}
-
-static void __exit cpufreq_gov_dbs_exit(void)
-{
- cpufreq_unregister_governor(&cpufreq_gov_adaptive);
-}
-
-
-MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
-MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
-MODULE_DESCRIPTION("'cpufreq_adaptive' - A dynamic cpufreq governor for "
- "Low Latency Frequency Transition capable processors");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ADAPTIVE
-fs_initcall(cpufreq_gov_dbs_init);
-#else
-module_init(cpufreq_gov_dbs_init);
-#endif
-module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 33b56e5..c97b468 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -120,10 +120,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
{
- u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+ u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall);
+ else
+ idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time;
}
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
deleted file mode 100644
index 7dbacf0..0000000
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * drivers/cpufreq/cpufreq_interactive.c
- *
- * Copyright (C) 2010 Google, 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.
- *
- * Author: Mike Chan (mike@android.com)
- *
- */
-
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/cpufreq.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/tick.h>
-#include <linux/time.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <asm/cputime.h>
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/cpufreq_interactive.h>
-
-static atomic_t active_count = ATOMIC_INIT(0);
-
-struct cpufreq_interactive_cpuinfo {
- struct timer_list cpu_timer;
- int timer_idlecancel;
- u64 time_in_idle;
- u64 idle_exit_time;
- u64 timer_run_time;
- int idling;
- u64 target_set_time;
- u64 target_set_time_in_idle;
- struct cpufreq_policy *policy;
- struct cpufreq_frequency_table *freq_table;
- unsigned int target_freq;
- unsigned int floor_freq;
- u64 floor_validate_time;
- u64 hispeed_validate_time;
- int governor_enabled;
-};
-
-static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo);
-
-/* Workqueues handle frequency scaling */
-static struct task_struct *up_task;
-static struct workqueue_struct *down_wq;
-static struct work_struct freq_scale_down_work;
-static cpumask_t up_cpumask;
-static spinlock_t up_cpumask_lock;
-static cpumask_t down_cpumask;
-static spinlock_t down_cpumask_lock;
-static struct mutex set_speed_lock;
-
-/* Hi speed to bump to from lo speed when load burst (default max) */
-static u64 hispeed_freq;
-
-/* Go to hi speed when CPU load at or above this value. */
-#define DEFAULT_GO_HISPEED_LOAD 85
-static unsigned long go_hispeed_load;
-
-/*
- * The minimum amount of time to spend at a frequency before we can ramp down.
- */
-#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC)
-static unsigned long min_sample_time;
-
-/*
- * The sample rate of the timer used to increase frequency
- */
-#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC)
-static unsigned long timer_rate;
-
-/*
- * Wait this long before raising speed above hispeed, by default a single
- * timer interval.
- */
-#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
-static unsigned long above_hispeed_delay_val;
-
-/*
- * Boost pulse to hispeed on touchscreen input.
- */
-
-static int input_boost_val;
-
-struct cpufreq_interactive_inputopen {
- struct input_handle *handle;
- struct work_struct inputopen_work;
-};
-
-static struct cpufreq_interactive_inputopen inputopen;
-
-/*
- * Non-zero means longer-term speed boost active.
- */
-
-static int boost_val;
-
-static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
- unsigned int event);
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_interactive = {
- .name = "interactive",
- .governor = cpufreq_governor_interactive,
- .max_transition_latency = 10000000,
- .owner = THIS_MODULE,
-};
-
-static void cpufreq_interactive_timer(unsigned long data)
-{
- unsigned int delta_idle;
- unsigned int delta_time;
- int cpu_load;
- int load_since_change;
- u64 time_in_idle;
- u64 idle_exit_time;
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, data);
- u64 now_idle;
- unsigned int new_freq;
- unsigned int index;
- unsigned long flags;
-
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- goto exit;
-
- /*
- * Once pcpu->timer_run_time is updated to >= pcpu->idle_exit_time,
- * this lets idle exit know the current idle time sample has
- * been processed, and idle exit can generate a new sample and
- * re-arm the timer. This prevents a concurrent idle
- * exit on that CPU from writing a new set of info at the same time
- * the timer function runs (the timer function can't use that info
- * until more time passes).
- */
- time_in_idle = pcpu->time_in_idle;
- idle_exit_time = pcpu->idle_exit_time;
- now_idle = get_cpu_idle_time_us(data, &pcpu->timer_run_time);
- smp_wmb();
-
- /* If we raced with cancelling a timer, skip. */
- if (!idle_exit_time)
- goto exit;
-
- delta_idle = (unsigned int) cputime64_sub(now_idle, time_in_idle);
- delta_time = (unsigned int) cputime64_sub(pcpu->timer_run_time,
- idle_exit_time);
-
- /*
- * If timer ran less than 1ms after short-term sample started, retry.
- */
- if (delta_time < 1000)
- goto rearm;
-
- if (delta_idle > delta_time)
- cpu_load = 0;
- else
- cpu_load = 100 * (delta_time - delta_idle) / delta_time;
-
- delta_idle = (unsigned int) cputime64_sub(now_idle,
- pcpu->target_set_time_in_idle);
- delta_time = (unsigned int) cputime64_sub(pcpu->timer_run_time,
- pcpu->target_set_time);
-
- if ((delta_time == 0) || (delta_idle > delta_time))
- load_since_change = 0;
- else
- load_since_change =
- 100 * (delta_time - delta_idle) / delta_time;
-
- /*
- * Choose greater of short-term load (since last idle timer
- * started or timer function re-armed itself) or long-term load
- * (since last frequency change).
- */
- if (load_since_change > cpu_load)
- cpu_load = load_since_change;
-
- if (cpu_load >= go_hispeed_load || boost_val) {
- if (pcpu->target_freq <= pcpu->policy->min) {
- new_freq = hispeed_freq;
- } else {
- new_freq = pcpu->policy->max * cpu_load / 100;
-
- if (new_freq < hispeed_freq)
- new_freq = hispeed_freq;
-
- if (pcpu->target_freq == hispeed_freq &&
- new_freq > hispeed_freq &&
- cputime64_sub(pcpu->timer_run_time,
- pcpu->hispeed_validate_time)
- < above_hispeed_delay_val) {
- trace_cpufreq_interactive_notyet(data, cpu_load,
- pcpu->target_freq,
- new_freq);
- goto rearm;
- }
- }
- } else {
- new_freq = pcpu->policy->max * cpu_load / 100;
- }
-
- if (new_freq <= hispeed_freq)
- pcpu->hispeed_validate_time = pcpu->timer_run_time;
-
- if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
- new_freq, CPUFREQ_RELATION_H,
- &index)) {
- pr_warn_once("timer %d: cpufreq_frequency_table_target error\n",
- (int) data);
- goto rearm;
- }
-
- new_freq = pcpu->freq_table[index].frequency;
-
- /*
- * Do not scale below floor_freq unless we have been at or above the
- * floor frequency for the minimum sample time since last validated.
- */
- if (new_freq < pcpu->floor_freq) {
- if (cputime64_sub(pcpu->timer_run_time,
- pcpu->floor_validate_time)
- < min_sample_time) {
- trace_cpufreq_interactive_notyet(data, cpu_load,
- pcpu->target_freq, new_freq);
- goto rearm;
- }
- }
-
- pcpu->floor_freq = new_freq;
- pcpu->floor_validate_time = pcpu->timer_run_time;
-
- if (pcpu->target_freq == new_freq) {
- trace_cpufreq_interactive_already(data, cpu_load,
- pcpu->target_freq, new_freq);
- goto rearm_if_notmax;
- }
-
- trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq,
- new_freq);
- pcpu->target_set_time_in_idle = now_idle;
- pcpu->target_set_time = pcpu->timer_run_time;
-
- if (new_freq < pcpu->target_freq) {
- pcpu->target_freq = new_freq;
- spin_lock_irqsave(&down_cpumask_lock, flags);
- cpumask_set_cpu(data, &down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
- queue_work(down_wq, &freq_scale_down_work);
- } else {
- pcpu->target_freq = new_freq;
- spin_lock_irqsave(&up_cpumask_lock, flags);
- cpumask_set_cpu(data, &up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- wake_up_process(up_task);
- }
-
-rearm_if_notmax:
- /*
- * Already set max speed and don't see a need to change that,
- * wait until next idle to re-evaluate, don't need timer.
- */
- if (pcpu->target_freq == pcpu->policy->max)
- goto exit;
-
-rearm:
- if (!timer_pending(&pcpu->cpu_timer)) {
- /*
- * If already at min: if that CPU is idle, don't set timer.
- * Else cancel the timer if that CPU goes idle. We don't
- * need to re-evaluate speed until the next idle exit.
- */
- if (pcpu->target_freq == pcpu->policy->min) {
- smp_rmb();
-
- if (pcpu->idling)
- goto exit;
-
- pcpu->timer_idlecancel = 1;
- }
-
- pcpu->time_in_idle = get_cpu_idle_time_us(
- data, &pcpu->idle_exit_time);
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-
-exit:
- return;
-}
-
-static void cpufreq_interactive_idle_start(void)
-{
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, smp_processor_id());
- int pending;
-
- if (!pcpu->governor_enabled)
- return;
-
- pcpu->idling = 1;
- smp_wmb();
- pending = timer_pending(&pcpu->cpu_timer);
-
- if (pcpu->target_freq != pcpu->policy->min) {
-#ifdef CONFIG_SMP
- /*
- * Entering idle while not at lowest speed. On some
- * platforms this can hold the other CPU(s) at that speed
- * even though the CPU is idle. Set a timer to re-evaluate
- * speed so this idle CPU doesn't hold the other CPUs above
- * min indefinitely. This should probably be a quirk of
- * the CPUFreq driver.
- */
- if (!pending) {
- pcpu->time_in_idle = get_cpu_idle_time_us(
- smp_processor_id(), &pcpu->idle_exit_time);
- pcpu->timer_idlecancel = 0;
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-#endif
- } else {
- /*
- * If at min speed and entering idle after load has
- * already been evaluated, and a timer has been set just in
- * case the CPU suddenly goes busy, cancel that timer. The
- * CPU didn't go busy; we'll recheck things upon idle exit.
- */
- if (pending && pcpu->timer_idlecancel) {
- del_timer(&pcpu->cpu_timer);
- /*
- * Ensure last timer run time is after current idle
- * sample start time, so next idle exit will always
- * start a new idle sampling period.
- */
- pcpu->idle_exit_time = 0;
- pcpu->timer_idlecancel = 0;
- }
- }
-
-}
-
-static void cpufreq_interactive_idle_end(void)
-{
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, smp_processor_id());
-
- pcpu->idling = 0;
- smp_wmb();
-
- /*
- * Arm the timer for 1-2 ticks later if not already, and if the timer
- * function has already processed the previous load sampling
- * interval. (If the timer is not pending but has not processed
- * the previous interval, it is probably racing with us on another
- * CPU. Let it compute load based on the previous sample and then
- * re-arm the timer for another interval when it's done, rather
- * than updating the interval start time to be "now", which doesn't
- * give the timer function enough time to make a decision on this
- * run.)
- */
- if (timer_pending(&pcpu->cpu_timer) == 0 &&
- pcpu->timer_run_time >= pcpu->idle_exit_time &&
- pcpu->governor_enabled) {
- pcpu->time_in_idle =
- get_cpu_idle_time_us(smp_processor_id(),
- &pcpu->idle_exit_time);
- pcpu->timer_idlecancel = 0;
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-
-}
-
-static int cpufreq_interactive_up_task(void *data)
-{
- unsigned int cpu;
- cpumask_t tmp_mask;
- unsigned long flags;
- struct cpufreq_interactive_cpuinfo *pcpu;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&up_cpumask_lock, flags);
-
- if (cpumask_empty(&up_cpumask)) {
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- schedule();
-
- if (kthread_should_stop())
- break;
-
- spin_lock_irqsave(&up_cpumask_lock, flags);
- }
-
- set_current_state(TASK_RUNNING);
- tmp_mask = up_cpumask;
- cpumask_clear(&up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
-
- for_each_cpu(cpu, &tmp_mask) {
- unsigned int j;
- unsigned int max_freq = 0;
-
- pcpu = &per_cpu(cpuinfo, cpu);
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- continue;
-
- mutex_lock(&set_speed_lock);
-
- for_each_cpu(j, pcpu->policy->cpus) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
-
- if (pjcpu->target_freq > max_freq)
- max_freq = pjcpu->target_freq;
- }
-
- if (max_freq != pcpu->policy->cur)
- __cpufreq_driver_target(pcpu->policy,
- max_freq,
- CPUFREQ_RELATION_H);
- mutex_unlock(&set_speed_lock);
- trace_cpufreq_interactive_up(cpu, pcpu->target_freq,
- pcpu->policy->cur);
- }
- }
-
- return 0;
-}
-
-static void cpufreq_interactive_freq_down(struct work_struct *work)
-{
- unsigned int cpu;
- cpumask_t tmp_mask;
- unsigned long flags;
- struct cpufreq_interactive_cpuinfo *pcpu;
-
- spin_lock_irqsave(&down_cpumask_lock, flags);
- tmp_mask = down_cpumask;
- cpumask_clear(&down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
-
- for_each_cpu(cpu, &tmp_mask) {
- unsigned int j;
- unsigned int max_freq = 0;
-
- pcpu = &per_cpu(cpuinfo, cpu);
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- continue;
-
- mutex_lock(&set_speed_lock);
-
- for_each_cpu(j, pcpu->policy->cpus) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
-
- if (pjcpu->target_freq > max_freq)
- max_freq = pjcpu->target_freq;
- }
-
- if (max_freq != pcpu->policy->cur)
- __cpufreq_driver_target(pcpu->policy, max_freq,
- CPUFREQ_RELATION_H);
-
- mutex_unlock(&set_speed_lock);
- trace_cpufreq_interactive_down(cpu, pcpu->target_freq,
- pcpu->policy->cur);
- }
-}
-
-static void cpufreq_interactive_boost(void)
-{
- int i;
- int anyboost = 0;
- unsigned long flags;
- struct cpufreq_interactive_cpuinfo *pcpu;
-
- spin_lock_irqsave(&up_cpumask_lock, flags);
-
- for_each_online_cpu(i) {
- pcpu = &per_cpu(cpuinfo, i);
-
- if (pcpu->target_freq < hispeed_freq) {
- pcpu->target_freq = hispeed_freq;
- cpumask_set_cpu(i, &up_cpumask);
- pcpu->target_set_time_in_idle =
- get_cpu_idle_time_us(i, &pcpu->target_set_time);
- pcpu->hispeed_validate_time = pcpu->target_set_time;
- anyboost = 1;
- }
-
- /*
- * Set floor freq and (re)start timer for when last
- * validated.
- */
-
- pcpu->floor_freq = hispeed_freq;
- pcpu->floor_validate_time = ktime_to_us(ktime_get());
- }
-
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
-
- if (anyboost)
- wake_up_process(up_task);
-}
-
-/*
- * Pulsed boost on input event raises CPUs to hispeed_freq and lets
- * usual algorithm of min_sample_time decide when to allow speed
- * to drop.
- */
-
-static void cpufreq_interactive_input_event(struct input_handle *handle,
- unsigned int type,
- unsigned int code, int value)
-{
- if (input_boost_val && type == EV_SYN && code == SYN_REPORT) {
- trace_cpufreq_interactive_boost("input");
- cpufreq_interactive_boost();
- }
-}
-
-static void cpufreq_interactive_input_open(struct work_struct *w)
-{
- struct cpufreq_interactive_inputopen *io =
- container_of(w, struct cpufreq_interactive_inputopen,
- inputopen_work);
- int error;
-
- error = input_open_device(io->handle);
- if (error)
- input_unregister_handle(io->handle);
-}
-
-static int cpufreq_interactive_input_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
-{
- struct input_handle *handle;
- int error;
-
- pr_info("%s: connect to %s\n", __func__, dev->name);
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "cpufreq_interactive";
-
- error = input_register_handle(handle);
- if (error)
- goto err;
-
- inputopen.handle = handle;
- queue_work(down_wq, &inputopen.inputopen_work);
- return 0;
-err:
- kfree(handle);
- return error;
-}
-
-static void cpufreq_interactive_input_disconnect(struct input_handle *handle)
-{
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static const struct input_device_id cpufreq_interactive_ids[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
- INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT_MASK(EV_ABS) },
- .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
- BIT_MASK(ABS_MT_POSITION_X) |
- BIT_MASK(ABS_MT_POSITION_Y) },
- }, /* multi-touch touchscreen */
- {
- .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
- INPUT_DEVICE_ID_MATCH_ABSBIT,
- .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
- .absbit = { [BIT_WORD(ABS_X)] =
- BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
- }, /* touchpad */
- { },
-};
-
-static struct input_handler cpufreq_interactive_input_handler = {
- .event = cpufreq_interactive_input_event,
- .connect = cpufreq_interactive_input_connect,
- .disconnect = cpufreq_interactive_input_disconnect,
- .name = "cpufreq_interactive",
- .id_table = cpufreq_interactive_ids,
-};
-
-static ssize_t show_hispeed_freq(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%llu\n", hispeed_freq);
-}
-
-static ssize_t store_hispeed_freq(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t count)
-{
- int ret;
- u64 val;
-
- ret = strict_strtoull(buf, 0, &val);
- if (ret < 0)
- return ret;
- hispeed_freq = val;
- return count;
-}
-
-static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644,
- show_hispeed_freq, store_hispeed_freq);
-
-
-static ssize_t show_go_hispeed_load(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", go_hispeed_load);
-}
-
-static ssize_t store_go_hispeed_load(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- go_hispeed_load = val;
- return count;
-}
-
-static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644,
- show_go_hispeed_load, store_go_hispeed_load);
-
-static ssize_t show_min_sample_time(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", min_sample_time);
-}
-
-static ssize_t store_min_sample_time(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- min_sample_time = val;
- return count;
-}
-
-static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644,
- show_min_sample_time, store_min_sample_time);
-
-static ssize_t show_above_hispeed_delay(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", above_hispeed_delay_val);
-}
-
-static ssize_t store_above_hispeed_delay(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- above_hispeed_delay_val = val;
- return count;
-}
-
-define_one_global_rw(above_hispeed_delay);
-
-static ssize_t show_timer_rate(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", timer_rate);
-}
-
-static ssize_t store_timer_rate(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- timer_rate = val;
- return count;
-}
-
-static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644,
- show_timer_rate, store_timer_rate);
-
-static ssize_t show_input_boost(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%u\n", input_boost_val);
-}
-
-static ssize_t store_input_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- input_boost_val = val;
- return count;
-}
-
-define_one_global_rw(input_boost);
-
-static ssize_t show_boost(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d\n", boost_val);
-}
-
-static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = kstrtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
-
- boost_val = val;
-
- if (boost_val) {
- trace_cpufreq_interactive_boost("on");
- cpufreq_interactive_boost();
- } else {
- trace_cpufreq_interactive_unboost("off");
- }
-
- return count;
-}
-
-define_one_global_rw(boost);
-
-static ssize_t store_boostpulse(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = kstrtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
-
- trace_cpufreq_interactive_boost("pulse");
- cpufreq_interactive_boost();
- return count;
-}
-
-static struct global_attr boostpulse =
- __ATTR(boostpulse, 0200, NULL, store_boostpulse);
-
-static struct attribute *interactive_attributes[] = {
- &hispeed_freq_attr.attr,
- &go_hispeed_load_attr.attr,
- &above_hispeed_delay.attr,
- &min_sample_time_attr.attr,
- &timer_rate_attr.attr,
- &input_boost.attr,
- &boost.attr,
- &boostpulse.attr,
- NULL,
-};
-
-static struct attribute_group interactive_attr_group = {
- .attrs = interactive_attributes,
- .name = "interactive",
-};
-
-static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
- unsigned int event)
-{
- int rc;
- unsigned int j;
- struct cpufreq_interactive_cpuinfo *pcpu;
- struct cpufreq_frequency_table *freq_table;
-
- switch (event) {
- case CPUFREQ_GOV_START:
- if (!cpu_online(policy->cpu))
- return -EINVAL;
-
- freq_table =
- cpufreq_frequency_get_table(policy->cpu);
-
- for_each_cpu(j, policy->cpus) {
- pcpu = &per_cpu(cpuinfo, j);
- pcpu->policy = policy;
- pcpu->target_freq = policy->cur;
- pcpu->freq_table = freq_table;
- pcpu->target_set_time_in_idle =
- get_cpu_idle_time_us(j,
- &pcpu->target_set_time);
- pcpu->floor_freq = pcpu->target_freq;
- pcpu->floor_validate_time =
- pcpu->target_set_time;
- pcpu->hispeed_validate_time =
- pcpu->target_set_time;
- pcpu->governor_enabled = 1;
- smp_wmb();
- }
-
- if (!hispeed_freq)
- hispeed_freq = policy->max;
-
- /*
- * Do not register the idle hook and create sysfs
- * entries if we have already done so.
- */
- if (atomic_inc_return(&active_count) > 1)
- return 0;
-
- rc = sysfs_create_group(cpufreq_global_kobject,
- &interactive_attr_group);
- if (rc)
- return rc;
-
- rc = input_register_handler(&cpufreq_interactive_input_handler);
- if (rc)
- pr_warn("%s: failed to register input handler\n",
- __func__);
-
- break;
-
- case CPUFREQ_GOV_STOP:
- for_each_cpu(j, policy->cpus) {
- pcpu = &per_cpu(cpuinfo, j);
- pcpu->governor_enabled = 0;
- smp_wmb();
- del_timer_sync(&pcpu->cpu_timer);
-
- /*
- * Reset idle exit time since we may cancel the timer
- * before it can run after the last idle exit time,
- * to avoid tripping the check in idle exit for a timer
- * that is trying to run.
- */
- pcpu->idle_exit_time = 0;
- }
-
- flush_work(&freq_scale_down_work);
- if (atomic_dec_return(&active_count) > 0)
- return 0;
-
- input_unregister_handler(&cpufreq_interactive_input_handler);
- sysfs_remove_group(cpufreq_global_kobject,
- &interactive_attr_group);
-
- break;
-
- case CPUFREQ_GOV_LIMITS:
- if (policy->max < policy->cur)
- __cpufreq_driver_target(policy,
- policy->max, CPUFREQ_RELATION_H);
- else if (policy->min > policy->cur)
- __cpufreq_driver_target(policy,
- policy->min, CPUFREQ_RELATION_L);
- break;
- }
- return 0;
-}
-
-static int cpufreq_interactive_idle_notifier(struct notifier_block *nb,
- unsigned long val,
- void *data)
-{
- switch (val) {
- case IDLE_START:
- cpufreq_interactive_idle_start();
- break;
- case IDLE_END:
- cpufreq_interactive_idle_end();
- break;
- }
-
- return 0;
-}
-
-static struct notifier_block cpufreq_interactive_idle_nb = {
- .notifier_call = cpufreq_interactive_idle_notifier,
-};
-
-static int __init cpufreq_interactive_init(void)
-{
- unsigned int i;
- struct cpufreq_interactive_cpuinfo *pcpu;
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-
- go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
- min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
- above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY;
- timer_rate = DEFAULT_TIMER_RATE;
-
- /* Initalize per-cpu timers */
- for_each_possible_cpu(i) {
- pcpu = &per_cpu(cpuinfo, i);
- init_timer(&pcpu->cpu_timer);
- pcpu->cpu_timer.function = cpufreq_interactive_timer;
- pcpu->cpu_timer.data = i;
- }
-
- up_task = kthread_create(cpufreq_interactive_up_task, NULL,
- "kinteractiveup");
- if (IS_ERR(up_task))
- return PTR_ERR(up_task);
-
- sched_setscheduler_nocheck(up_task, SCHED_FIFO, &param);
- get_task_struct(up_task);
-
- /* No rescuer thread, bind to CPU queuing the work for possibly
- warm cache (probably doesn't matter much). */
- down_wq = alloc_workqueue("knteractive_down", 0, 1);
-
- if (!down_wq)
- goto err_freeuptask;
-
- INIT_WORK(&freq_scale_down_work,
- cpufreq_interactive_freq_down);
-
- spin_lock_init(&up_cpumask_lock);
- spin_lock_init(&down_cpumask_lock);
- mutex_init(&set_speed_lock);
-
- idle_notifier_register(&cpufreq_interactive_idle_nb);
- INIT_WORK(&inputopen.inputopen_work, cpufreq_interactive_input_open);
- return cpufreq_register_governor(&cpufreq_gov_interactive);
-
-err_freeuptask:
- put_task_struct(up_task);
- return -ENOMEM;
-}
-
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
-fs_initcall(cpufreq_interactive_init);
-#else
-module_init(cpufreq_interactive_init);
-#endif
-
-static void __exit cpufreq_interactive_exit(void)
-{
- cpufreq_unregister_governor(&cpufreq_gov_interactive);
- kthread_stop(up_task);
- put_task_struct(up_task);
- destroy_workqueue(down_wq);
-}
-
-module_exit(cpufreq_interactive_exit);
-
-MODULE_AUTHOR("Mike Chan <mike@android.com>");
-MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for "
- "Latency sensitive workloads");
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index a87dc5d..fa8af4e 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -22,7 +22,6 @@
#include <linux/tick.h>
#include <linux/ktime.h>
#include <linux/sched.h>
-#include <linux/pm_qos_params.h>
/*
* dbs is used in this file as a shortform for demandbased switching
@@ -33,15 +32,8 @@
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (100000)
-
-#if defined(CONFIG_MACH_SLP_PQ)
-#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (5)
-#define MICRO_FREQUENCY_UP_THRESHOLD (85)
-#else
#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
#define MICRO_FREQUENCY_UP_THRESHOLD (95)
-#endif
-
#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
@@ -101,10 +93,6 @@ struct cpu_dbs_info_s {
* when user is changing the governor or limits.
*/
struct mutex timer_mutex;
- bool activated; /* dbs_timer_init is in effect */
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- unsigned int flex_duration;
-#endif
};
static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
@@ -114,9 +102,6 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
* dbs_mutex protects dbs_enable in governor start/stop.
*/
static DEFINE_MUTEX(dbs_mutex);
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
-static DEFINE_MUTEX(flex_mutex);
-#endif
static struct dbs_tuners {
unsigned int sampling_rate;
@@ -126,20 +111,12 @@ static struct dbs_tuners {
unsigned int sampling_down_factor;
unsigned int powersave_bias;
unsigned int io_is_busy;
- struct notifier_block dvfs_lat_qos_db;
- unsigned int dvfs_lat_qos_wants;
- unsigned int freq_step;
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- unsigned int flex_sampling_rate;
- unsigned int flex_duration;
-#endif
} dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
.ignore_nice = 0,
.powersave_bias = 0,
- .freq_step = 100,
};
static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
@@ -167,10 +144,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
{
- u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+ u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall);
+ else
+ idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time;
}
@@ -186,23 +165,6 @@ static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wal
}
/*
- * Find right sampling rate based on sampling_rate and
- * QoS requests on dvfs latency.
- */
-static unsigned int effective_sampling_rate(void)
-{
- unsigned int effective;
-
- if (dbs_tuners_ins.dvfs_lat_qos_wants)
- effective = min(dbs_tuners_ins.dvfs_lat_qos_wants,
- dbs_tuners_ins.sampling_rate);
- else
- effective = dbs_tuners_ins.sampling_rate;
-
- return max(effective, min_sampling_rate);
-}
-
-/*
* Find right freq to be set now with powersave_bias on.
* Returns the freq_hi to be used right now and will set freq_hi_jiffies,
* freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
@@ -246,7 +208,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
dbs_info->freq_lo_jiffies = 0;
return freq_lo;
}
- jiffies_total = usecs_to_jiffies(effective_sampling_rate());
+ jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
jiffies_hi += ((freq_hi - freq_lo) / 2);
jiffies_hi /= (freq_hi - freq_lo);
@@ -295,95 +257,6 @@ show_one(up_threshold, up_threshold);
show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
-show_one(down_differential, down_differential);
-show_one(freq_step, freq_step);
-
-/**
- * update_sampling_rate - update sampling rate effective immediately if needed.
- * @new_rate: new sampling rate. If it is 0, regard sampling rate is not
- * changed and assume that qos request value is changed.
- *
- * If new rate is smaller than the old, simply updaing
- * 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 sure if higher frequency will be required or not,
- * then, the governor may change the sampling rate too late; up to 1 second
- * later. Thus, if we are reducing the sampling rate, we need to make the
- * new value effective immediately.
- */
-static void update_sampling_rate(unsigned int new_rate)
-{
- int cpu;
- unsigned int effective;
-
- if (new_rate)
- dbs_tuners_ins.sampling_rate = max(new_rate, min_sampling_rate);
-
- effective = effective_sampling_rate();
-
- for_each_online_cpu(cpu) {
- struct cpufreq_policy *policy;
- struct cpu_dbs_info_s *dbs_info;
- unsigned long next_sampling, appointed_at;
-
- /*
- * mutex_destory(&dbs_info->timer_mutex) should not happen
- * in this context. dbs_mutex is locked/unlocked at GOV_START
- * and GOV_STOP context only other than here.
- */
- mutex_lock(&dbs_mutex);
-
- policy = cpufreq_cpu_get(cpu);
- if (!policy) {
- mutex_unlock(&dbs_mutex);
- continue;
- }
- dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
- cpufreq_cpu_put(policy);
-
- /* timer_mutex is destroyed or will be destroyed soon */
- if (!dbs_info->activated) {
- mutex_unlock(&dbs_mutex);
- continue;
- }
-
- mutex_lock(&dbs_info->timer_mutex);
-
- if (!delayed_work_pending(&dbs_info->work)) {
- mutex_unlock(&dbs_info->timer_mutex);
- mutex_unlock(&dbs_mutex);
- continue;
- }
-
- next_sampling = jiffies + usecs_to_jiffies(new_rate);
- appointed_at = dbs_info->work.timer.expires;
-
- if (time_before(next_sampling, appointed_at)) {
- mutex_unlock(&dbs_info->timer_mutex);
- cancel_delayed_work_sync(&dbs_info->work);
- mutex_lock(&dbs_info->timer_mutex);
-
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
- usecs_to_jiffies(effective));
- }
- mutex_unlock(&dbs_info->timer_mutex);
-
- /*
- * For the little possiblity that dbs_timer_exit() has been
- * called after checking dbs_info->activated above.
- * If cancel_delayed_work_syn() has been calld by
- * dbs_timer_exit() before schedule_delayed_work_on() of this
- * function, it should be revoked by calling cancel again
- * before releasing dbs_mutex, which will trigger mutex_destroy
- * to be called.
- */
- if (!dbs_info->activated)
- cancel_delayed_work_sync(&dbs_info->work);
-
- mutex_unlock(&dbs_mutex);
- }
-}
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
@@ -393,7 +266,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
- update_sampling_rate(input);
+ dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
return count;
}
@@ -496,46 +369,12 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
return count;
}
-static ssize_t store_down_differential(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;
- dbs_tuners_ins.down_differential = min(input, 100u);
- return count;
-}
-
-static ssize_t store_freq_step(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;
- dbs_tuners_ins.freq_step = min(input, 100u);
- return count;
-}
-
-
define_one_global_rw(sampling_rate);
define_one_global_rw(io_is_busy);
define_one_global_rw(up_threshold);
define_one_global_rw(sampling_down_factor);
define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
-define_one_global_rw(down_differential);
-define_one_global_rw(freq_step);
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
-static struct global_attr flexrate_request;
-static struct global_attr flexrate_duration;
-static struct global_attr flexrate_enable;
-static struct global_attr flexrate_forcerate;
-static struct global_attr flexrate_num_effective_usage;
-#endif
static struct attribute *dbs_attributes[] = {
&sampling_rate_min.attr,
@@ -545,15 +384,6 @@ static struct attribute *dbs_attributes[] = {
&ignore_nice_load.attr,
&powersave_bias.attr,
&io_is_busy.attr,
- &down_differential.attr,
- &freq_step.attr,
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- &flexrate_request.attr,
- &flexrate_duration.attr,
- &flexrate_enable.attr,
- &flexrate_forcerate.attr,
- &flexrate_num_effective_usage.attr,
-#endif
NULL
};
@@ -568,10 +398,8 @@ static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
{
if (dbs_tuners_ins.powersave_bias)
freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
-#if !defined(CONFIG_ARCH_EXYNOS4) && !defined(CONFIG_ARCH_EXYNOS5)
else if (p->cur == p->max)
return;
-#endif
__cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ?
CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
@@ -669,22 +497,18 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
/* Check for frequency increase */
if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
- int inc = (policy->max * dbs_tuners_ins.freq_step) / 100;
- int target = min(policy->max, policy->cur + inc);
/* If switching to max speed, apply sampling_down_factor */
- if (policy->cur < policy->max && target == policy->max)
+ if (policy->cur < policy->max)
this_dbs_info->rate_mult =
dbs_tuners_ins.sampling_down_factor;
- dbs_freq_increase(policy, target);
+ dbs_freq_increase(policy, policy->max);
return;
}
/* Check for frequency decrease */
-#if !defined(CONFIG_ARCH_EXYNOS4) && !defined(CONFIG_ARCH_EXYNOS5)
/* if we cannot reduce the frequency anymore, break out early */
if (policy->cur == policy->min)
return;
-#endif
/*
* The optimal frequency is the frequency that is the lowest that
@@ -741,7 +565,7 @@ static void do_dbs_timer(struct work_struct *work)
/* We want all CPUs to do sampling nearly on
* same jiffy
*/
- delay = usecs_to_jiffies(effective_sampling_rate()
+ delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
* dbs_info->rate_mult);
if (num_online_cpus() > 1)
@@ -752,23 +576,6 @@ static void do_dbs_timer(struct work_struct *work)
dbs_info->freq_lo, CPUFREQ_RELATION_H);
delay = dbs_info->freq_lo_jiffies;
}
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
- if (dbs_info->flex_duration) {
- struct cpufreq_policy *policy = dbs_info->cur_policy;
-
- mutex_lock(&flex_mutex);
- delay = usecs_to_jiffies(dbs_tuners_ins.flex_sampling_rate);
-
- /* If it's already max, we don't need to iterate fast */
- if (policy->cur >= policy->max)
- dbs_info->flex_duration = 1;
-
- if (--dbs_info->flex_duration < dbs_tuners_ins.flex_duration) {
- dbs_tuners_ins.flex_duration = dbs_info->flex_duration;
- }
- mutex_unlock(&flex_mutex);
- }
-#endif /* CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE */
schedule_delayed_work_on(cpu, &dbs_info->work, delay);
mutex_unlock(&dbs_info->timer_mutex);
}
@@ -776,20 +583,18 @@ static void do_dbs_timer(struct work_struct *work)
static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{
/* We want all CPUs to do sampling nearly on same jiffy */
- int delay = usecs_to_jiffies(effective_sampling_rate());
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
if (num_online_cpus() > 1)
delay -= jiffies % delay;
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
- schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, 10 * delay);
- dbs_info->activated = true;
+ schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
}
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
- dbs_info->activated = false;
cancel_delayed_work_sync(&dbs_info->work);
}
@@ -908,40 +713,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-/**
- * qos_dvfs_lat_notify - PM QoS Notifier for DVFS_LATENCY QoS Request
- * @nb notifier block struct
- * @value QoS value
- * @dummy
- */
-static int qos_dvfs_lat_notify(struct notifier_block *nb, unsigned long value,
- void *dummy)
-{
- /*
- * In the worst case, with a continuous up-treshold + e cpu load
- * from up-threshold - e load, the ondemand governor will react
- * sampling_rate * 2.
- *
- * Thus, based on the worst case scenario, we use value / 2;
- */
- dbs_tuners_ins.dvfs_lat_qos_wants = value / 2;
-
- /* Update sampling rate */
- update_sampling_rate(0);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block ondemand_qos_dvfs_lat_nb = {
- .notifier_call = qos_dvfs_lat_notify,
-};
-
static int __init cpufreq_gov_dbs_init(void)
{
cputime64_t wall;
u64 idle_time;
int cpu = get_cpu();
- int err = 0;
idle_time = get_cpu_idle_time_us(cpu, &wall);
put_cpu();
@@ -951,7 +727,7 @@ static int __init cpufreq_gov_dbs_init(void)
dbs_tuners_ins.down_differential =
MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
/*
- * In no_hz/micro accounting case we set the minimum frequency
+ * In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
* timer might skip some samples if idle/sleeping as needed.
*/
@@ -962,241 +738,14 @@ static int __init cpufreq_gov_dbs_init(void)
MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
}
- err = pm_qos_add_notifier(PM_QOS_DVFS_RESPONSE_LATENCY,
- &ondemand_qos_dvfs_lat_nb);
- if (err)
- return err;
-
- err = cpufreq_register_governor(&cpufreq_gov_ondemand);
- if (err) {
- pm_qos_remove_notifier(PM_QOS_DVFS_RESPONSE_LATENCY,
- &ondemand_qos_dvfs_lat_nb);
- }
-
- return err;
+ return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- pm_qos_remove_notifier(PM_QOS_DVFS_RESPONSE_LATENCY,
- &ondemand_qos_dvfs_lat_nb);
-
cpufreq_unregister_governor(&cpufreq_gov_ondemand);
}
-#ifdef CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE
-static unsigned int max_duration =
- (CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE_MAX_DURATION);
-#define DEFAULT_DURATION (5)
-static unsigned int sysfs_duration = DEFAULT_DURATION;
-static bool flexrate_enabled = true;
-static unsigned int forced_rate;
-static unsigned int flexrate_num_effective;
-
-static int cpufreq_ondemand_flexrate_do(struct cpufreq_policy *policy,
- bool now)
-{
- unsigned int cpu = policy->cpu;
- bool using_ondemand;
- struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
-
- WARN(!mutex_is_locked(&flex_mutex), "flex_mutex not locked\n");
-
- dbs_info->flex_duration = dbs_tuners_ins.flex_duration;
-
- if (now) {
- flexrate_num_effective++;
-
- mutex_lock(&dbs_mutex);
- using_ondemand = dbs_enable && !strncmp(policy->governor->name, "ondemand", 8);
- mutex_unlock(&dbs_mutex);
-
- if (!using_ondemand)
- return 0;
-
- mutex_unlock(&flex_mutex);
- mutex_lock(&dbs_info->timer_mutex);
-
- /* Do It! */
- cancel_delayed_work_sync(&dbs_info->work);
- schedule_delayed_work_on(cpu, &dbs_info->work, 1);
-
- mutex_unlock(&dbs_info->timer_mutex);
- mutex_lock(&flex_mutex);
- }
-
- return 0;
-}
-
-int cpufreq_ondemand_flexrate_request(unsigned int rate_us,
- unsigned int duration)
-{
- int err = 0;
-
- if (!flexrate_enabled)
- return 0;
-
- if (forced_rate)
- rate_us = forced_rate;
-
- mutex_lock(&flex_mutex);
-
- /* Unnecessary requests are dropped */
- if (rate_us >= dbs_tuners_ins.sampling_rate)
- goto out;
- if (rate_us >= dbs_tuners_ins.flex_sampling_rate &&
- duration <= dbs_tuners_ins.flex_duration)
- goto out;
-
- duration = min(max_duration, duration);
- if (rate_us > 0 && rate_us < min_sampling_rate)
- rate_us = min_sampling_rate;
-
- err = 1; /* Need update */
-
- /* Cancel the active flexrate requests */
- if (rate_us == 0 || duration == 0) {
- dbs_tuners_ins.flex_duration = 0;
- dbs_tuners_ins.flex_sampling_rate = 0;
- goto out;
- }
-
- if (dbs_tuners_ins.flex_sampling_rate == 0 ||
- dbs_tuners_ins.flex_sampling_rate > rate_us)
- err = 2; /* Need to poll faster */
-
- /* Set new flexrate per the request */
- dbs_tuners_ins.flex_sampling_rate =
- min(dbs_tuners_ins.flex_sampling_rate, rate_us);
- dbs_tuners_ins.flex_duration =
- max(dbs_tuners_ins.flex_duration, duration);
-out:
- /* Apply new flexrate */
- if (err > 0) {
- bool now = (err == 2);
- int cpu = 0;
-
- /* TODO: For every CPU using ONDEMAND */
- err = cpufreq_ondemand_flexrate_do(cpufreq_cpu_get(cpu), now);
- }
- mutex_unlock(&flex_mutex);
- return err;
-}
-EXPORT_SYMBOL_GPL(cpufreq_ondemand_flexrate_request);
-
-static ssize_t store_flexrate_request(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int rate;
- int ret;
-
- ret = sscanf(buf, "%u", &rate);
- if (ret != 1)
- return -EINVAL;
-
- ret = cpufreq_ondemand_flexrate_request(rate, sysfs_duration);
- if (ret)
- return ret;
- return count;
-}
-
-static ssize_t show_flexrate_request(struct kobject *a, struct attribute *b,
- char *buf)
-{
- return sprintf(buf, "Flexrate decreases CPUFreq Ondemand governor's polling rate temporaily.\n"
- "Usage Example:\n"
- "# echo 8 > flexrate_duration\n"
- "# echo 10000 > flexrate_request\n"
- "With the second statement, Ondemand polls with 10ms(10000us) interval 8 times.\n"
- "run \"echo flexrate_duration\" to see the currecnt duration setting.\n");
-}
-
-static ssize_t store_flexrate_duration(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int duration;
- int ret;
-
- /* mutex not needed for flexrate_sysfs_duration */
- ret = sscanf(buf, "%u", &duration);
- if (ret != 1)
- return -EINVAL;
-
- if (duration == 0)
- duration = DEFAULT_DURATION;
- if (duration > max_duration)
- duration = max_duration;
-
- sysfs_duration = duration;
- return count;
-}
-
-static ssize_t show_flexrate_duration(struct kobject *a, struct attribute *b,
- char *buf)
-{
- return sprintf(buf, "%d\n", sysfs_duration);
-}
-
-static ssize_t store_flexrate_enable(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;
-
- if (input > 0)
- flexrate_enabled = true;
- else
- flexrate_enabled = false;
-
- return count;
-}
-
-static ssize_t show_flexrate_enable(struct kobject *a, struct attribute *b,
- char *buf)
-{
- return sprintf(buf, "%d\n", !!flexrate_enabled);
-}
-
-static ssize_t store_flexrate_forcerate(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int rate;
- int ret;
-
- ret = sscanf(buf, "%u", &rate);
- if (ret != 1)
- return -EINVAL;
-
- forced_rate = rate;
-
- pr_info("CAUTION: flexrate_forcerate is for debugging/benchmarking only.\n");
- return count;
-}
-
-static ssize_t show_flexrate_forcerate(struct kobject *a, struct attribute *b,
- char *buf)
-{
- return sprintf(buf, "%u\n", forced_rate);
-}
-
-static ssize_t show_flexrate_num_effective_usage(struct kobject *a,
- struct attribute *b,
- char *buf)
-{
- return sprintf(buf, "%u\n", flexrate_num_effective);
-}
-
-define_one_global_rw(flexrate_request);
-define_one_global_rw(flexrate_duration);
-define_one_global_rw(flexrate_enable);
-define_one_global_rw(flexrate_forcerate);
-define_one_global_ro(flexrate_num_effective_usage);
-#endif
-
MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
diff --git a/drivers/cpufreq/cpufreq_pegasusq.c b/drivers/cpufreq/cpufreq_pegasusq.c
deleted file mode 100644
index c44af54..0000000
--- a/drivers/cpufreq/cpufreq_pegasusq.c
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- * drivers/cpufreq/cpufreq_pegasusq.c
- *
- * Copyright (C) 2011 Samsung Electronics co. ltd
- * ByungChang Cha <bc.cha@samsung.com>
- *
- * Based on ondemand governor
- * Copyright (C) 2001 Russell King
- * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
- * Jun Nakajima <jun.nakajima@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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/jiffies.h>
-#include <linux/kernel_stat.h>
-#include <linux/mutex.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <linux/ktime.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#include <linux/earlysuspend.h>
-#endif
-#define EARLYSUSPEND_HOTPLUGLOCK 1
-
-/*
- * runqueue average
- */
-
-#define RQ_AVG_TIMER_RATE 10
-
-struct runqueue_data {
- unsigned int nr_run_avg;
- unsigned int update_rate;
- int64_t last_time;
- int64_t total_time;
- struct delayed_work work;
- struct workqueue_struct *nr_run_wq;
- spinlock_t lock;
-};
-
-static struct runqueue_data *rq_data;
-static void rq_work_fn(struct work_struct *work);
-
-static void start_rq_work(void)
-{
- rq_data->nr_run_avg = 0;
- rq_data->last_time = 0;
- rq_data->total_time = 0;
- if (rq_data->nr_run_wq == NULL)
- rq_data->nr_run_wq =
- create_singlethread_workqueue("nr_run_avg");
-
- queue_delayed_work(rq_data->nr_run_wq, &rq_data->work,
- msecs_to_jiffies(rq_data->update_rate));
- return;
-}
-
-static void stop_rq_work(void)
-{
- if (rq_data->nr_run_wq)
- cancel_delayed_work(&rq_data->work);
- return;
-}
-
-static int __init init_rq_avg(void)
-{
- rq_data = kzalloc(sizeof(struct runqueue_data), GFP_KERNEL);
- if (rq_data == NULL) {
- pr_err("%s cannot allocate memory\n", __func__);
- return -ENOMEM;
- }
- spin_lock_init(&rq_data->lock);
- rq_data->update_rate = RQ_AVG_TIMER_RATE;
- INIT_DELAYED_WORK_DEFERRABLE(&rq_data->work, rq_work_fn);
-
- return 0;
-}
-
-static void rq_work_fn(struct work_struct *work)
-{
- int64_t time_diff = 0;
- int64_t nr_run = 0;
- unsigned long flags = 0;
- int64_t cur_time = ktime_to_ns(ktime_get());
-
- spin_lock_irqsave(&rq_data->lock, flags);
-
- if (rq_data->last_time == 0)
- rq_data->last_time = cur_time;
- if (rq_data->nr_run_avg == 0)
- rq_data->total_time = 0;
-
- nr_run = nr_running() * 100;
- time_diff = cur_time - rq_data->last_time;
- do_div(time_diff, 1000 * 1000);
-
- if (time_diff != 0 && rq_data->total_time != 0) {
- nr_run = (nr_run * time_diff) +
- (rq_data->nr_run_avg * rq_data->total_time);
- do_div(nr_run, rq_data->total_time + time_diff);
- }
- rq_data->nr_run_avg = nr_run;
- rq_data->total_time += time_diff;
- rq_data->last_time = cur_time;
-
- if (rq_data->update_rate != 0)
- queue_delayed_work(rq_data->nr_run_wq, &rq_data->work,
- msecs_to_jiffies(rq_data->update_rate));
-
- spin_unlock_irqrestore(&rq_data->lock, flags);
-}
-
-static unsigned int get_nr_run_avg(void)
-{
- unsigned int nr_run_avg;
- unsigned long flags = 0;
-
- spin_lock_irqsave(&rq_data->lock, flags);
- nr_run_avg = rq_data->nr_run_avg;
- rq_data->nr_run_avg = 0;
- spin_unlock_irqrestore(&rq_data->lock, flags);
-
- return nr_run_avg;
-}
-
-
-/*
- * dbs is used in this file as a shortform for demandbased switching
- * It helps to keep variable names smaller, simpler
- */
-
-#define DEF_SAMPLING_DOWN_FACTOR (2)
-#define MAX_SAMPLING_DOWN_FACTOR (100000)
-#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (5)
-#define DEF_FREQUENCY_UP_THRESHOLD (85)
-#define DEF_FREQUENCY_MIN_SAMPLE_RATE (10000)
-#define MIN_FREQUENCY_UP_THRESHOLD (11)
-#define MAX_FREQUENCY_UP_THRESHOLD (100)
-#define DEF_SAMPLING_RATE (50000)
-#define MIN_SAMPLING_RATE (10000)
-#define MAX_HOTPLUG_RATE (40u)
-
-#define DEF_MAX_CPU_LOCK (0)
-#define DEF_MIN_CPU_LOCK (0)
-#define DEF_CPU_UP_FREQ (500000)
-#define DEF_CPU_DOWN_FREQ (200000)
-#define DEF_UP_NR_CPUS (1)
-#define DEF_CPU_UP_RATE (10)
-#define DEF_CPU_DOWN_RATE (20)
-#define DEF_FREQ_STEP (37)
-#define DEF_START_DELAY (0)
-
-#define UP_THRESHOLD_AT_MIN_FREQ (40)
-#define FREQ_FOR_RESPONSIVENESS (500000)
-
-#define HOTPLUG_DOWN_INDEX (0)
-#define HOTPLUG_UP_INDEX (1)
-
-#ifdef CONFIG_MACH_MIDAS
-static int hotplug_rq[4][2] = {
- {0, 100}, {100, 200}, {200, 300}, {300, 0}
-};
-
-static int hotplug_freq[4][2] = {
- {0, 500000},
- {200000, 500000},
- {200000, 500000},
- {200000, 0}
-};
-#else
-static int hotplug_rq[4][2] = {
- {0, 100}, {100, 200}, {200, 300}, {300, 0}
-};
-
-static int hotplug_freq[4][2] = {
- {0, 500000},
- {200000, 500000},
- {200000, 500000},
- {200000, 0}
-};
-#endif
-
-static unsigned int min_sampling_rate;
-
-static void do_dbs_timer(struct work_struct *work);
-static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event);
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_PEGASUSQ
-static
-#endif
-struct cpufreq_governor cpufreq_gov_pegasusq = {
- .name = "pegasusq",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
-};
-
-/* Sampling types */
-enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
-
-struct cpu_dbs_info_s {
- cputime64_t prev_cpu_idle;
- cputime64_t prev_cpu_iowait;
- cputime64_t prev_cpu_wall;
- cputime64_t prev_cpu_nice;
- struct cpufreq_policy *cur_policy;
- struct delayed_work work;
- struct work_struct up_work;
- struct work_struct down_work;
- struct cpufreq_frequency_table *freq_table;
- unsigned int rate_mult;
- int cpu;
- /*
- * percpu mutex that serializes governor limit change with
- * do_dbs_timer invocation. We do not want do_dbs_timer to run
- * when user is changing the governor or limits.
- */
- struct mutex timer_mutex;
-};
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
-
-struct workqueue_struct *dvfs_workqueue;
-
-static unsigned int dbs_enable; /* number of CPUs using this policy */
-
-/*
- * dbs_mutex protects dbs_enable in governor start/stop.
- */
-static DEFINE_MUTEX(dbs_mutex);
-
-static struct dbs_tuners {
- unsigned int sampling_rate;
- unsigned int up_threshold;
- unsigned int down_differential;
- unsigned int ignore_nice;
- unsigned int sampling_down_factor;
- unsigned int io_is_busy;
- /* pegasusq tuners */
- unsigned int freq_step;
- unsigned int cpu_up_rate;
- unsigned int cpu_down_rate;
- unsigned int cpu_up_freq;
- unsigned int cpu_down_freq;
- unsigned int up_nr_cpus;
- unsigned int max_cpu_lock;
- unsigned int min_cpu_lock;
- atomic_t hotplug_lock;
- unsigned int dvfs_debug;
- unsigned int max_freq;
- unsigned int min_freq;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- int early_suspend;
-#endif
-} dbs_tuners_ins = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
- .ignore_nice = 0,
- .freq_step = DEF_FREQ_STEP,
- .cpu_up_rate = DEF_CPU_UP_RATE,
- .cpu_down_rate = DEF_CPU_DOWN_RATE,
- .cpu_up_freq = DEF_CPU_UP_FREQ,
- .cpu_down_freq = DEF_CPU_DOWN_FREQ,
- .up_nr_cpus = DEF_UP_NR_CPUS,
- .max_cpu_lock = DEF_MAX_CPU_LOCK,
- .min_cpu_lock = DEF_MIN_CPU_LOCK,
- .hotplug_lock = ATOMIC_INIT(0),
- .dvfs_debug = 0,
-#ifdef CONFIG_HAS_EARLYSUSPEND
- .early_suspend = -1,
-#endif
-};
-
-
-/*
- * CPU hotplug lock interface
- */
-
-static atomic_t g_hotplug_count = ATOMIC_INIT(0);
-static atomic_t g_hotplug_lock = ATOMIC_INIT(0);
-
-static void apply_hotplug_lock(void)
-{
- int online, possible, lock, flag;
- struct work_struct *work;
- struct cpu_dbs_info_s *dbs_info;
-
- /* do turn_on/off cpus */
- dbs_info = &per_cpu(od_cpu_dbs_info, 0); /* from CPU0 */
- online = num_online_cpus();
- possible = num_possible_cpus();
- lock = atomic_read(&g_hotplug_lock);
- flag = lock - online;
-
- if (lock == 0 || flag == 0)
- return;
-
- work = flag > 0 ? &dbs_info->up_work : &dbs_info->down_work;
-
- pr_debug("%s online %d possible %d lock %d flag %d %d\n",
- __func__, online, possible, lock, flag, (int)abs(flag));
-
- queue_work_on(dbs_info->cpu, dvfs_workqueue, work);
-}
-
-int cpufreq_pegasusq_cpu_lock(int num_core)
-{
- int prev_lock;
-
- if (num_core < 1 || num_core > num_possible_cpus())
- return -EINVAL;
-
- prev_lock = atomic_read(&g_hotplug_lock);
-
- if (prev_lock != 0 && prev_lock < num_core)
- return -EINVAL;
- else if (prev_lock == num_core)
- atomic_inc(&g_hotplug_count);
-
- atomic_set(&g_hotplug_lock, num_core);
- atomic_set(&g_hotplug_count, 1);
- apply_hotplug_lock();
-
- return 0;
-}
-
-int cpufreq_pegasusq_cpu_unlock(int num_core)
-{
- int prev_lock = atomic_read(&g_hotplug_lock);
-
- if (prev_lock < num_core)
- return 0;
- else if (prev_lock == num_core)
- atomic_dec(&g_hotplug_count);
-
- if (atomic_read(&g_hotplug_count) == 0)
- atomic_set(&g_hotplug_lock, 0);
-
- return 0;
-}
-
-void cpufreq_pegasusq_min_cpu_lock(unsigned int num_core)
-{
- int online, flag;
- struct cpu_dbs_info_s *dbs_info;
-
- dbs_tuners_ins.min_cpu_lock = min(num_core, num_possible_cpus());
-
- dbs_info = &per_cpu(od_cpu_dbs_info, 0); /* from CPU0 */
- online = num_online_cpus();
- flag = (int)num_core - online;
- if (flag <= 0)
- return;
- queue_work_on(dbs_info->cpu, dvfs_workqueue, &dbs_info->up_work);
-}
-
-void cpufreq_pegasusq_min_cpu_unlock(void)
-{
- int online, lock, flag;
- struct cpu_dbs_info_s *dbs_info;
-
- dbs_tuners_ins.min_cpu_lock = 0;
-
- dbs_info = &per_cpu(od_cpu_dbs_info, 0); /* from CPU0 */
- online = num_online_cpus();
- lock = atomic_read(&g_hotplug_lock);
- if (lock == 0)
- return;
-#if defined(CONFIG_HAS_EARLYSUSPEND) && EARLYSUSPEND_HOTPLUGLOCK
- if (dbs_tuners_ins.early_suspend >= 0) { /* if LCD is off-state */
- atomic_set(&g_hotplug_lock, 1);
- apply_hotplug_lock();
- return;
- }
-#endif
- flag = lock - online;
- if (flag >= 0)
- return;
- queue_work_on(dbs_info->cpu, dvfs_workqueue, &dbs_info->down_work);
-}
-
-/*
- * History of CPU usage
- */
-struct cpu_usage {
- unsigned int freq;
- unsigned int load[NR_CPUS];
- unsigned int rq_avg;
-};
-
-struct cpu_usage_history {
- struct cpu_usage usage[MAX_HOTPLUG_RATE];
- unsigned int num_hist;
-};
-
-struct cpu_usage_history *hotplug_history;
-
-static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
- cputime64_t *wall)
-{
- cputime64_t idle_time;
- cputime64_t cur_wall_time;
- cputime64_t busy_time;
-
- cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
- busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
- kstat_cpu(cpu).cpustat.system);
-
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal);
- busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.nice);
-
- idle_time = cputime64_sub(cur_wall_time, busy_time);
- if (wall)
- *wall = (cputime64_t)jiffies_to_usecs(cur_wall_time);
-
- return (cputime64_t)jiffies_to_usecs(idle_time);
-}
-
-static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
-{
- u64 idle_time = get_cpu_idle_time_us(cpu, wall);
-
- if (idle_time == -1ULL)
- return get_cpu_idle_time_jiffy(cpu, wall);
-
- return idle_time;
-}
-
-static inline cputime64_t get_cpu_iowait_time(unsigned int cpu,
- cputime64_t *wall)
-{
- u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
-
- if (iowait_time == -1ULL)
- return 0;
-
- return iowait_time;
-}
-
-/************************** sysfs interface ************************/
-
-static ssize_t show_sampling_rate_min(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", min_sampling_rate);
-}
-
-define_one_global_ro(sampling_rate_min);
-
-/* cpufreq_pegasusq Governor Tunables */
-#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", dbs_tuners_ins.object); \
-}
-show_one(sampling_rate, sampling_rate);
-show_one(io_is_busy, io_is_busy);
-show_one(up_threshold, up_threshold);
-show_one(sampling_down_factor, sampling_down_factor);
-show_one(ignore_nice_load, ignore_nice);
-show_one(down_differential, down_differential);
-show_one(freq_step, freq_step);
-show_one(cpu_up_rate, cpu_up_rate);
-show_one(cpu_down_rate, cpu_down_rate);
-show_one(cpu_up_freq, cpu_up_freq);
-show_one(cpu_down_freq, cpu_down_freq);
-show_one(up_nr_cpus, up_nr_cpus);
-show_one(max_cpu_lock, max_cpu_lock);
-show_one(min_cpu_lock, min_cpu_lock);
-show_one(dvfs_debug, dvfs_debug);
-static ssize_t show_hotplug_lock(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", atomic_read(&g_hotplug_lock));
-}
-
-static ssize_t show_cpucore_table(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- ssize_t count = 0;
- int i;
-
- for (i = CONFIG_NR_CPUS; i > 0; i--) {
- count += sprintf(&buf[count], "%d ", i);
- }
- count += sprintf(&buf[count], "\n");
-
- return count;
-}
-
-
-#define show_hotplug_param(file_name, num_core, up_down) \
-static ssize_t show_##file_name##_##num_core##_##up_down \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
-{ \
- return sprintf(buf, "%u\n", file_name[num_core - 1][up_down]); \
-}
-
-#define store_hotplug_param(file_name, num_core, up_down) \
-static ssize_t store_##file_name##_##num_core##_##up_down \
-(struct kobject *kobj, struct attribute *attr, \
- const char *buf, size_t count) \
-{ \
- unsigned int input; \
- int ret; \
- ret = sscanf(buf, "%u", &input); \
- if (ret != 1) \
- return -EINVAL; \
- file_name[num_core - 1][up_down] = input; \
- return count; \
-}
-
-show_hotplug_param(hotplug_freq, 1, 1);
-show_hotplug_param(hotplug_freq, 2, 0);
-show_hotplug_param(hotplug_freq, 2, 1);
-show_hotplug_param(hotplug_freq, 3, 0);
-show_hotplug_param(hotplug_freq, 3, 1);
-show_hotplug_param(hotplug_freq, 4, 0);
-
-show_hotplug_param(hotplug_rq, 1, 1);
-show_hotplug_param(hotplug_rq, 2, 0);
-show_hotplug_param(hotplug_rq, 2, 1);
-show_hotplug_param(hotplug_rq, 3, 0);
-show_hotplug_param(hotplug_rq, 3, 1);
-show_hotplug_param(hotplug_rq, 4, 0);
-
-store_hotplug_param(hotplug_freq, 1, 1);
-store_hotplug_param(hotplug_freq, 2, 0);
-store_hotplug_param(hotplug_freq, 2, 1);
-store_hotplug_param(hotplug_freq, 3, 0);
-store_hotplug_param(hotplug_freq, 3, 1);
-store_hotplug_param(hotplug_freq, 4, 0);
-
-store_hotplug_param(hotplug_rq, 1, 1);
-store_hotplug_param(hotplug_rq, 2, 0);
-store_hotplug_param(hotplug_rq, 2, 1);
-store_hotplug_param(hotplug_rq, 3, 0);
-store_hotplug_param(hotplug_rq, 3, 1);
-store_hotplug_param(hotplug_rq, 4, 0);
-
-define_one_global_rw(hotplug_freq_1_1);
-define_one_global_rw(hotplug_freq_2_0);
-define_one_global_rw(hotplug_freq_2_1);
-define_one_global_rw(hotplug_freq_3_0);
-define_one_global_rw(hotplug_freq_3_1);
-define_one_global_rw(hotplug_freq_4_0);
-
-define_one_global_rw(hotplug_rq_1_1);
-define_one_global_rw(hotplug_rq_2_0);
-define_one_global_rw(hotplug_rq_2_1);
-define_one_global_rw(hotplug_rq_3_0);
-define_one_global_rw(hotplug_rq_3_1);
-define_one_global_rw(hotplug_rq_4_0);
-
-static ssize_t store_sampling_rate(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;
- dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
- return count;
-}
-
-static ssize_t store_io_is_busy(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;
-
- dbs_tuners_ins.io_is_busy = !!input;
- return count;
-}
-
-static ssize_t store_up_threshold(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 || input > MAX_FREQUENCY_UP_THRESHOLD ||
- input < MIN_FREQUENCY_UP_THRESHOLD) {
- return -EINVAL;
- }
- dbs_tuners_ins.up_threshold = input;
- return count;
-}
-
-static ssize_t store_sampling_down_factor(struct kobject *a,
- struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int input, j;
- int ret;
- ret = sscanf(buf, "%u", &input);
-
- if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
- return -EINVAL;
- dbs_tuners_ins.sampling_down_factor = input;
-
- /* Reset down sampling multiplier in case it was active */
- for_each_online_cpu(j) {
- struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(od_cpu_dbs_info, j);
- dbs_info->rate_mult = 1;
- }
- return count;
-}
-
-static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int input;
- int ret;
-
- unsigned int j;
-
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
-
- if (input > 1)
- input = 1;
-
- if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
- return count;
- }
- dbs_tuners_ins.ignore_nice = input;
-
- /* we need to re-evaluate prev_cpu_idle */
- for_each_online_cpu(j) {
- struct cpu_dbs_info_s *dbs_info;
- dbs_info = &per_cpu(od_cpu_dbs_info, j);
- dbs_info->prev_cpu_idle =
- get_cpu_idle_time(j, &dbs_info->prev_cpu_wall);
- if (dbs_tuners_ins.ignore_nice)
- dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
- }
- return count;
-}
-
-static ssize_t store_down_differential(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;
- dbs_tuners_ins.down_differential = min(input, 100u);
- return count;
-}
-
-static ssize_t store_freq_step(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;
- dbs_tuners_ins.freq_step = min(input, 100u);
- return count;
-}
-
-static ssize_t store_cpu_up_rate(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;
- dbs_tuners_ins.cpu_up_rate = min(input, MAX_HOTPLUG_RATE);
- return count;
-}
-
-static ssize_t store_cpu_down_rate(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;
- dbs_tuners_ins.cpu_down_rate = min(input, MAX_HOTPLUG_RATE);
- return count;
-}
-
-static ssize_t store_cpu_up_freq(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;
- dbs_tuners_ins.cpu_up_freq = min(input, dbs_tuners_ins.max_freq);
- return count;
-}
-
-static ssize_t store_cpu_down_freq(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;
- dbs_tuners_ins.cpu_down_freq = max(input, dbs_tuners_ins.min_freq);
- return count;
-}
-
-static ssize_t store_up_nr_cpus(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;
- dbs_tuners_ins.up_nr_cpus = min(input, num_possible_cpus());
- return count;
-}
-
-static ssize_t store_max_cpu_lock(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;
- dbs_tuners_ins.max_cpu_lock = min(input, num_possible_cpus());
- return count;
-}
-
-static ssize_t store_min_cpu_lock(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;
- if (input == 0)
- cpufreq_pegasusq_min_cpu_unlock();
- else
- cpufreq_pegasusq_min_cpu_lock(input);
- return count;
-}
-
-static ssize_t store_hotplug_lock(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
-{
- unsigned int input;
- int ret;
- int prev_lock;
-
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- input = min(input, num_possible_cpus());
- prev_lock = atomic_read(&dbs_tuners_ins.hotplug_lock);
-
- if (prev_lock)
- cpufreq_pegasusq_cpu_unlock(prev_lock);
-
- if (input == 0) {
- atomic_set(&dbs_tuners_ins.hotplug_lock, 0);
- return count;
- }
-
- ret = cpufreq_pegasusq_cpu_lock(input);
- if (ret) {
- printk(KERN_ERR "[HOTPLUG] already locked with smaller value %d < %d\n",
- atomic_read(&g_hotplug_lock), input);
- return ret;
- }
-
- atomic_set(&dbs_tuners_ins.hotplug_lock, input);
-
- return count;
-}
-
-static ssize_t store_dvfs_debug(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;
- dbs_tuners_ins.dvfs_debug = input > 0;
- return count;
-}
-
-define_one_global_rw(sampling_rate);
-define_one_global_rw(io_is_busy);
-define_one_global_rw(up_threshold);
-define_one_global_rw(sampling_down_factor);
-define_one_global_rw(ignore_nice_load);
-define_one_global_rw(down_differential);
-define_one_global_rw(freq_step);
-define_one_global_rw(cpu_up_rate);
-define_one_global_rw(cpu_down_rate);
-define_one_global_rw(cpu_up_freq);
-define_one_global_rw(cpu_down_freq);
-define_one_global_rw(up_nr_cpus);
-define_one_global_rw(max_cpu_lock);
-define_one_global_rw(min_cpu_lock);
-define_one_global_rw(hotplug_lock);
-define_one_global_rw(dvfs_debug);
-define_one_global_ro(cpucore_table);
-
-static struct attribute *dbs_attributes[] = {
- &sampling_rate_min.attr,
- &sampling_rate.attr,
- &up_threshold.attr,
- &sampling_down_factor.attr,
- &ignore_nice_load.attr,
- &io_is_busy.attr,
- &down_differential.attr,
- &freq_step.attr,
- &cpu_up_rate.attr,
- &cpu_down_rate.attr,
- &cpu_up_freq.attr,
- &cpu_down_freq.attr,
- &up_nr_cpus.attr,
- /* priority: hotplug_lock > max_cpu_lock > min_cpu_lock
- Exception: hotplug_lock on early_suspend uses min_cpu_lock */
- &max_cpu_lock.attr,
- &min_cpu_lock.attr,
- &hotplug_lock.attr,
- &dvfs_debug.attr,
- &hotplug_freq_1_1.attr,
- &hotplug_freq_2_0.attr,
- &hotplug_freq_2_1.attr,
- &hotplug_freq_3_0.attr,
- &hotplug_freq_3_1.attr,
- &hotplug_freq_4_0.attr,
- &hotplug_rq_1_1.attr,
- &hotplug_rq_2_0.attr,
- &hotplug_rq_2_1.attr,
- &hotplug_rq_3_0.attr,
- &hotplug_rq_3_1.attr,
- &hotplug_rq_4_0.attr,
- &cpucore_table.attr,
- NULL
-};
-
-static struct attribute_group dbs_attr_group = {
- .attrs = dbs_attributes,
- .name = "pegasusq",
-};
-
-/************************** sysfs end ************************/
-
-static void cpu_up_work(struct work_struct *work)
-{
- int cpu;
- int online = num_online_cpus();
- int nr_up = dbs_tuners_ins.up_nr_cpus;
- int min_cpu_lock = dbs_tuners_ins.min_cpu_lock;
- int hotplug_lock = atomic_read(&g_hotplug_lock);
-
- if (hotplug_lock && min_cpu_lock)
- nr_up = max(hotplug_lock, min_cpu_lock) - online;
- else if (hotplug_lock)
- nr_up = hotplug_lock - online;
- else if (min_cpu_lock)
- nr_up = max(nr_up, min_cpu_lock - online);
-
- if (online == 1) {
- printk(KERN_ERR "CPU_UP 3\n");
- cpu_up(num_possible_cpus() - 1);
- nr_up -= 1;
- }
-
- for_each_cpu_not(cpu, cpu_online_mask) {
- if (nr_up-- == 0)
- break;
- if (cpu == 0)
- continue;
- printk(KERN_ERR "CPU_UP %d\n", cpu);
- cpu_up(cpu);
- }
-}
-
-static void cpu_down_work(struct work_struct *work)
-{
- int cpu;
- int online = num_online_cpus();
- int nr_down = 1;
- int hotplug_lock = atomic_read(&g_hotplug_lock);
-
- if (hotplug_lock)
- nr_down = online - hotplug_lock;
-
- for_each_online_cpu(cpu) {
- if (cpu == 0)
- continue;
- printk(KERN_ERR "CPU_DOWN %d\n", cpu);
- cpu_down(cpu);
- if (--nr_down == 0)
- break;
- }
-}
-
-static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
-{
-#ifndef CONFIG_ARCH_EXYNOS4
- if (p->cur == p->max)
- return;
-#endif
-
- __cpufreq_driver_target(p, freq, CPUFREQ_RELATION_L);
-}
-
-/*
- * print hotplug debugging info.
- * which 1 : UP, 0 : DOWN
- */
-static void debug_hotplug_check(int which, int rq_avg, int freq,
- struct cpu_usage *usage)
-{
- int cpu;
- printk(KERN_ERR "CHECK %s rq %d.%02d freq %d [", which ? "up" : "down",
- rq_avg / 100, rq_avg % 100, freq);
- for_each_online_cpu(cpu) {
- printk(KERN_ERR "(%d, %d), ", cpu, usage->load[cpu]);
- }
- printk(KERN_ERR "]\n");
-}
-
-static int check_up(void)
-{
- int num_hist = hotplug_history->num_hist;
- struct cpu_usage *usage;
- int freq, rq_avg;
- int i;
- int up_rate = dbs_tuners_ins.cpu_up_rate;
- int up_freq, up_rq;
- int min_freq = INT_MAX;
- int min_rq_avg = INT_MAX;
- int online;
- int hotplug_lock = atomic_read(&g_hotplug_lock);
-
- if (hotplug_lock > 0)
- return 0;
-
- online = num_online_cpus();
- up_freq = hotplug_freq[online - 1][HOTPLUG_UP_INDEX];
- up_rq = hotplug_rq[online - 1][HOTPLUG_UP_INDEX];
-
- if (online == num_possible_cpus())
- return 0;
-
- if (dbs_tuners_ins.max_cpu_lock != 0
- && online >= dbs_tuners_ins.max_cpu_lock)
- return 0;
-
- if (dbs_tuners_ins.min_cpu_lock != 0
- && online < dbs_tuners_ins.min_cpu_lock)
- return 1;
-
- if (num_hist == 0 || num_hist % up_rate)
- return 0;
-
- for (i = num_hist - 1; i >= num_hist - up_rate; --i) {
- usage = &hotplug_history->usage[i];
-
- freq = usage->freq;
- rq_avg = usage->rq_avg;
-
- min_freq = min(min_freq, freq);
- min_rq_avg = min(min_rq_avg, rq_avg);
-
- if (dbs_tuners_ins.dvfs_debug)
- debug_hotplug_check(1, rq_avg, freq, usage);
- }
-
- if (min_freq >= up_freq && min_rq_avg > up_rq) {
- printk(KERN_ERR "[HOTPLUG IN] %s %d>=%d && %d>%d\n",
- __func__, min_freq, up_freq, min_rq_avg, up_rq);
- hotplug_history->num_hist = 0;
- return 1;
- }
- return 0;
-}
-
-static int check_down(void)
-{
- int num_hist = hotplug_history->num_hist;
- struct cpu_usage *usage;
- int freq, rq_avg;
- int i;
- int down_rate = dbs_tuners_ins.cpu_down_rate;
- int down_freq, down_rq;
- int max_freq = 0;
- int max_rq_avg = 0;
- int online;
- int hotplug_lock = atomic_read(&g_hotplug_lock);
-
- if (hotplug_lock > 0)
- return 0;
-
- online = num_online_cpus();
- down_freq = hotplug_freq[online - 1][HOTPLUG_DOWN_INDEX];
- down_rq = hotplug_rq[online - 1][HOTPLUG_DOWN_INDEX];
-
- if (online == 1)
- return 0;
-
- if (dbs_tuners_ins.max_cpu_lock != 0
- && online > dbs_tuners_ins.max_cpu_lock)
- return 1;
-
- if (dbs_tuners_ins.min_cpu_lock != 0
- && online <= dbs_tuners_ins.min_cpu_lock)
- return 0;
-
- if (num_hist == 0 || num_hist % down_rate)
- return 0;
-
- for (i = num_hist - 1; i >= num_hist - down_rate; --i) {
- usage = &hotplug_history->usage[i];
-
- freq = usage->freq;
- rq_avg = usage->rq_avg;
-
- max_freq = max(max_freq, freq);
- max_rq_avg = max(max_rq_avg, rq_avg);
-
- if (dbs_tuners_ins.dvfs_debug)
- debug_hotplug_check(0, rq_avg, freq, usage);
- }
-
- if (max_freq <= down_freq && max_rq_avg <= down_rq) {
- printk(KERN_ERR "[HOTPLUG OUT] %s %d<=%d && %d<%d\n",
- __func__, max_freq, down_freq, max_rq_avg, down_rq);
- hotplug_history->num_hist = 0;
- return 1;
- }
-
- return 0;
-}
-
-static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
-{
- unsigned int max_load_freq;
-
- struct cpufreq_policy *policy;
- unsigned int j;
- int num_hist = hotplug_history->num_hist;
- int max_hotplug_rate = max(dbs_tuners_ins.cpu_up_rate,
- dbs_tuners_ins.cpu_down_rate);
- int up_threshold = dbs_tuners_ins.up_threshold;
-
- policy = this_dbs_info->cur_policy;
-
- hotplug_history->usage[num_hist].freq = policy->cur;
- hotplug_history->usage[num_hist].rq_avg = get_nr_run_avg();
- ++hotplug_history->num_hist;
-
- /* Get Absolute Load - in terms of freq */
- max_load_freq = 0;
-
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
- cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
- cputime64_t prev_wall_time, prev_idle_time, prev_iowait_time;
- unsigned int idle_time, wall_time, iowait_time;
- unsigned int load, load_freq;
- int freq_avg;
-
- j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
- prev_wall_time = j_dbs_info->prev_cpu_wall;
- prev_idle_time = j_dbs_info->prev_cpu_idle;
- prev_iowait_time = j_dbs_info->prev_cpu_iowait;
-
- cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
- cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time);
-
- wall_time = (unsigned int) cputime64_sub(cur_wall_time,
- prev_wall_time);
- j_dbs_info->prev_cpu_wall = cur_wall_time;
-
- idle_time = (unsigned int) cputime64_sub(cur_idle_time,
- prev_idle_time);
- j_dbs_info->prev_cpu_idle = cur_idle_time;
-
- iowait_time = (unsigned int) cputime64_sub(cur_iowait_time,
- prev_iowait_time);
- j_dbs_info->prev_cpu_iowait = cur_iowait_time;
-
- if (dbs_tuners_ins.ignore_nice) {
- cputime64_t cur_nice;
- unsigned long cur_nice_jiffies;
-
- cur_nice = cputime64_sub(kstat_cpu(j).cpustat.nice,
- j_dbs_info->prev_cpu_nice);
- /*
- * Assumption: nice time between sampling periods will
- * be less than 2^32 jiffies for 32 bit sys
- */
- cur_nice_jiffies = (unsigned long)
- cputime64_to_jiffies64(cur_nice);
-
- j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
- idle_time += jiffies_to_usecs(cur_nice_jiffies);
- }
-
- if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time)
- idle_time -= iowait_time;
-
- if (unlikely(!wall_time || wall_time < idle_time))
- continue;
-
- load = 100 * (wall_time - idle_time) / wall_time;
- hotplug_history->usage[num_hist].load[j] = load;
-
- freq_avg = __cpufreq_driver_getavg(policy, j);
- if (freq_avg <= 0)
- freq_avg = policy->cur;
-
- load_freq = load * freq_avg;
- if (load_freq > max_load_freq)
- max_load_freq = load_freq;
- }
-
- /* Check for CPU hotplug */
- if (check_up()) {
- queue_work_on(this_dbs_info->cpu, dvfs_workqueue,
- &this_dbs_info->up_work);
- } else if (check_down()) {
- queue_work_on(this_dbs_info->cpu, dvfs_workqueue,
- &this_dbs_info->down_work);
- }
- if (hotplug_history->num_hist == max_hotplug_rate)
- hotplug_history->num_hist = 0;
-
- /* Check for frequency increase */
- if (policy->cur < FREQ_FOR_RESPONSIVENESS) {
- up_threshold = UP_THRESHOLD_AT_MIN_FREQ;
- }
-
- if (max_load_freq > up_threshold * policy->cur) {
- int inc = (policy->max * dbs_tuners_ins.freq_step) / 100;
- int target = min(policy->max, policy->cur + inc);
- /* If switching to max speed, apply sampling_down_factor */
- if (policy->cur < policy->max && target == policy->max)
- this_dbs_info->rate_mult =
- dbs_tuners_ins.sampling_down_factor;
- dbs_freq_increase(policy, target);
- return;
- }
-
- /* Check for frequency decrease */
-#ifndef CONFIG_ARCH_EXYNOS4
- /* if we cannot reduce the frequency anymore, break out early */
- if (policy->cur == policy->min)
- return;
-#endif
-
- /*
- * The optimal frequency is the frequency that is the lowest that
- * can support the current CPU usage without triggering the up
- * policy. To be safe, we focus DOWN_DIFFERENTIAL points under
- * the threshold.
- */
- if (max_load_freq <
- (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) *
- policy->cur) {
- unsigned int freq_next;
- unsigned int down_thres;
-
- freq_next = max_load_freq /
- (dbs_tuners_ins.up_threshold -
- dbs_tuners_ins.down_differential);
-
- /* No longer fully busy, reset rate_mult */
- this_dbs_info->rate_mult = 1;
-
- if (freq_next < policy->min)
- freq_next = policy->min;
-
-
- down_thres = UP_THRESHOLD_AT_MIN_FREQ
- - dbs_tuners_ins.down_differential;
-
- if (freq_next < FREQ_FOR_RESPONSIVENESS
- && (max_load_freq / freq_next) > down_thres)
- freq_next = FREQ_FOR_RESPONSIVENESS;
-
- if (policy->cur == freq_next)
- return;
-
- __cpufreq_driver_target(policy, freq_next,
- CPUFREQ_RELATION_L);
- }
-}
-
-static void do_dbs_timer(struct work_struct *work)
-{
- struct cpu_dbs_info_s *dbs_info =
- container_of(work, struct cpu_dbs_info_s, work.work);
- unsigned int cpu = dbs_info->cpu;
- int delay;
-
- mutex_lock(&dbs_info->timer_mutex);
-
- dbs_check_cpu(dbs_info);
- /* We want all CPUs to do sampling nearly on
- * same jiffy
- */
- delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
- * dbs_info->rate_mult);
-
- if (num_online_cpus() > 1)
- delay -= jiffies % delay;
-
- queue_delayed_work_on(cpu, dvfs_workqueue, &dbs_info->work, delay);
- mutex_unlock(&dbs_info->timer_mutex);
-}
-
-static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
-{
- /* We want all CPUs to do sampling nearly on same jiffy */
- int delay = usecs_to_jiffies(DEF_START_DELAY * 1000 * 1000
- + dbs_tuners_ins.sampling_rate);
- if (num_online_cpus() > 1)
- delay -= jiffies % delay;
-
- INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
- INIT_WORK(&dbs_info->up_work, cpu_up_work);
- INIT_WORK(&dbs_info->down_work, cpu_down_work);
-
- queue_delayed_work_on(dbs_info->cpu, dvfs_workqueue,
- &dbs_info->work, delay + 2 * HZ);
-}
-
-static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
-{
- cancel_delayed_work_sync(&dbs_info->work);
- cancel_work_sync(&dbs_info->up_work);
- cancel_work_sync(&dbs_info->down_work);
-}
-
-static int pm_notifier_call(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- static unsigned int prev_hotplug_lock;
- switch (event) {
- case PM_SUSPEND_PREPARE:
- prev_hotplug_lock = atomic_read(&g_hotplug_lock);
- atomic_set(&g_hotplug_lock, 1);
- apply_hotplug_lock();
- pr_debug("%s enter suspend\n", __func__);
- return NOTIFY_OK;
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- atomic_set(&g_hotplug_lock, prev_hotplug_lock);
- if (prev_hotplug_lock)
- apply_hotplug_lock();
- prev_hotplug_lock = 0;
- pr_debug("%s exit suspend\n", __func__);
- return NOTIFY_OK;
- }
- return NOTIFY_DONE;
-}
-
-static struct notifier_block pm_notifier = {
- .notifier_call = pm_notifier_call,
-};
-
-static int reboot_notifier_call(struct notifier_block *this,
- unsigned long code, void *_cmd)
-{
- atomic_set(&g_hotplug_lock, 1);
- return NOTIFY_DONE;
-}
-
-static struct notifier_block reboot_notifier = {
- .notifier_call = reboot_notifier_call,
-};
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static struct early_suspend early_suspend;
-unsigned int prev_freq_step;
-unsigned int prev_sampling_rate;
-static void cpufreq_pegasusq_early_suspend(struct early_suspend *h)
-{
-#if EARLYSUSPEND_HOTPLUGLOCK
- dbs_tuners_ins.early_suspend =
- atomic_read(&g_hotplug_lock);
-#endif
- prev_freq_step = dbs_tuners_ins.freq_step;
- prev_sampling_rate = dbs_tuners_ins.sampling_rate;
- dbs_tuners_ins.freq_step = 20;
- dbs_tuners_ins.sampling_rate *= 4;
-#if EARLYSUSPEND_HOTPLUGLOCK
- atomic_set(&g_hotplug_lock,
- (dbs_tuners_ins.min_cpu_lock) ? dbs_tuners_ins.min_cpu_lock : 1);
- apply_hotplug_lock();
- stop_rq_work();
-#endif
-}
-static void cpufreq_pegasusq_late_resume(struct early_suspend *h)
-{
-#if EARLYSUSPEND_HOTPLUGLOCK
- atomic_set(&g_hotplug_lock, dbs_tuners_ins.early_suspend);
-#endif
- dbs_tuners_ins.early_suspend = -1;
- dbs_tuners_ins.freq_step = prev_freq_step;
- dbs_tuners_ins.sampling_rate = prev_sampling_rate;
-#if EARLYSUSPEND_HOTPLUGLOCK
- apply_hotplug_lock();
- start_rq_work();
-#endif
-}
-#endif
-
-static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event)
-{
- unsigned int cpu = policy->cpu;
- struct cpu_dbs_info_s *this_dbs_info;
- unsigned int j;
- int rc;
-
- this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
-
- switch (event) {
- case CPUFREQ_GOV_START:
- if ((!cpu_online(cpu)) || (!policy->cur))
- return -EINVAL;
-
- dbs_tuners_ins.max_freq = policy->max;
- dbs_tuners_ins.min_freq = policy->min;
- hotplug_history->num_hist = 0;
- start_rq_work();
-
- mutex_lock(&dbs_mutex);
-
- dbs_enable++;
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
- j_dbs_info->cur_policy = policy;
-
- j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
- &j_dbs_info->prev_cpu_wall);
- if (dbs_tuners_ins.ignore_nice) {
- j_dbs_info->prev_cpu_nice =
- kstat_cpu(j).cpustat.nice;
- }
- }
- this_dbs_info->cpu = cpu;
- this_dbs_info->rate_mult = 1;
- /*
- * Start the timerschedule work, when this governor
- * is used for first time
- */
- if (dbs_enable == 1) {
- rc = sysfs_create_group(cpufreq_global_kobject,
- &dbs_attr_group);
- if (rc) {
- mutex_unlock(&dbs_mutex);
- return rc;
- }
-
- min_sampling_rate = MIN_SAMPLING_RATE;
- dbs_tuners_ins.sampling_rate = DEF_SAMPLING_RATE;
- dbs_tuners_ins.io_is_busy = 0;
- }
- mutex_unlock(&dbs_mutex);
-
- register_reboot_notifier(&reboot_notifier);
-
- mutex_init(&this_dbs_info->timer_mutex);
- dbs_timer_init(this_dbs_info);
-
-#if !EARLYSUSPEND_HOTPLUGLOCK
- register_pm_notifier(&pm_notifier);
-#endif
-#ifdef CONFIG_HAS_EARLYSUSPEND
- register_early_suspend(&early_suspend);
-#endif
- break;
-
- case CPUFREQ_GOV_STOP:
-#ifdef CONFIG_HAS_EARLYSUSPEND
- unregister_early_suspend(&early_suspend);
-#endif
-#if !EARLYSUSPEND_HOTPLUGLOCK
- unregister_pm_notifier(&pm_notifier);
-#endif
-
- dbs_timer_exit(this_dbs_info);
-
- mutex_lock(&dbs_mutex);
- mutex_destroy(&this_dbs_info->timer_mutex);
-
- unregister_reboot_notifier(&reboot_notifier);
-
- dbs_enable--;
- mutex_unlock(&dbs_mutex);
-
- stop_rq_work();
-
- if (!dbs_enable)
- sysfs_remove_group(cpufreq_global_kobject,
- &dbs_attr_group);
-
- break;
-
- case CPUFREQ_GOV_LIMITS:
- mutex_lock(&this_dbs_info->timer_mutex);
-
- if (policy->max < this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- policy->max,
- CPUFREQ_RELATION_H);
- else if (policy->min > this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- policy->min,
- CPUFREQ_RELATION_L);
-
- mutex_unlock(&this_dbs_info->timer_mutex);
- break;
- }
- return 0;
-}
-
-static int __init cpufreq_gov_dbs_init(void)
-{
- int ret;
-
- ret = init_rq_avg();
- if (ret)
- return ret;
-
- hotplug_history = kzalloc(sizeof(struct cpu_usage_history), GFP_KERNEL);
- if (!hotplug_history) {
- pr_err("%s cannot create hotplug history array\n", __func__);
- ret = -ENOMEM;
- goto err_hist;
- }
-
- dvfs_workqueue = create_workqueue("kpegasusq");
- if (!dvfs_workqueue) {
- pr_err("%s cannot create workqueue\n", __func__);
- ret = -ENOMEM;
- goto err_queue;
- }
-
- ret = cpufreq_register_governor(&cpufreq_gov_pegasusq);
- if (ret)
- goto err_reg;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
- early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
- early_suspend.suspend = cpufreq_pegasusq_early_suspend;
- early_suspend.resume = cpufreq_pegasusq_late_resume;
-#endif
-
- return ret;
-
-err_reg:
- destroy_workqueue(dvfs_workqueue);
-err_queue:
- kfree(hotplug_history);
-err_hist:
- kfree(rq_data);
- return ret;
-}
-
-static void __exit cpufreq_gov_dbs_exit(void)
-{
- cpufreq_unregister_governor(&cpufreq_gov_pegasusq);
- destroy_workqueue(dvfs_workqueue);
- kfree(hotplug_history);
- kfree(rq_data);
-}
-
-MODULE_AUTHOR("ByungChang Cha <bc.cha@samsung.com>");
-MODULE_DESCRIPTION("'cpufreq_pegasusq' - A dynamic cpufreq/cpuhotplug governor");
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PEGASUSQ
-fs_initcall(cpufreq_gov_dbs_init);
-#else
-module_init(cpufreq_gov_dbs_init);
-#endif
-module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index f6fba49..4bf374d 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -15,6 +15,7 @@
#include <linux/cpu.h>
#include <linux/sysfs.h>
#include <linux/cpufreq.h>
+#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/kobject.h>
@@ -317,27 +318,6 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
return 0;
}
-static int cpufreq_stats_create_table_cpu(unsigned int cpu)
-{
- struct cpufreq_policy *policy;
- struct cpufreq_frequency_table *table;
- int ret = -ENODEV;
-
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return -ENODEV;
-
- table = cpufreq_frequency_get_table(cpu);
- if (!table)
- goto out;
-
- ret = cpufreq_stats_create_table(policy, table);
-
-out:
- cpufreq_cpu_put(policy);
- return ret;
-}
-
static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
@@ -357,10 +337,6 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
break;
- case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- cpufreq_stats_create_table_cpu(cpu);
- break;
}
return NOTIFY_OK;
}
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index d90456a..f500201 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -12,30 +12,35 @@
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
#include <mach/id.h>
static struct cpufreq_frequency_table freq_table[] = {
[0] = {
.index = 0,
- .frequency = 300000,
+ .frequency = 200000,
},
[1] = {
.index = 1,
- .frequency = 600000,
+ .frequency = 300000,
},
[2] = {
- /* Used for MAX_OPP, if available */
.index = 2,
- .frequency = CPUFREQ_TABLE_END,
+ .frequency = 600000,
},
[3] = {
+ /* Used for MAX_OPP, if available */
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
+ [4] = {
+ .index = 4,
+ .frequency = CPUFREQ_TABLE_END,
+ },
};
static enum arm_opp idx2opp[] = {
+ ARM_EXTCLK,
ARM_50_OPP,
ARM_100_OPP,
ARM_MAX_OPP
@@ -72,13 +77,13 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = freq_table[idx].frequency;
- freqs.cpu = policy->cpu;
if (freqs.old == freqs.new)
return 0;
/* pre-change notification */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ for_each_cpu(freqs.cpu, policy->cpus)
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* request the PRCM unit for opp change */
if (prcmu_set_arm_opp(idx2opp[idx])) {
@@ -87,7 +92,8 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
}
/* post change notification */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ for_each_cpu(freqs.cpu, policy->cpus)
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
@@ -103,17 +109,19 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{
- int res;
- int i;
+ int i, res;
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
- if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
- freq_table[0].frequency = 400000;
- freq_table[1].frequency = 800000;
+ if (!prcmu_is_u8400()) {
+ freq_table[1].frequency = 400000;
+ freq_table[2].frequency = 800000;
if (prcmu_has_arm_maxopp())
- freq_table[2].frequency = 1000000;
+ freq_table[3].frequency = 1000000;
}
+ pr_info("db8500-cpufreq : Available frequencies:\n");
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+ pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
@@ -127,10 +135,6 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = db8500_cpufreq_getspeed(policy->cpu);
-
- for (i = 0; freq_table[i].frequency != policy->cur; i++)
- ;
-
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/*
diff --git a/drivers/cpufreq/dvfs_monitor.c b/drivers/cpufreq/dvfs_monitor.c
deleted file mode 100644
index e1e02b4..0000000
--- a/drivers/cpufreq/dvfs_monitor.c
+++ /dev/null
@@ -1,236 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/atomic.h>
-#include <linux/tick.h>
-
-struct cpufreq_load_data {
- cputime64_t prev_idle;
- cputime64_t prev_wall;
- unsigned char load;
-};
-
-struct dvfs_data {
- atomic_t opened;
- atomic_t num_events;
- unsigned char cpus[NR_CPUS];
- unsigned int prev_freq[NR_CPUS];
- unsigned int freq[NR_CPUS];
- struct cpufreq_load_data load_data[NR_CPUS];
- wait_queue_head_t wait_queue;
- spinlock_t load_lock;
-};
-
-static struct dvfs_data *dvfs_info;
-
-static void init_dvfs_mon(void)
-{
- int cpu;
- int cur_freq = cpufreq_get(0);
-
- for_each_possible_cpu(cpu) {
- dvfs_info->cpus[cpu] = cpu_online(cpu);
- dvfs_info->freq[cpu] = cur_freq;
- }
- atomic_set(&dvfs_info->num_events, 1);
-}
-
-static void calculate_load(void)
-{
- int cpu;
- cputime64_t cur_wall, cur_idle;
- cputime64_t prev_wall, prev_idle;
- unsigned int wall_time, idle_time;
- unsigned long flags;
-
- spin_lock_irqsave(&dvfs_info->load_lock, flags);
- for_each_online_cpu(cpu) {
- cur_idle = get_cpu_idle_time_us(cpu, &cur_wall);
- prev_idle = dvfs_info->load_data[cpu].prev_idle;
- prev_wall = dvfs_info->load_data[cpu].prev_wall;
-
- dvfs_info->load_data[cpu].prev_idle = cur_idle;
- dvfs_info->load_data[cpu].prev_wall = cur_wall;
-
- idle_time = (unsigned int)cputime64_sub(cur_idle, prev_idle);
- wall_time = (unsigned int)cputime64_sub(cur_wall, prev_wall);
-
- if (wall_time < idle_time) {
- pr_err("%s walltime < idletime\n", __func__);
- dvfs_info->load_data[cpu].load = 0;
- }
-
- dvfs_info->load_data[cpu].load = (wall_time - idle_time) * 100
- / wall_time;
- }
- spin_unlock_irqrestore(&dvfs_info->load_lock, flags);
- return;
-}
-
-static int dvfs_monitor_trans(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct cpufreq_freqs *freq = data;
-
- if (val != CPUFREQ_POSTCHANGE)
- return 0;
-
- if (freq->new == freq->old)
- return 0;
-
- dvfs_info->prev_freq[freq->cpu] = freq->old;
- dvfs_info->freq[freq->cpu] = freq->new;
-
- calculate_load();
-
- atomic_inc(&dvfs_info->num_events);
- wake_up_interruptible(&dvfs_info->wait_queue);
-
- return 0;
-}
-
-static int __cpuinit dvfs_monitor_hotplug(struct notifier_block *nb,
- unsigned long action,
- void *hcpu)
-{
- unsigned int cpu = (unsigned long)hcpu;
- int cpu_status = 0;
-
- switch (action) {
- case CPU_ONLINE:
- cpu_status = 1;
- break;
- case CPU_DOWN_PREPARE:
- cpu_status = 0;
- break;
- default:
- return NOTIFY_OK;
- }
-
- dvfs_info->cpus[cpu] = cpu_status;
- atomic_inc(&dvfs_info->num_events);
- calculate_load();
- wake_up_interruptible(&dvfs_info->wait_queue);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block notifier_trans_block = {
- .notifier_call = dvfs_monitor_trans,
-};
-
-static struct notifier_block notifier_hotplug_block __refdata = {
- .notifier_call = dvfs_monitor_hotplug,
- .priority = 1,
-};
-
-static int dvfs_mon_open(struct inode *inode, struct file *file)
-{
- int ret = 0;
-
- if (atomic_xchg(&dvfs_info->opened, 1) != 0)
- return -EBUSY;
-
- init_dvfs_mon();
- ret = cpufreq_register_notifier(&notifier_trans_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- if (ret)
- return ret;
-
- register_hotcpu_notifier(&notifier_hotplug_block);
-
- return 0;
-}
-
-static int dvfs_mon_release(struct inode *inode, struct file *file)
-{
- int ret = 0;
-
- atomic_dec(&dvfs_info->opened);
- ret = cpufreq_unregister_notifier(&notifier_trans_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- unregister_hotcpu_notifier(&notifier_hotplug_block);
-
- return ret;
-}
-
-static ssize_t dvfs_mon_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned long long t;
- unsigned long nanosec_rem;
- int freq, prev_freq;
- char cpu_status[NR_CPUS * 8 + 1];
- char temp[3];
- int i;
-
- wait_event_interruptible(dvfs_info->wait_queue,
- atomic_read(&dvfs_info->num_events));
-
- atomic_set(&dvfs_info->num_events, 0);
-
- /* for now, assume that all cores run on same speed */
- freq = dvfs_info->freq[0];
- prev_freq = dvfs_info->prev_freq[0];
- dvfs_info->prev_freq[0] = freq;
-
- memset(cpu_status, 0, sizeof(cpu_status));
- for (i = 0; i != num_possible_cpus(); ++i) {
- unsigned char load = dvfs_info->cpus[i] ?
- dvfs_info->load_data[i].load : 0;
- sprintf(temp, "(%d,%3d),", dvfs_info->cpus[i], load);
- strcat(cpu_status, temp);
- }
-
- t = cpu_clock(0);
- nanosec_rem = do_div(t, 1000000000);
-
- return sprintf(buf, "%lu.%06lu,%s%d,%d\n",
- (unsigned long) t, nanosec_rem / 1000,
- cpu_status, prev_freq, freq);
-}
-
-static const struct file_operations dvfs_mon_operations = {
- .read = dvfs_mon_read,
- .open = dvfs_mon_open,
- .release = dvfs_mon_release,
-};
-
-static int __init dvfs_monitor_init(void)
-{
- dvfs_info = kzalloc(sizeof(struct dvfs_data), GFP_KERNEL);
- if (dvfs_info == NULL) {
- pr_err("[DVFS_MON] cannot allocate memory\n");
- return -ENOMEM;
- }
-
- spin_lock_init(&dvfs_info->load_lock);
-
- init_waitqueue_head(&dvfs_info->wait_queue);
-
- proc_create("dvfs_mon", S_IRUSR, NULL, &dvfs_mon_operations);
-
- return 0;
-}
-late_initcall(dvfs_monitor_init);
-
-static void __exit dvfs_monitor_exit(void)
-{
- kfree(dvfs_info);
- return;
-}
-module_exit(dvfs_monitor_exit);
-
-MODULE_AUTHOR("ByungChang Cha <bc.cha@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("DVFS Monitoring proc file");
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 35a257d..4bd6815 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -19,6 +19,11 @@
#include <asm/msr.h>
#include <asm/tsc.h>
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+#endif
+
#define EPS_BRAND_C7M 0
#define EPS_BRAND_C7 1
#define EPS_BRAND_EDEN 2
@@ -27,11 +32,59 @@
struct eps_cpu_data {
u32 fsb;
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+ u32 bios_limit;
+#endif
struct cpufreq_frequency_table freq_table[];
};
static struct eps_cpu_data *eps_cpu[NR_CPUS];
+/* Module parameters */
+static int freq_failsafe_off;
+static int voltage_failsafe_off;
+static int set_max_voltage;
+
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+static int ignore_acpi_limit;
+
+static struct acpi_processor_performance *eps_acpi_cpu_perf;
+
+/* Minimum necessary to get acpi_processor_get_bios_limit() working */
+static int eps_acpi_init(void)
+{
+ eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
+ GFP_KERNEL);
+ if (!eps_acpi_cpu_perf)
+ return -ENOMEM;
+
+ if (!zalloc_cpumask_var(&eps_acpi_cpu_perf->shared_cpu_map,
+ GFP_KERNEL)) {
+ kfree(eps_acpi_cpu_perf);
+ eps_acpi_cpu_perf = NULL;
+ return -ENOMEM;
+ }
+
+ if (acpi_processor_register_performance(eps_acpi_cpu_perf, 0)) {
+ free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
+ kfree(eps_acpi_cpu_perf);
+ eps_acpi_cpu_perf = NULL;
+ return -EIO;
+ }
+ return 0;
+}
+
+static int eps_acpi_exit(struct cpufreq_policy *policy)
+{
+ if (eps_acpi_cpu_perf) {
+ acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0);
+ free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
+ kfree(eps_acpi_cpu_perf);
+ eps_acpi_cpu_perf = NULL;
+ }
+ return 0;
+}
+#endif
static unsigned int eps_get(unsigned int cpu)
{
@@ -164,6 +217,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
int k, step, voltage;
int ret;
int states;
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+ unsigned int limit;
+#endif
if (policy->cpu != 0)
return -ENODEV;
@@ -244,11 +300,62 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
return -EINVAL;
if (current_voltage > 0x1f || max_voltage > 0x1f)
return -EINVAL;
- if (max_voltage < min_voltage)
+ if (max_voltage < min_voltage
+ || current_voltage < min_voltage
+ || current_voltage > max_voltage)
return -EINVAL;
+ /* Check for systems using underclocked CPU */
+ if (!freq_failsafe_off && max_multiplier != current_multiplier) {
+ printk(KERN_INFO "eps: Your processor is running at different "
+ "frequency then its maximum. Aborting.\n");
+ printk(KERN_INFO "eps: You can use freq_failsafe_off option "
+ "to disable this check.\n");
+ return -EINVAL;
+ }
+ if (!voltage_failsafe_off && max_voltage != current_voltage) {
+ printk(KERN_INFO "eps: Your processor is running at different "
+ "voltage then its maximum. Aborting.\n");
+ printk(KERN_INFO "eps: You can use voltage_failsafe_off "
+ "option to disable this check.\n");
+ return -EINVAL;
+ }
+
/* Calc FSB speed */
fsb = cpu_khz / current_multiplier;
+
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+ /* Check for ACPI processor speed limit */
+ if (!ignore_acpi_limit && !eps_acpi_init()) {
+ if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
+ printk(KERN_INFO "eps: ACPI limit %u.%uGHz\n",
+ limit/1000000,
+ (limit%1000000)/10000);
+ eps_acpi_exit(policy);
+ /* Check if max_multiplier is in BIOS limits */
+ if (limit && max_multiplier * fsb > limit) {
+ printk(KERN_INFO "eps: Aborting.\n");
+ return -EINVAL;
+ }
+ }
+ }
+#endif
+
+ /* Allow user to set lower maximum voltage then that reported
+ * by processor */
+ if (brand == EPS_BRAND_C7M && set_max_voltage) {
+ u32 v;
+
+ /* Change mV to something hardware can use */
+ v = (set_max_voltage - 700) / 16;
+ /* Check if voltage is within limits */
+ if (v >= min_voltage && v <= max_voltage) {
+ printk(KERN_INFO "eps: Setting %dmV as maximum.\n",
+ v * 16 + 700);
+ max_voltage = v;
+ }
+ }
+
/* Calc number of p-states supported */
if (brand == EPS_BRAND_C7M)
states = max_multiplier - min_multiplier + 1;
@@ -265,6 +372,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Copy basic values */
centaur->fsb = fsb;
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+ centaur->bios_limit = limit;
+#endif
/* Fill frequency and MSR value table */
f_table = &centaur->freq_table[0];
@@ -303,17 +413,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
static int eps_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
- struct eps_cpu_data *centaur;
- u32 lo, hi;
- if (eps_cpu[cpu] == NULL)
- return -ENODEV;
- centaur = eps_cpu[cpu];
-
- /* Get max frequency */
- rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
- /* Set max frequency */
- eps_set_state(centaur, cpu, hi & 0xffff);
/* Bye */
cpufreq_frequency_table_put_attr(policy->cpu);
kfree(eps_cpu[cpu]);
@@ -359,6 +459,19 @@ static void __exit eps_exit(void)
cpufreq_unregister_driver(&eps_driver);
}
+/* Allow user to overclock his machine or to change frequency to higher after
+ * unloading module */
+module_param(freq_failsafe_off, int, 0644);
+MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
+module_param(voltage_failsafe_off, int, 0644);
+MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check");
+#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
+module_param(ignore_acpi_limit, int, 0644);
+MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit");
+#endif
+module_param(set_max_voltage, int, 0644);
+MODULE_PARM_DESC(set_max_voltage, "Set maximum CPU voltage (mV) C7-M only");
+
MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index b3379d6..2c6b671 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -25,41 +25,108 @@
static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier;
+static unsigned int param_busfreq = 0;
+static unsigned int param_max_multiplier = 0;
+
+module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO);
+MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)");
+
+module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO);
+MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz");
/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
static struct cpufreq_frequency_table clock_ratio[] = {
- {45, /* 000 -> 4.5x */ 0},
+ {60, /* 110 -> 6.0x */ 0},
+ {55, /* 011 -> 5.5x */ 0},
{50, /* 001 -> 5.0x */ 0},
+ {45, /* 000 -> 4.5x */ 0},
{40, /* 010 -> 4.0x */ 0},
- {55, /* 011 -> 5.5x */ 0},
- {20, /* 100 -> 2.0x */ 0},
- {30, /* 101 -> 3.0x */ 0},
- {60, /* 110 -> 6.0x */ 0},
{35, /* 111 -> 3.5x */ 0},
+ {30, /* 101 -> 3.0x */ 0},
+ {20, /* 100 -> 2.0x */ 0},
{0, CPUFREQ_TABLE_END}
};
+static const u8 index_to_register[8] = { 6, 3, 1, 0, 2, 7, 5, 4 };
+static const u8 register_to_index[8] = { 3, 2, 4, 1, 7, 6, 0, 5 };
+
+static const struct {
+ unsigned freq;
+ unsigned mult;
+} usual_frequency_table[] = {
+ { 400000, 40 }, // 100 * 4
+ { 450000, 45 }, // 100 * 4.5
+ { 475000, 50 }, // 95 * 5
+ { 500000, 50 }, // 100 * 5
+ { 506250, 45 }, // 112.5 * 4.5
+ { 533500, 55 }, // 97 * 5.5
+ { 550000, 55 }, // 100 * 5.5
+ { 562500, 50 }, // 112.5 * 5
+ { 570000, 60 }, // 95 * 6
+ { 600000, 60 }, // 100 * 6
+ { 618750, 55 }, // 112.5 * 5.5
+ { 660000, 55 }, // 120 * 5.5
+ { 675000, 60 }, // 112.5 * 6
+ { 720000, 60 }, // 120 * 6
+};
+
+#define FREQ_RANGE 3000
/**
* powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
*
- * Returns the current setting of the frequency multiplier. Core clock
+ * Returns the current setting of the frequency multiplier. Core clock
* speed is frequency of the Front-Side Bus multiplied with this value.
*/
static int powernow_k6_get_cpu_multiplier(void)
{
- u64 invalue = 0;
+ unsigned long invalue = 0;
u32 msrval;
+ local_irq_disable();
+
msrval = POWERNOW_IOPORT + 0x1;
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
invalue = inl(POWERNOW_IOPORT + 0x8);
msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
- return clock_ratio[(invalue >> 5)&7].index;
+ local_irq_enable();
+
+ return clock_ratio[register_to_index[(invalue >> 5)&7]].index;
}
+static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
+{
+ unsigned long outvalue, invalue;
+ unsigned long msrval;
+ unsigned long cr0;
+
+ /* we now need to transform best_i to the BVC format, see AMD#23446 */
+
+ /*
+ * The processor doesn't respond to inquiry cycles while changing the
+ * frequency, so we must disable cache.
+ */
+ local_irq_disable();
+ cr0 = read_cr0();
+ write_cr0(cr0 | X86_CR0_CD);
+ wbinvd();
+
+ outvalue = (1<<12) | (1<<10) | (1<<9) | (index_to_register[best_i]<<5);
+
+ msrval = POWERNOW_IOPORT + 0x1;
+ wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+ invalue = inl(POWERNOW_IOPORT + 0x8);
+ invalue = invalue & 0x1f;
+ outvalue = outvalue | invalue;
+ outl(outvalue, (POWERNOW_IOPORT + 0x8));
+ msrval = POWERNOW_IOPORT + 0x0;
+ wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+
+ write_cr0(cr0);
+ local_irq_enable();
+}
/**
* powernow_k6_set_state - set the PowerNow! multiplier
@@ -69,8 +136,6 @@ static int powernow_k6_get_cpu_multiplier(void)
*/
static void powernow_k6_set_state(unsigned int best_i)
{
- unsigned long outvalue = 0, invalue = 0;
- unsigned long msrval;
struct cpufreq_freqs freqs;
if (clock_ratio[best_i].index > max_multiplier) {
@@ -84,18 +149,7 @@ static void powernow_k6_set_state(unsigned int best_i)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- /* we now need to transform best_i to the BVC format, see AMD#23446 */
-
- outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
-
- msrval = POWERNOW_IOPORT + 0x1;
- wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
- invalue = inl(POWERNOW_IOPORT + 0x8);
- invalue = invalue & 0xf;
- outvalue = outvalue | invalue;
- outl(outvalue , (POWERNOW_IOPORT + 0x8));
- msrval = POWERNOW_IOPORT + 0x0;
- wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+ powernow_k6_set_cpu_multiplier(best_i);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -140,18 +194,57 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
return 0;
}
-
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{
unsigned int i, f;
int result;
+ unsigned khz;
if (policy->cpu != 0)
return -ENODEV;
- /* get frequencies */
- max_multiplier = powernow_k6_get_cpu_multiplier();
- busfreq = cpu_khz / max_multiplier;
+ max_multiplier = 0;
+ khz = cpu_khz;
+ for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) {
+ if (khz >= usual_frequency_table[i].freq - FREQ_RANGE &&
+ khz <= usual_frequency_table[i].freq + FREQ_RANGE) {
+ khz = usual_frequency_table[i].freq;
+ max_multiplier = usual_frequency_table[i].mult;
+ break;
+ }
+ }
+ if (param_max_multiplier) {
+ for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
+ if (clock_ratio[i].index == param_max_multiplier) {
+ max_multiplier = param_max_multiplier;
+ goto have_max_multiplier;
+ }
+ }
+ printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
+ return -EINVAL;
+ }
+
+ if (!max_multiplier) {
+ printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz);
+ printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n");
+ return -EOPNOTSUPP;
+ }
+
+have_max_multiplier:
+ param_max_multiplier = max_multiplier;
+
+ if (param_busfreq) {
+ if (param_busfreq >= 50000 && param_busfreq <= 150000) {
+ busfreq = param_busfreq / 10;
+ goto have_busfreq;
+ }
+ printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n");
+ return -EINVAL;
+ }
+
+ busfreq = khz / max_multiplier;
+have_busfreq:
+ param_busfreq = busfreq * 10;
/* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
@@ -163,7 +256,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
/* cpuinfo and default policy values */
- policy->cpuinfo.transition_latency = 200000;
+ policy->cpuinfo.transition_latency = 500000;
policy->cur = busfreq * max_multiplier;
result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index ad683ec..f6cd315 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/cpumask.h>
-#include <linux/sched.h> /* for current / set_cpus_allowed() */
#include <linux/io.h>
#include <linux/delay.h>
@@ -1132,16 +1131,23 @@ static int transition_frequency_pstate(struct powernow_k8_data *data,
return res;
}
-/* Driver entry point to switch to the target frequency */
-static int powernowk8_target(struct cpufreq_policy *pol,
- unsigned targfreq, unsigned relation)
+struct powernowk8_target_arg {
+ struct cpufreq_policy *pol;
+ unsigned targfreq;
+ unsigned relation;
+};
+
+static long powernowk8_target_fn(void *arg)
{
- cpumask_var_t oldmask;
+ struct powernowk8_target_arg *pta = arg;
+ struct cpufreq_policy *pol = pta->pol;
+ unsigned targfreq = pta->targfreq;
+ unsigned relation = pta->relation;
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
u32 checkfid;
u32 checkvid;
unsigned int newstate;
- int ret = -EIO;
+ int ret;
if (!data)
return -EINVAL;
@@ -1149,29 +1155,16 @@ static int powernowk8_target(struct cpufreq_policy *pol,
checkfid = data->currfid;
checkvid = data->currvid;
- /* only run on specific CPU from here on. */
- /* This is poor form: use a workqueue or smp_call_function_single */
- if (!alloc_cpumask_var(&oldmask, GFP_KERNEL))
- return -ENOMEM;
-
- cpumask_copy(oldmask, tsk_cpus_allowed(current));
- set_cpus_allowed_ptr(current, cpumask_of(pol->cpu));
-
- if (smp_processor_id() != pol->cpu) {
- printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
- goto err_out;
- }
-
if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing targ, change pending bit set\n");
- goto err_out;
+ return -EIO;
}
pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
pol->cpu, targfreq, pol->min, pol->max, relation);
if (query_current_values_with_pending_wait(data))
- goto err_out;
+ return -EIO;
if (cpu_family != CPU_HW_PSTATE) {
pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
@@ -1189,7 +1182,7 @@ static int powernowk8_target(struct cpufreq_policy *pol,
if (cpufreq_frequency_table_target(pol, data->powernow_table,
targfreq, relation, &newstate))
- goto err_out;
+ return -EIO;
mutex_lock(&fidvid_mutex);
@@ -1202,9 +1195,8 @@ static int powernowk8_target(struct cpufreq_policy *pol,
ret = transition_frequency_fidvid(data, newstate);
if (ret) {
printk(KERN_ERR PFX "transition frequency failed\n");
- ret = 1;
mutex_unlock(&fidvid_mutex);
- goto err_out;
+ return 1;
}
mutex_unlock(&fidvid_mutex);
@@ -1213,12 +1205,18 @@ static int powernowk8_target(struct cpufreq_policy *pol,
data->powernow_table[newstate].index);
else
pol->cur = find_khz_freq_from_fid(data->currfid);
- ret = 0;
-err_out:
- set_cpus_allowed_ptr(current, oldmask);
- free_cpumask_var(oldmask);
- return ret;
+ return 0;
+}
+
+/* Driver entry point to switch to the target frequency */
+static int powernowk8_target(struct cpufreq_policy *pol,
+ unsigned targfreq, unsigned relation)
+{
+ struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq,
+ .relation = relation };
+
+ return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
}
/* Driver entry point to verify the policy and range of frequencies */
diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c
index 8af2d2f..2c0345a 100644
--- a/drivers/cpufreq/speedstep-lib.c
+++ b/drivers/cpufreq/speedstep-lib.c
@@ -399,6 +399,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
pr_debug("previous speed is %u\n", prev_speed);
+ preempt_disable();
local_irq_save(flags);
/* switch to low state */
@@ -463,6 +464,8 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
out:
local_irq_restore(flags);
+ preempt_enable();
+
return ret;
}
EXPORT_SYMBOL_GPL(speedstep_get_freqs);
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index c76ead3..8a97f94 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -187,6 +187,7 @@ static void speedstep_set_state(unsigned int state)
return;
/* Disable IRQs */
+ preempt_disable();
local_irq_save(flags);
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
@@ -197,9 +198,19 @@ static void speedstep_set_state(unsigned int state)
do {
if (retry) {
+ /*
+ * We need to enable interrupts, otherwise the blockage
+ * won't resolve.
+ *
+ * We disable preemption so that other processes don't
+ * run. If other processes were running, they could
+ * submit more DMA requests, making the blockage worse.
+ */
pr_debug("retry %u, previous result %u, waiting...\n",
retry, result);
+ local_irq_enable();
mdelay(retry * 50);
+ local_irq_disable();
}
retry++;
__asm__ __volatile__(
@@ -216,6 +227,7 @@ static void speedstep_set_state(unsigned int state)
/* enable IRQs */
local_irq_restore(flags);
+ preempt_enable();
if (new_state == state)
pr_debug("change to %u MHz succeeded after %u tries "
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 40b6342..7e3002b 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -201,6 +201,7 @@ config CRYPTO_DEV_HIFN_795X
select CRYPTO_BLKCIPHER
select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG
depends on PCI
+ depends on !ARCH_DMA_ADDR_T_64BIT
help
This option allows you to have support for HIFN 795x crypto adapters.
@@ -267,7 +268,7 @@ config CRYPTO_DEV_OMAP_AES
config CRYPTO_DEV_PICOXCELL
tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
- depends on ARCH_PICOXCELL
+ depends on ARCH_PICOXCELL && HAVE_CLK
select CRYPTO_AES
select CRYPTO_AUTHENC
select CRYPTO_ALGAPI
@@ -293,59 +294,4 @@ config CRYPTO_DEV_S5P
Select this to offload Samsung S5PV210 or S5PC110 from AES
algorithms execution.
-config CRYPTO_S5P_DEV_ACE
- tristate "Support for Samsung ACE (Advanced Crypto Engine)"
- depends on ARCH_EXYNOS4 || ARCH_EXYNOS5 || ARCH_S5PV210
- select S5P_DEV_ACE
- select CRYPTO_ALGAPI
- help
- Use ACE for AES (ECB, CBC, CTR) and SHA1/SHA256.
- Available in EXYNOS4/S5PV210/S5PC110 and newer CPUs.
-
-config ACE_BC
- bool "Support for AES block cipher (ECB, CBC, CTR mode)"
- depends on CRYPTO_S5P_DEV_ACE
- select CRYPTO_AES
- select CRYPTO_BLKCIPHER
- select CRYPTO_ECB
- select CRYPTO_CTR
- select CRYPTO_CBC
- default y
- help
- Use ACE for ACE (ECB, CBC, CTR) for Samsung Hardware Crypto engine.
-
-config ACE_BC_ASYNC
- bool "Support for AES async mode"
- default y
- depends on ACE_BC
-
-config ACE_BC_IRQMODE
- bool "Support for AES IRQ mode"
- default n
- depends on ACE_BC_ASYNC
-
-config ACE_HASH_SHA1
- bool "Support for SHA1 hash algorithm"
- depends on CRYPTO_S5P_DEV_ACE
- select CRYPTO_HASH
- select CRYPTO_SHA1
- default y
- help
- Use SHA1 hash algorithm for Samsung Hardware Crypto engine
-
-config ACE_HASH_SHA256
- bool "Support for SHA256 hash algorithm"
- depends on CRYPTO_S5P_DEV_ACE && !ARCH_S5PV210
- select CRYPTO_HASH
- select CRYPTO_SHA256
- default y
- help
- Use SHA256 hash algorithm for Samsung Hardware Crypto engine
-
-config ACE_DEBUG
- bool "Debug message for crypto driver"
- depends on CRYPTO_S5P_DEV_ACE
- help
- This option allows you to check the debug print message for crypto driver.
-
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 4fe1e44..53ea501 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -13,4 +13,3 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
-obj-$(CONFIG_CRYPTO_S5P_DEV_ACE) += ace.o
diff --git a/drivers/crypto/ace.c b/drivers/crypto/ace.c
deleted file mode 100644
index 21ddf96..0000000
--- a/drivers/crypto/ace.c
+++ /dev/null
@@ -1,2651 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for ACE (Advanced Crypto Engine) for S5PV210/EXYNOS4210.
- *
- * Copyright (c) 2011 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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/err.h>
-#include <linux/scatterlist.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/memory.h>
-#include <linux/delay.h>
-#include <linux/version.h>
-#include <linux/hrtimer.h>
-
-#include <asm/cacheflush.h>
-
-#include <crypto/aes.h>
-#include <crypto/internal/hash.h>
-#include <crypto/sha.h>
-#include <crypto/scatterwalk.h>
-
-#include <mach/secmem.h>
-
-#include "ace.h"
-#include "ace_sfr.h"
-
-#define S5P_ACE_DRIVER_NAME "s5p-ace"
-#define ACE_AES_MIN_BLOCK_SIZE 16
-
-#undef ACE_USE_ACP
-#ifdef ACE_USE_ACP
-#define PA_SSS_USER_CON 0x10010344
-#define ACE_ARCACHE 0xA
-#define ACE_AWCACHE 0xA
-#endif
-
-#undef ACE_DEBUG_HEARTBEAT
-#undef ACE_DEBUG_WATCHDOG
-
-#ifdef CONFIG_ACE_DEBUG
-#define S5P_ACE_DEBUG(args...) printk(KERN_INFO args)
-#else
-#define S5P_ACE_DEBUG(args...)
-#endif
-
-#define s5p_ace_read_sfr(_sfr_) __raw_readl(s5p_ace_dev.ace_base + (_sfr_))
-#define s5p_ace_write_sfr(_sfr_, _val_) __raw_writel((_val_), s5p_ace_dev.ace_base + (_sfr_))
-
-enum s5p_cpu_type {
- TYPE_S5PV210,
- TYPE_EXYNOS,
-};
-
-enum {
- FLAGS_BC_BUSY,
- FLAGS_HASH_BUSY,
- FLAGS_SUSPENDED,
- FLAGS_USE_SW
-};
-
-static struct s5p_ace_device s5p_ace_dev;
-
-#ifdef CONFIG_ACE_BC_ASYNC
-static void s5p_ace_bc_task(unsigned long data);
-#endif
-
-#define ACE_CLOCK_ON 0
-#define ACE_CLOCK_OFF 1
-
-static int count_clk;
-static int count_clk_delta;
-
-static int count_use_sw;
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
-#define ACE_HEARTBEAT_MS 10000
-#define ACE_WATCHDOG_MS 500
-
-struct timeval timestamp_base;
-struct timeval timestamp[5];
-
-static inline void s5p_ace_dump(void)
-{
- int i;
- char *str[] = {"request: ", "dma start: ", "dma end: ", "suspend: ", "resume: "};
-
- for (i = 0; i < 5; i++)
- printk(KERN_INFO "%s%5lu.%06lu\n",
- str[i], timestamp[i].tv_sec - timestamp_base.tv_sec, timestamp[i].tv_usec);
- printk(KERN_INFO "clock: [%d - %d]\n", count_clk, count_clk_delta);
-}
-#endif
-
-struct s5p_ace_reqctx {
- u32 mode;
-};
-
-struct s5p_ace_device {
- void __iomem *ace_base;
- struct clk *clock;
-#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
- int irq;
-#endif
-#ifdef ACE_USE_ACP
- void __iomem *sss_usercon;
-#endif
- spinlock_t lock;
- unsigned long flags;
-
- struct hrtimer timer;
- struct work_struct work;
-#ifdef ACE_DEBUG_HEARTBEAT
- struct hrtimer heartbeat;
-#endif
-#ifdef ACE_DEBUG_WATCHDOG
- struct hrtimer watchdog_bc;
-#endif
-
-#ifdef CONFIG_ACE_BC_ASYNC
- struct crypto_queue queue_bc;
- struct tasklet_struct task_bc;
- int rc_depth_bc;
-#endif
-
- struct s5p_ace_aes_ctx *ctx_bc;
-
-#ifdef CONFIG_ACE_HASH_ASYNC
- struct crypto_queue queue_hash;
- struct tasklet_struct task_hash;
-#endif
- enum s5p_cpu_type cputype;
-};
-
-#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
-struct crypto_shash *sw_tfm;
-struct crypto_hash **fallback_hash;
-#endif
-struct secmem_crypto_driver_ftn secmem_ftn;
-
-static void s5p_ace_init_clock_gating(void)
-{
- count_clk = 0;
- count_clk_delta = 0;
-}
-
-static void s5p_ace_deferred_clock_disable(struct work_struct *work)
-{
- unsigned long flags;
- int tmp;
-
- if (count_clk_delta == 0)
- return;
-
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- count_clk -= count_clk_delta;
- count_clk_delta = 0;
- tmp = count_clk;
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- if (tmp == 0) {
- clk_disable(s5p_ace_dev.clock);
- S5P_ACE_DEBUG("ACE clock OFF\n");
- }
-}
-
-static enum hrtimer_restart s5p_ace_timer_func(struct hrtimer *timer)
-{
- S5P_ACE_DEBUG("ACE HRTIMER\n");
-
- /* It seems that "schedule_work" is expensive. */
- schedule_work(&s5p_ace_dev.work);
-
- return HRTIMER_NORESTART;
-}
-
-static void s5p_ace_clock_gating(int status)
-{
- unsigned long flags;
- int tmp;
-
- if (status == ACE_CLOCK_ON) {
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- tmp = count_clk++;
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- if (tmp == 0) {
- clk_enable(s5p_ace_dev.clock);
- S5P_ACE_DEBUG("ACE clock ON\n");
- }
- } else if (status == ACE_CLOCK_OFF) {
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- if (count_clk > 1)
- count_clk--;
- else
- count_clk_delta++;
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- hrtimer_start(&s5p_ace_dev.timer,
- ns_to_ktime((u64)500 * NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
- }
-}
-
-struct s5p_ace_aes_ctx {
- u32 keylen;
-
- u32 sfr_ctrl;
- u8 sfr_key[AES_MAX_KEY_SIZE];
- u8 sfr_semikey[AES_BLOCK_SIZE];
-
- struct crypto_blkcipher *fallback_bc;
-#ifdef CONFIG_ACE_BC_ASYNC
- struct ablkcipher_request *req;
- struct crypto_ablkcipher *fallback_abc;
- struct crypto_tfm *origin_tfm;
-#else
- struct crypto_blkcipher *origin_tfm;
-
-#endif
- size_t total;
- struct scatterlist *in_sg;
- size_t in_ofs;
- struct scatterlist *out_sg;
- size_t out_ofs;
-
- int directcall;
-
- u8 *src_addr;
- u8 *dst_addr;
- u32 dma_size;
- u8 tbuf[AES_BLOCK_SIZE];
-};
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
-static void s5p_ace_print_info(void)
-{
- struct s5p_ace_aes_ctx *sctx = s5p_ace_dev.ctx_bc;
-
- printk(KERN_INFO "flags: 0x%X\n", (u32)s5p_ace_dev.flags);
- s5p_ace_dump();
- if (sctx == NULL) {
- printk(KERN_INFO "sctx == NULL\n");
- } else {
-#ifdef CONFIG_ACE_BC_ASYNC
- printk(KERN_INFO "sctx->req: 0x%08X\n", (u32)sctx->req);
-#endif
- printk(KERN_INFO "sctx->total: 0x%08X\n", sctx->total);
- printk(KERN_INFO "sctx->dma_size: 0x%08X\n", sctx->dma_size);
- }
-}
-#endif
-
-#ifdef ACE_DEBUG_HEARTBEAT
-static enum hrtimer_restart s5p_ace_heartbeat_func(struct hrtimer *timer)
-{
- printk(KERN_INFO "[[ACE HEARTBEAT]] -- START ----------\n");
-
- s5p_ace_print_info();
-
- printk(KERN_INFO "[[ACE HEARTBEAT]] -- END ------------\n");
-
- hrtimer_start(&s5p_ace_dev.heartbeat,
- ns_to_ktime((u64)ACE_HEARTBEAT_MS * NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
-
- return HRTIMER_NORESTART;
-}
-#endif
-
-#ifdef ACE_DEBUG_WATCHDOG
-static enum hrtimer_restart s5p_ace_watchdog_bc_func(struct hrtimer *timer)
-{
- printk(KERN_ERR "[[ACE WATCHDOG BC]] ============\n");
-
- s5p_ace_print_info();
-
- return HRTIMER_NORESTART;
-}
-#endif
-
-static void s5p_ace_resume_device(struct s5p_ace_device *dev)
-{
- if (test_and_clear_bit(FLAGS_SUSPENDED, &dev->flags)) {
- clear_bit(FLAGS_BC_BUSY, &dev->flags);
- clear_bit(FLAGS_HASH_BUSY, &dev->flags);
-
-#ifdef ACE_USE_ACP
- /* Set ARUSER[12:8] and AWUSER[4:0] */
- writel(0x101, dev->sss_usercon
- + (PA_SSS_USER_CON & (PAGE_SIZE - 1)));
-#endif
- }
-}
-
-#if defined(CONFIG_ACE_BC)
-static int s5p_ace_aes_set_cipher(struct s5p_ace_aes_ctx *sctx,
- u32 alg_id, u32 key_size)
-{
- u32 new_status = 0;
-
- /* Fixed setting */
- new_status |= ACE_AES_FIFO_ON;
-
- if (s5p_ace_dev.cputype == TYPE_S5PV210)
- new_status |= ACE_AES_KEYCNGMODE_ON;
-
- new_status |= ACE_AES_SWAPKEY_ON;
- new_status |= ACE_AES_SWAPCNT_ON;
- new_status |= ACE_AES_SWAPIV_ON;
-
- if (s5p_ace_dev.cputype == TYPE_EXYNOS) {
- new_status |= ACE_AES_SWAPDO_ON;
- new_status |= ACE_AES_SWAPDI_ON;
- new_status |= ACE_AES_COUNTERSIZE_128;
- }
-
- switch (MI_GET_MODE(alg_id)) {
- case _MODE_ECB_:
- new_status |= ACE_AES_OPERMODE_ECB;
- break;
- case _MODE_CBC_:
- new_status |= ACE_AES_OPERMODE_CBC;
- break;
- case _MODE_CTR_:
- new_status |= ACE_AES_OPERMODE_CTR;
- break;
- default:
- return -EINVAL;
- }
-
- switch (key_size) {
- case 128:
- new_status |= ACE_AES_KEYSIZE_128;
- break;
- case 192:
- new_status |= ACE_AES_KEYSIZE_192;
- break;
- case 256:
- new_status |= ACE_AES_KEYSIZE_256;
- break;
- default:
- return -EINVAL;
- }
-
- /* Set AES context */
- sctx->sfr_ctrl = new_status;
- sctx->keylen = key_size >> 3;
-
- return 0;
-}
-
-/*
- * enc: BC_MODE_ENC - encryption, BC_MODE_DEC - decryption
- */
-static int s5p_ace_aes_set_encmode(struct s5p_ace_aes_ctx *sctx, u32 enc)
-{
- u32 status = sctx->sfr_ctrl;
- u32 enc_mode = ACE_AES_MODE_ENC;
-
- if ((status & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_CTR)
- enc_mode = (enc == BC_MODE_ENC ?
- ACE_AES_MODE_ENC : ACE_AES_MODE_DEC);
-
- sctx->sfr_ctrl = (status & ~ACE_AES_MODE_MASK) | enc_mode;
-
- return 0;
-}
-
-static int s5p_ace_aes_update_semikey(struct s5p_ace_aes_ctx *sctx,
- u8 *in, u8 *out, u32 len)
-{
- u32 *addr = (u32 *)sctx->sfr_semikey;
- u32 tmp1, tmp2;
-
- switch (sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) {
- case ACE_AES_OPERMODE_ECB:
- break;
- case ACE_AES_OPERMODE_CBC:
- if ((sctx->sfr_ctrl & ACE_AES_MODE_MASK) == ACE_AES_MODE_ENC)
- memcpy(sctx->sfr_semikey, out, AES_BLOCK_SIZE);
- else
- memcpy(sctx->sfr_semikey, in, AES_BLOCK_SIZE);
- break;
- case ACE_AES_OPERMODE_CTR:
- tmp1 = be32_to_cpu(addr[3]);
- tmp2 = tmp1 + (len >> 4);
- addr[3] = be32_to_cpu(tmp2);
- if (tmp2 < tmp1) {
- tmp1 = be32_to_cpu(addr[2]) + 1;
- addr[2] = be32_to_cpu(tmp1);
- if (addr[2] == 0) {
- tmp1 = be32_to_cpu(addr[1]) + 1;
- addr[1] = be32_to_cpu(tmp1);
- if (addr[1] == 0) {
- tmp1 = be32_to_cpu(addr[0]) + 1;
- addr[0] = be32_to_cpu(tmp1);
- }
- }
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s5p_ace_aes_write_sfr(struct s5p_ace_aes_ctx *sctx)
-{
- u32 *addr;
-
- s5p_ace_write_sfr(ACE_AES_CONTROL, sctx->sfr_ctrl);
-
- addr = (u32 *)sctx->sfr_key;
- switch (sctx->keylen) {
- case 16:
- s5p_ace_write_sfr(ACE_AES_KEY5, addr[0]);
- s5p_ace_write_sfr(ACE_AES_KEY6, addr[1]);
- s5p_ace_write_sfr(ACE_AES_KEY7, addr[2]);
- s5p_ace_write_sfr(ACE_AES_KEY8, addr[3]);
- break;
- case 24:
- s5p_ace_write_sfr(ACE_AES_KEY3, addr[0]);
- s5p_ace_write_sfr(ACE_AES_KEY4, addr[1]);
- s5p_ace_write_sfr(ACE_AES_KEY5, addr[2]);
- s5p_ace_write_sfr(ACE_AES_KEY6, addr[3]);
- s5p_ace_write_sfr(ACE_AES_KEY7, addr[4]);
- s5p_ace_write_sfr(ACE_AES_KEY8, addr[5]);
- break;
- case 32:
- s5p_ace_write_sfr(ACE_AES_KEY1, addr[0]);
- s5p_ace_write_sfr(ACE_AES_KEY2, addr[1]);
- s5p_ace_write_sfr(ACE_AES_KEY3, addr[2]);
- s5p_ace_write_sfr(ACE_AES_KEY4, addr[3]);
- s5p_ace_write_sfr(ACE_AES_KEY5, addr[4]);
- s5p_ace_write_sfr(ACE_AES_KEY6, addr[5]);
- s5p_ace_write_sfr(ACE_AES_KEY7, addr[6]);
- s5p_ace_write_sfr(ACE_AES_KEY8, addr[7]);
- break;
- default:
- return -EINVAL;
- }
-
- addr = (u32 *)sctx->sfr_semikey;
- switch (sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) {
- case ACE_AES_OPERMODE_ECB:
- break;
- case ACE_AES_OPERMODE_CBC:
- s5p_ace_write_sfr(ACE_AES_IV1, addr[0]);
- s5p_ace_write_sfr(ACE_AES_IV2, addr[1]);
- s5p_ace_write_sfr(ACE_AES_IV3, addr[2]);
- s5p_ace_write_sfr(ACE_AES_IV4, addr[3]);
- break;
- case ACE_AES_OPERMODE_CTR:
- s5p_ace_write_sfr(ACE_AES_CNT1, addr[0]);
- s5p_ace_write_sfr(ACE_AES_CNT2, addr[1]);
- s5p_ace_write_sfr(ACE_AES_CNT3, addr[2]);
- s5p_ace_write_sfr(ACE_AES_CNT4, addr[3]);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int s5p_ace_aes_engine_start(struct s5p_ace_aes_ctx *sctx,
- u8 *out, const u8 *in, u32 len, int irqen)
-{
- u32 reg;
- u32 first_blklen;
-
- if ((sctx == NULL) || (out == NULL) || (in == NULL)) {
- printk(KERN_ERR "%s : NULL input.\n", __func__);
- return -EINVAL;
- }
-
- if (len & (AES_BLOCK_SIZE - 1)) {
- printk(KERN_ERR "Invalid len for AES engine (%d)\n", len);
- return -EINVAL;
- }
-
- if (s5p_ace_aes_write_sfr(sctx) != 0)
- return -EINVAL;
-
- S5P_ACE_DEBUG("AES: %s, in: 0x%08X, out: 0x%08X, len: 0x%08X\n",
- __func__, (u32)in, (u32)out, len);
- S5P_ACE_DEBUG("AES: %s, AES_control : 0x%08X\n",
- __func__, s5p_ace_read_sfr(ACE_AES_CONTROL));
-
- /* Assert code */
- reg = s5p_ace_read_sfr(ACE_AES_STATUS);
- if ((reg & ACE_AES_BUSY_MASK) == ACE_AES_BUSY_ON)
- return -EBUSY;
-
- /* Flush BRDMA and BTDMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAC, ACE_FC_BRDMACFLUSH_ON);
- s5p_ace_write_sfr(ACE_FC_BTDMAC, ACE_FC_BTDMACFLUSH_ON);
-
- /* Select Input MUX as AES */
- reg = s5p_ace_read_sfr(ACE_FC_FIFOCTRL);
- reg = (reg & ~ACE_FC_SELBC_MASK) | ACE_FC_SELBC_AES;
- s5p_ace_write_sfr(ACE_FC_FIFOCTRL, reg);
-
- /* Stop flushing BRDMA and BTDMA */
- reg = ACE_FC_BRDMACFLUSH_OFF;
- if (s5p_ace_dev.cputype == TYPE_S5PV210)
- reg |= ACE_FC_BRDMACSWAP_ON;
-
-#ifdef ACE_USE_ACP
- reg |= ACE_ARCACHE << ACE_FC_BRDMACARCACHE_OFS;
-#endif
- s5p_ace_write_sfr(ACE_FC_BRDMAC, reg);
- reg = ACE_FC_BTDMACFLUSH_OFF;
- if (s5p_ace_dev.cputype == TYPE_S5PV210)
- reg |= ACE_FC_BTDMACSWAP_ON;
-
-#ifdef ACE_USE_ACP
- reg |= ACE_AWCACHE << ACE_FC_BTDMACAWCACHE_OFS;
-#endif
- s5p_ace_write_sfr(ACE_FC_BTDMAC, reg);
-
- /* Set DMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAS, (u32)in);
- s5p_ace_write_sfr(ACE_FC_BTDMAS, (u32)out);
-
- if (s5p_ace_dev.cputype == TYPE_S5PV210) {
- /* Set the length of first block (Key Change Mode On) */
- if ((((u32)in) & (2 * AES_BLOCK_SIZE - 1)) == 0)
- first_blklen = 2 * AES_BLOCK_SIZE;
- else
- first_blklen = AES_BLOCK_SIZE;
-
- if (len <= first_blklen) {
-#ifdef CONFIG_ACE_BC_IRQMODE
- if (irqen)
- s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
-#endif
-
- /* Set DMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAL, len);
- s5p_ace_write_sfr(ACE_FC_BTDMAL, len);
- } else {
- unsigned long timeout;
-
- /* Set DMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAL, first_blklen);
- s5p_ace_write_sfr(ACE_FC_BTDMAL, first_blklen);
-
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)
- break;
- }
- if (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)) {
- printk(KERN_ERR "AES : DMA time out\n");
- return -EBUSY;
- }
- s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_BTDMA | ACE_FC_BRDMA);
-
- reg = sctx->sfr_ctrl;
- reg = (reg & ~ACE_AES_KEYCNGMODE_MASK) | ACE_AES_KEYCNGMODE_OFF;
- s5p_ace_write_sfr(ACE_AES_CONTROL, reg);
-
-#ifdef CONFIG_ACE_BC_IRQMODE
- if (irqen)
- s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
-#endif
-
- /* Set DMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAL, len - first_blklen);
- s5p_ace_write_sfr(ACE_FC_BTDMAL, len - first_blklen);
- }
- } else {
-#ifdef CONFIG_ACE_BC_IRQMODE
- if (irqen)
- s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
-#endif
-
- /* Set DMA */
- s5p_ace_write_sfr(ACE_FC_BRDMAL, len);
- s5p_ace_write_sfr(ACE_FC_BTDMAL, len);
- }
-
- return 0;
-}
-
-static void s5p_ace_aes_engine_wait(struct s5p_ace_aes_ctx *sctx,
- u8 *out, const u8 *in, u32 len)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout))
- if (s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)
- break;
- if (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA))
- printk(KERN_ERR "%s : DMA time out\n", __func__);
- s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_BTDMA | ACE_FC_BRDMA);
-}
-
-void s5p_ace_sg_update(struct scatterlist **sg, size_t *offset,
- size_t count)
-{
- *offset += count;
- if (*offset >= sg_dma_len(*sg)) {
- *offset -= sg_dma_len(*sg);
- *sg = scatterwalk_sg_next(*sg);
- }
-}
-
-int s5p_ace_sg_set_from_sg(struct scatterlist *dst, struct scatterlist *src,
- u32 num)
-{
- sg_init_table(dst, num);
- while (num--) {
- sg_set_page(dst, sg_page(src), sg_dma_len(src), src->offset);
-
- dst++;
- src = scatterwalk_sg_next(src);
- if (!src)
- return -ENOMEM;
- }
- return 0;
-}
-
-/* Unaligned data Handling
- * - size should be a multiple of ACE_AES_MIN_BLOCK_SIZE.
- */
-static int s5p_ace_aes_crypt_unaligned(struct s5p_ace_aes_ctx *sctx,
- size_t size)
-{
- struct blkcipher_desc desc;
- struct scatterlist in_sg[2], out_sg[2];
- int ret;
-
- S5P_ACE_DEBUG("%s - %s (size: %d / %d)\n", __func__,
- sctx->fallback_bc->base.__crt_alg->cra_driver_name,
- size, sctx->total);
-
- desc.tfm = sctx->fallback_bc;
- desc.info = sctx->sfr_semikey;
- desc.flags = 0;
-
- s5p_ace_sg_set_from_sg(in_sg, sctx->in_sg, 2);
- in_sg->length -= sctx->in_ofs;
- in_sg->offset += sctx->in_ofs;
-
- s5p_ace_sg_set_from_sg(out_sg, sctx->out_sg, 2);
- out_sg->length -= sctx->out_ofs;
- out_sg->offset += sctx->out_ofs;
-
- if ((sctx->sfr_ctrl & ACE_AES_MODE_MASK) == ACE_AES_MODE_ENC)
- ret = crypto_blkcipher_encrypt_iv(
- &desc, out_sg, in_sg, size);
- else
- ret = crypto_blkcipher_decrypt_iv(
- &desc, out_sg, in_sg, size);
-
- sctx->dma_size = 0;
- sctx->total -= size;
- if (!sctx->total)
- return 0;
-
- s5p_ace_sg_update(&sctx->in_sg, &sctx->in_ofs, size);
- s5p_ace_sg_update(&sctx->out_sg, &sctx->out_ofs, size);
-
- return 0;
-}
-
-static int s5p_ace_aes_crypt_dma_start(struct s5p_ace_device *dev)
-{
- struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
- u8 *src, *dst;
- size_t count;
- int i;
- int ret;
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[1]); /* 1: dma start */
-#endif
-
- sctx->directcall = 0;
-
- while (1) {
- count = sctx->total;
- count = min(count, sg_dma_len(sctx->in_sg) - sctx->in_ofs);
- count = min(count, sg_dma_len(sctx->out_sg) - sctx->out_ofs);
-
- S5P_ACE_DEBUG("total_start: %d (%d)\n", sctx->total, count);
- S5P_ACE_DEBUG(" in(ofs: %x, len: %x), %x\n",
- sctx->in_sg->offset, sg_dma_len(sctx->in_sg),
- sctx->in_ofs);
- S5P_ACE_DEBUG(" out(ofs: %x, len: %x), %x\n",
- sctx->out_sg->offset, sg_dma_len(sctx->out_sg),
- sctx->out_ofs);
-
- if (count > ACE_AES_MIN_BLOCK_SIZE)
- break;
-
- count = min(sctx->total, (size_t)ACE_AES_MIN_BLOCK_SIZE);
- if (count & (AES_BLOCK_SIZE - 1))
- printk(KERN_ERR "%s - Invalid count\n", __func__);
- ret = s5p_ace_aes_crypt_unaligned(sctx, count);
- if (!sctx->total) {
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[2]); /* 2: dma end */
-#endif
-#ifdef CONFIG_ACE_BC_IRQMODE
- tasklet_schedule(&dev->task_bc);
- return 0;
-#else
- goto run;
-#endif
- }
- }
-
- count &= ~(AES_BLOCK_SIZE - 1);
- sctx->dma_size = count;
-
- src = (u8 *)page_to_phys(sg_page(sctx->in_sg));
- src += sctx->in_sg->offset + sctx->in_ofs;
- if (!PageHighMem(sg_page(sctx->in_sg))) {
- sctx->src_addr = (u8 *)phys_to_virt((u32)src);
- } else {
- sctx->src_addr = crypto_kmap(sg_page(sctx->in_sg),
- crypto_kmap_type(0));
- sctx->src_addr += sctx->in_sg->offset + sctx->in_ofs;
- }
-
- dst = (u8 *)page_to_phys(sg_page(sctx->out_sg));
- dst += sctx->out_sg->offset + sctx->out_ofs;
- if (!PageHighMem(sg_page(sctx->out_sg))) {
- sctx->dst_addr = (u8 *)phys_to_virt((u32)dst);
- } else {
- sctx->dst_addr = crypto_kmap(sg_page(sctx->out_sg),
- crypto_kmap_type(1));
- sctx->dst_addr += sctx->out_sg->offset + sctx->out_ofs;
- }
-
- S5P_ACE_DEBUG(" phys(src: %x, dst: %x)\n", (u32)src, (u32)dst);
- S5P_ACE_DEBUG(" virt(src: %x, dst: %x)\n",
- (u32)sctx->src_addr, (u32)sctx->dst_addr);
-
- if (src == dst)
- memcpy(sctx->tbuf, sctx->src_addr + count - AES_BLOCK_SIZE,
- AES_BLOCK_SIZE);
-
-#ifndef ACE_USE_ACP
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- dmac_clean_range((void *)sctx->src_addr,
- (void *)sctx->src_addr + count);
- dmac_clean_range((void *)sctx->dst_addr,
- (void *)sctx->dst_addr + count);
-#else
- dmac_map_area((void *)sctx->src_addr, count, DMA_TO_DEVICE);
- outer_clean_range((unsigned long)src, (unsigned long)src + count);
- dmac_map_area((void *)sctx->dst_addr, count, DMA_FROM_DEVICE);
- outer_clean_range((unsigned long)dst, (unsigned long)dst + count);
-#endif
-#endif
-
- for (i = 0; i < 100; i++) {
- ret = s5p_ace_aes_engine_start(sctx, dst, src, count, 1);
- if (ret != -EBUSY)
- break;
- }
- if (i == 100) {
- printk(KERN_ERR "%s : DMA Start Failed\n", __func__);
- return ret;
- }
-
-run:
-#ifdef CONFIG_ACE_BC_ASYNC
-#ifndef CONFIG_ACE_BC_IRQMODE
- if (!ret) {
- if ((count <= 2048) && ((s5p_ace_dev.rc_depth_bc++) < 1)) {
- sctx->directcall = 1;
- s5p_ace_bc_task((unsigned long)&s5p_ace_dev);
- return ret;
- }
- }
-#endif
-
- if (sctx->dma_size) {
- if (PageHighMem(sg_page(sctx->in_sg)))
- crypto_kunmap(sctx->src_addr, crypto_kmap_type(0));
- if (PageHighMem(sg_page(sctx->out_sg)))
- crypto_kunmap(sctx->dst_addr, crypto_kmap_type(1));
- }
-
-#ifndef CONFIG_ACE_BC_IRQMODE
- if (!ret)
- tasklet_schedule(&dev->task_bc);
-#endif
-#endif
- return ret;
-}
-
-static int s5p_ace_aes_crypt_dma_wait(struct s5p_ace_device *dev)
-{
- struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
- u8 *src, *dst;
- u8 *src_lb_addr;
- u32 lastblock;
- int ret = 0;
-
- S5P_ACE_DEBUG("%s\n", __func__);
-
- src = (u8 *)page_to_phys(sg_page(sctx->in_sg));
- src += sctx->in_sg->offset + sctx->in_ofs;
- dst = (u8 *)page_to_phys(sg_page(sctx->out_sg));
- dst += sctx->out_sg->offset + sctx->out_ofs;
-
-#ifdef CONFIG_ACE_BC_ASYNC
- if (!sctx->directcall) {
- if (PageHighMem(sg_page(sctx->in_sg))) {
- sctx->src_addr = crypto_kmap(sg_page(sctx->in_sg),
- crypto_kmap_type(0));
- sctx->src_addr += sctx->in_sg->offset + sctx->in_ofs;
- }
-
- if (PageHighMem(sg_page(sctx->out_sg))) {
- sctx->dst_addr = crypto_kmap(sg_page(sctx->out_sg),
- crypto_kmap_type(1));
- sctx->dst_addr += sctx->out_sg->offset + sctx->out_ofs;
- }
- }
-#endif
-
-#ifndef CONFIG_ACE_BC_IRQMODE
- s5p_ace_aes_engine_wait(sctx, dst, src, sctx->dma_size);
-#endif
-
-#ifndef ACE_USE_ACP
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- dmac_inv_range((void *)sctx->dst_addr,
- (void *)sctx->dst_addr + sctx->dma_size);
-#else
- dmac_unmap_area((void *)sctx->dst_addr, sctx->dma_size,
- DMA_FROM_DEVICE);
- outer_inv_range((unsigned long)dst,
- (unsigned long)dst + sctx->dma_size);
-#endif
-#endif
-
- lastblock = sctx->dma_size - AES_BLOCK_SIZE;
- if (src == dst)
- src_lb_addr = sctx->tbuf;
- else
- src_lb_addr = sctx->src_addr + lastblock;
- if (s5p_ace_aes_update_semikey(sctx, src_lb_addr,
- sctx->dst_addr + lastblock,
- sctx->dma_size) != 0)
- return -EINVAL;
-
- if (PageHighMem(sg_page(sctx->in_sg)))
- crypto_kunmap(sctx->src_addr, crypto_kmap_type(0));
- if (PageHighMem(sg_page(sctx->out_sg)))
- crypto_kunmap(sctx->dst_addr, crypto_kmap_type(1));
-
- sctx->total -= sctx->dma_size;
-
- S5P_ACE_DEBUG("total_end: %d\n", sctx->total);
-
- if (ret || !sctx->total) {
- if (ret)
- printk(KERN_NOTICE "err: %d\n", ret);
- } else {
- s5p_ace_sg_update(&sctx->in_sg, &sctx->in_ofs,
- sctx->dma_size);
- s5p_ace_sg_update(&sctx->out_sg, &sctx->out_ofs,
- sctx->dma_size);
- }
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[2]); /* 2: dma end */
-#endif
-
- return ret;
-}
-
-#ifdef CONFIG_ACE_BC_ASYNC
-static int s5p_ace_handle_lock_req(struct s5p_ace_device *dev,
- struct s5p_ace_aes_ctx *sctx,
- struct ablkcipher_request *req, u32 encmode)
-{
- int ret;
-
- sctx->origin_tfm = req->base.tfm;
- crypto_ablkcipher_set_flags(sctx->fallback_abc, 0);
- ablkcipher_request_set_tfm(req, sctx->fallback_abc);
-
- if (encmode == BC_MODE_ENC)
- ret = crypto_ablkcipher_encrypt(req);
- else
- ret = crypto_ablkcipher_decrypt(req);
-
- sctx->req = req;
- dev->ctx_bc = sctx;
- tasklet_schedule(&dev->task_bc);
-
- return ret;
-}
-
-static int s5p_ace_aes_handle_req(struct s5p_ace_device *dev)
-{
- struct crypto_async_request *async_req;
- struct crypto_async_request *backlog;
- struct s5p_ace_aes_ctx *sctx;
- struct s5p_ace_reqctx *rctx;
- struct ablkcipher_request *req;
- unsigned long flags;
-
- if (dev->ctx_bc)
- goto start;
-
- S5P_ACE_DEBUG("%s\n", __func__);
-
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- backlog = crypto_get_backlog(&dev->queue_bc);
- async_req = crypto_dequeue_request(&dev->queue_bc);
- S5P_ACE_DEBUG("[[ dequeue (%u) ]]\n", dev->queue_bc.qlen);
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- if (!async_req) {
- clear_bit(FLAGS_BC_BUSY, &dev->flags);
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
- return 0;
- }
-
- if (backlog) {
- S5P_ACE_DEBUG("backlog.\n");
- backlog->complete(backlog, -EINPROGRESS);
- }
-
- S5P_ACE_DEBUG("get new req\n");
-
- req = ablkcipher_request_cast(async_req);
- sctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
-
-#ifdef ACE_DEBUG_WATCHDOG
- hrtimer_start(&s5p_ace_dev.watchdog_bc,
- ns_to_ktime((u64)ACE_WATCHDOG_MS * NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
-#endif
- rctx = ablkcipher_request_ctx(req);
-
- if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW))
- return s5p_ace_handle_lock_req(dev, sctx, req, rctx->mode);
-
- /* assign new request to device */
- sctx->req = req;
- sctx->total = req->nbytes;
- sctx->in_sg = req->src;
- sctx->in_ofs = 0;
- sctx->out_sg = req->dst;
- sctx->out_ofs = 0;
-
- if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
- memcpy(sctx->sfr_semikey, req->info, AES_BLOCK_SIZE);
-
- s5p_ace_aes_set_encmode(sctx, rctx->mode);
-
- dev->ctx_bc = sctx;
-
-start:
- return s5p_ace_aes_crypt_dma_start(dev);
-}
-
-static void s5p_ace_bc_task(unsigned long data)
-{
- struct s5p_ace_device *dev = (struct s5p_ace_device *)data;
- struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
- int ret = 0;
-
- S5P_ACE_DEBUG("%s (total: %d, dma_size: %d)\n", __func__,
- sctx->total, sctx->dma_size);
-
- /* check if it is handled by SW or HW */
- if (sctx->req->base.tfm ==
- crypto_ablkcipher_tfm
- (crypto_ablkcipher_crt(sctx->fallback_abc)->base)) {
- sctx->req->base.tfm = sctx->origin_tfm;
- sctx->req->base.complete(&sctx->req->base, ret);
- dev->ctx_bc = NULL;
- s5p_ace_aes_handle_req(dev);
-
- return;
- }
-
- if (sctx->dma_size)
- ret = s5p_ace_aes_crypt_dma_wait(dev);
-
- if (!sctx->total) {
- if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK)
- != ACE_AES_OPERMODE_ECB)
- memcpy(sctx->req->info, sctx->sfr_semikey,
- AES_BLOCK_SIZE);
- sctx->req->base.complete(&sctx->req->base, ret);
- dev->ctx_bc = NULL;
-
-#ifdef ACE_DEBUG_WATCHDOG
- hrtimer_cancel(&s5p_ace_dev.watchdog_bc);
-#endif
- }
-
- s5p_ace_aes_handle_req(dev);
-}
-
-static int s5p_ace_aes_crypt(struct ablkcipher_request *req, u32 encmode)
-{
- struct s5p_ace_reqctx *rctx = ablkcipher_request_ctx(req);
- unsigned long flags;
- int ret;
- unsigned long timeout;
-
-#ifdef ACE_DEBUG_WATCHDOG
- do_gettimeofday(&timestamp[0]); /* 0: request */
-#endif
-
- S5P_ACE_DEBUG("%s (nbytes: 0x%x, mode: 0x%x)\n",
- __func__, (u32)req->nbytes, encmode);
-
- rctx->mode = encmode;
-
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (s5p_ace_dev.queue_bc.list.prev != &req->base.list)
- break;
- udelay(1); /* wait */
- }
- if (s5p_ace_dev.queue_bc.list.prev == &req->base.list) {
- printk(KERN_ERR "%s : Time Out.\n", __func__);
- return -EAGAIN;
- }
-
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- ret = ablkcipher_enqueue_request(&s5p_ace_dev.queue_bc, req);
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- S5P_ACE_DEBUG("[[ enqueue (%u) ]]\n", s5p_ace_dev.queue_bc.qlen);
-
- s5p_ace_resume_device(&s5p_ace_dev);
- if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
- s5p_ace_clock_gating(ACE_CLOCK_ON);
- s5p_ace_dev.rc_depth_bc = 0;
- s5p_ace_aes_handle_req(&s5p_ace_dev);
- }
-
- return ret;
-}
-#else
-static int s5p_ace_handle_lock_req(struct s5p_ace_aes_ctx *sctx,
- struct blkcipher_desc *desc,
- struct scatterlist *sg_dst,
- struct scatterlist *sg_src,
- unsigned int size, int encmode)
-{
- int ret;
-
- sctx->origin_tfm = desc->tfm;
- desc->tfm = sctx->fallback_bc;
-
- if (encmode == BC_MODE_ENC)
- ret = crypto_blkcipher_encrypt_iv(desc, sg_dst, sg_src, size);
- else
- ret = crypto_blkcipher_decrypt_iv(desc, sg_dst, sg_src, size);
-
- desc->tfm = sctx->origin_tfm;
-
- return ret;
-}
-
-static int s5p_ace_aes_crypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes, int encmode)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- int ret;
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[0]); /* 0: request */
-#endif
-
-#ifdef ACE_DEBUG_WATCHDOG
- hrtimer_start(&s5p_ace_dev.watchdog_bc,
- ns_to_ktime((u64)ACE_WATCHDOG_MS * NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
-#endif
-
- sctx->total = nbytes;
- sctx->in_sg = src;
- sctx->in_ofs = 0;
- sctx->out_sg = dst;
- sctx->out_ofs = 0;
-
- if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
- memcpy(sctx->sfr_semikey, desc->info, AES_BLOCK_SIZE);
-
- s5p_ace_aes_set_encmode(sctx, encmode);
-
- s5p_ace_resume_device(&s5p_ace_dev);
- s5p_ace_clock_gating(ACE_CLOCK_ON);
- local_bh_disable();
- while (test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags))
- udelay(1);
-
- if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
- clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
- return s5p_ace_handle_lock_req(sctx, desc, dst, src, nbytes,
- encmode);
- }
-
- s5p_ace_dev.ctx_bc = sctx;
-
- do {
- ret = s5p_ace_aes_crypt_dma_start(&s5p_ace_dev);
-
- if (sctx->dma_size)
- ret = s5p_ace_aes_crypt_dma_wait(&s5p_ace_dev);
- } while (sctx->total);
-
- s5p_ace_dev.ctx_bc = NULL;
-
- clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
-
- if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
- memcpy(desc->info, sctx->sfr_semikey, AES_BLOCK_SIZE);
-
-#ifdef ACE_DEBUG_WATCHDOG
- hrtimer_cancel(&s5p_ace_dev.watchdog_bc);
-#endif
-
- return ret;
-}
-#endif
-
-static int s5p_ace_aes_set_key(struct s5p_ace_aes_ctx *sctx, const u8 *key,
- unsigned int key_len)
-{
- memcpy(sctx->sfr_key, key, key_len);
- crypto_blkcipher_setkey(sctx->fallback_bc, key, key_len);
-
-#ifdef CONFIG_ACE_BC_ASYNC
- crypto_ablkcipher_setkey(sctx->fallback_abc, key, key_len);
-#endif
-
- return 0;
-}
-
-#ifdef CONFIG_ACE_BC_ASYNC
-static int s5p_ace_ecb_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_ECB, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_cbc_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_CBC, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_ctr_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_CTR, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_ecb_aes_encrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_ENC);
-}
-
-static int s5p_ace_ecb_aes_decrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_DEC);
-}
-
-static int s5p_ace_cbc_aes_encrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_ENC);
-}
-
-static int s5p_ace_cbc_aes_decrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_DEC);
-}
-
-static int s5p_ace_ctr_aes_encrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_ENC);
-}
-
-static int s5p_ace_ctr_aes_decrypt(struct ablkcipher_request *req)
-{
- return s5p_ace_aes_crypt(req, BC_MODE_DEC);
-}
-#else
-static int s5p_ace_ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_ECB, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_CBC, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
- s5p_ace_aes_set_cipher(sctx, MI_AES_CTR, key_len * 8);
- return s5p_ace_aes_set_key(sctx, key, key_len);
-}
-
-static int s5p_ace_ecb_aes_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
-}
-
-static int s5p_ace_ecb_aes_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
-}
-
-static int s5p_ace_cbc_aes_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
-}
-
-static int s5p_ace_cbc_aes_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
-}
-
-static int s5p_ace_ctr_aes_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
-}
-
-static int s5p_ace_ctr_aes_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
-{
- return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
-}
-#endif
-
-static int s5p_ace_cra_init_tfm(struct crypto_tfm *tfm)
-{
- const char *name = tfm->__crt_alg->cra_name;
- struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-
- sctx->fallback_bc = crypto_alloc_blkcipher(name, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-
- if (IS_ERR(sctx->fallback_bc)) {
- printk(KERN_ERR "Error allocating fallback algo %s\n", name);
- return PTR_ERR(sctx->fallback_bc);
- }
-#ifdef CONFIG_ACE_BC_ASYNC
- tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_ace_reqctx);
- sctx->fallback_abc = crypto_alloc_ablkcipher(name, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-
- if (IS_ERR(sctx->fallback_abc)) {
- printk(KERN_ERR "Error allocating abc fallback algo %s\n",
- name);
- return PTR_ERR(sctx->fallback_abc);
- }
-
-#endif
- S5P_ACE_DEBUG("%s\n", __func__);
-
- return 0;
-}
-
-static void s5p_ace_cra_exit_tfm(struct crypto_tfm *tfm)
-{
- struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-
- crypto_free_blkcipher(sctx->fallback_bc);
- sctx->fallback_bc = NULL;
-
-#ifdef CONFIG_ACE_BC_ASYNC
- crypto_free_ablkcipher(sctx->fallback_abc);
- sctx->fallback_abc = NULL;
-#endif
-
- S5P_ACE_DEBUG("%s\n", __func__);
-}
-
-static struct crypto_alg algs_bc[] = {
- {
- .cra_name = "ecb(aes)",
- .cra_driver_name = "ecb-aes-s5p-ace",
- .cra_priority = 300,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
- | CRYPTO_ALG_ASYNC,
-#else
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
-#endif
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
- .cra_alignmask = 0,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_type = &crypto_ablkcipher_type,
-#else
- .cra_type = &crypto_blkcipher_type,
-#endif
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_cra_init_tfm,
- .cra_exit = s5p_ace_cra_exit_tfm,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_ablkcipher = {
-#else
- .cra_blkcipher = {
-#endif
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = s5p_ace_ecb_aes_set_key,
- .encrypt = s5p_ace_ecb_aes_encrypt,
- .decrypt = s5p_ace_ecb_aes_decrypt,
- }
- },
- {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "cbc-aes-s5p-ace",
- .cra_priority = 300,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
- | CRYPTO_ALG_ASYNC,
-#else
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
-#endif
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
- .cra_alignmask = 0,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_type = &crypto_ablkcipher_type,
-#else
- .cra_type = &crypto_blkcipher_type,
-#endif
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_cra_init_tfm,
- .cra_exit = s5p_ace_cra_exit_tfm,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_ablkcipher = {
-#else
- .cra_blkcipher = {
-#endif
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = s5p_ace_cbc_aes_set_key,
- .encrypt = s5p_ace_cbc_aes_encrypt,
- .decrypt = s5p_ace_cbc_aes_decrypt,
- }
- },
- {
- .cra_name = "ctr(aes)",
- .cra_driver_name = "ctr-aes-s5p-ace",
- .cra_priority = 300,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
- | CRYPTO_ALG_ASYNC,
-#else
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
-#endif
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
- .cra_alignmask = 0,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_type = &crypto_ablkcipher_type,
-#else
- .cra_type = &crypto_blkcipher_type,
-#endif
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_cra_init_tfm,
- .cra_exit = s5p_ace_cra_exit_tfm,
-#ifdef CONFIG_ACE_BC_ASYNC
- .cra_ablkcipher = {
-#else
- .cra_blkcipher = {
-#endif
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = s5p_ace_ctr_aes_set_key,
- .encrypt = s5p_ace_ctr_aes_encrypt,
- .decrypt = s5p_ace_ctr_aes_decrypt,
- }
- }
-};
-#endif
-
-#define TYPE_HASH_SHA1 0
-#define TYPE_HASH_SHA256 1
-
-#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
-struct s5p_ace_hash_ctx {
- u32 type;
- u32 prelen_high;
- u32 prelen_low;
-
- u32 buflen;
- u8 buffer[SHA256_BLOCK_SIZE];
-
- u32 state[SHA256_DIGEST_SIZE / 4];
-
- u32 sw_init;
-
- struct shash_desc sw_desc;
- struct sha256_state dummy;
-};
-
-/*
- * out == NULL - This is not a final message block.
- * Intermediate value is stored at pCtx->digest.
- * out != NULL - This is a final message block.
- * Digest value will be stored at out.
- */
-static int s5p_ace_sha_engine(struct s5p_ace_hash_ctx *sctx,
- u8 *out, const u8* in, u32 len)
-{
- u32 reg;
- u32 *buffer;
- u32 block_size, digest_size;
- u8 *in_phys;
- int transformmode = 0;
-
- S5P_ACE_DEBUG("Out: 0x%08X, In: 0x%08X, Len: %d\n",
- (u32)out, (u32)in, len);
- S5P_ACE_DEBUG("PreLen_Hi: %u, PreLen_Lo: %u\n",
- sctx->prelen_high, sctx->prelen_low);
-
- block_size = (sctx->type == TYPE_HASH_SHA1) ?
- SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
- digest_size = (sctx->type == TYPE_HASH_SHA1) ?
- SHA1_DIGEST_SIZE : SHA256_DIGEST_SIZE;
-
- if (out == NULL) {
- if (len == 0) {
- return 0;
- } else if (len < digest_size) {
- printk(KERN_ERR "%s: Invalid input\n", __func__);
- return -EINVAL;
- }
- transformmode = 1;
- }
-
- if (len == 0) {
- S5P_ACE_DEBUG("%s: Workaround for empty input\n", __func__);
-
- memset(sctx->buffer, 0, block_size - 8);
- sctx->buffer[0] = 0x80;
- reg = cpu_to_be32(sctx->prelen_high);
- memcpy(sctx->buffer + block_size - 8, &reg, 4);
- reg = cpu_to_be32(sctx->prelen_low);
- memcpy(sctx->buffer + block_size - 4, &reg, 4);
-
- in = sctx->buffer;
- len = block_size;
- transformmode = 1;
- }
-
- if ((void *)in < high_memory) {
- in_phys = (u8 *)virt_to_phys((void*)in);
- } else {
- struct page *page;
- S5P_ACE_DEBUG("%s: high memory - 0x%08x\n", __func__, (u32)in);
- page = vmalloc_to_page(in);
- if (!page)
- printk(KERN_ERR "ERROR: %s: Null page\n", __func__);
- in_phys = (u8 *)page_to_phys(page);
- in_phys += ((u32)in & ~PAGE_MASK);
- }
-
- /* Flush HRDMA */
- s5p_ace_write_sfr(ACE_FC_HRDMAC, ACE_FC_HRDMACFLUSH_ON);
- reg = ACE_FC_HRDMACFLUSH_OFF;
- if (s5p_ace_dev.cputype == TYPE_S5PV210)
- reg |= ACE_FC_HRDMACSWAP_ON;
-
-#ifdef ACE_USE_ACP
- reg |= ACE_ARCACHE << ACE_FC_HRDMACARCACHE_OFS;
-#endif
- s5p_ace_write_sfr(ACE_FC_HRDMAC, reg);
-
- /* Set byte swap of data in */
- if (s5p_ace_dev.cputype == TYPE_EXYNOS)
- s5p_ace_write_sfr(ACE_HASH_BYTESWAP, ACE_HASH_SWAPDI_ON |
- ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON);
- else
- s5p_ace_write_sfr(ACE_HASH_BYTESWAP,
- ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON);
-
- /* Select Hash input mux as external source */
- reg = s5p_ace_read_sfr(ACE_FC_FIFOCTRL);
- reg = (reg & ~ACE_FC_SELHASH_MASK) | ACE_FC_SELHASH_EXOUT;
- s5p_ace_write_sfr(ACE_FC_FIFOCTRL, reg);
-
- /* Set Hash as SHA1 or SHA256 and start Hash engine */
- reg = (sctx->type == TYPE_HASH_SHA1) ?
- ACE_HASH_ENGSEL_SHA1HASH : ACE_HASH_ENGSEL_SHA256HASH;
- reg |= ACE_HASH_STARTBIT_ON;
- if ((sctx->prelen_low | sctx->prelen_high) != 0) {
- reg |= ACE_HASH_USERIV_EN;
- buffer = (u32 *)sctx->state;
- s5p_ace_write_sfr(ACE_HASH_IV1, buffer[0]);
- s5p_ace_write_sfr(ACE_HASH_IV2, buffer[1]);
- s5p_ace_write_sfr(ACE_HASH_IV3, buffer[2]);
- s5p_ace_write_sfr(ACE_HASH_IV4, buffer[3]);
- s5p_ace_write_sfr(ACE_HASH_IV5, buffer[4]);
-
- if (sctx->type == TYPE_HASH_SHA256) {
- s5p_ace_write_sfr(ACE_HASH_IV6, buffer[5]);
- s5p_ace_write_sfr(ACE_HASH_IV7, buffer[6]);
- s5p_ace_write_sfr(ACE_HASH_IV8, buffer[7]);
- }
- }
- s5p_ace_write_sfr(ACE_HASH_CONTROL, reg);
-
- /* Enable FIFO mode */
- s5p_ace_write_sfr(ACE_HASH_FIFO_MODE, ACE_HASH_FIFO_ON);
-
- /* Clean data cache */
-#ifndef ACE_USE_ACP
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
- dmac_clean_range((void *)in, (void *)in + len);
-#else
- dmac_map_area((void *)in, len, DMA_TO_DEVICE);
- outer_clean_range((unsigned long)in_phys, (unsigned long)in_phys + len);
-#endif
-#endif
-
- if (transformmode) {
- /* Set message length */
- s5p_ace_write_sfr(ACE_HASH_MSGSIZE_LOW, 0);
- s5p_ace_write_sfr(ACE_HASH_MSGSIZE_HIGH, 0x80000000);
-
- /* Set pre-message length */
- s5p_ace_write_sfr(ACE_HASH_PRELEN_LOW, 0);
- s5p_ace_write_sfr(ACE_HASH_PRELEN_HIGH, 0);
- } else {
- /* Set message length */
- s5p_ace_write_sfr(ACE_HASH_MSGSIZE_LOW, len);
- s5p_ace_write_sfr(ACE_HASH_MSGSIZE_HIGH, 0);
-
- /* Set pre-message length */
- s5p_ace_write_sfr(ACE_HASH_PRELEN_LOW, sctx->prelen_low);
- s5p_ace_write_sfr(ACE_HASH_PRELEN_HIGH, sctx->prelen_high);
- }
-
- /* Set HRDMA */
- s5p_ace_write_sfr(ACE_FC_HRDMAS, (u32)in_phys);
- s5p_ace_write_sfr(ACE_FC_HRDMAL, len);
-
- while (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_HRDMA))
- ; /* wait */
- s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_HRDMA);
-
- /*while ((s5p_ace_read_sfr(ACE_HASH_STATUS) & ACE_HASH_BUFRDY_MASK)
- == ACE_HASH_BUFRDY_OFF); */
-
- if (transformmode) {
- /* Set Pause bit */
- s5p_ace_write_sfr(ACE_HASH_CONTROL2, ACE_HASH_PAUSE_ON);
-
- while ((s5p_ace_read_sfr(ACE_HASH_STATUS)
- & ACE_HASH_PARTIALDONE_MASK)
- == ACE_HASH_PARTIALDONE_OFF)
- ; /* wait */
- s5p_ace_write_sfr(ACE_HASH_STATUS, ACE_HASH_PARTIALDONE_ON);
-
- if (out == NULL) {
- /* Update chaining variables */
- buffer = (u32 *)sctx->state;
-
- /* Update pre-message length */
- /* Note that the unit of pre-message length is a BIT! */
- sctx->prelen_low += (len << 3);
- if (sctx->prelen_low < len)
- sctx->prelen_high++;
- sctx->prelen_high += (len >> 29);
- } else {
- /* Read hash result */
- buffer = (u32 *)out;
- }
- } else {
- while ((s5p_ace_read_sfr(ACE_HASH_STATUS)
- & ACE_HASH_MSGDONE_MASK)
- == ACE_HASH_MSGDONE_OFF)
- ; /* wait */
- s5p_ace_write_sfr(ACE_HASH_STATUS, ACE_HASH_MSGDONE_ON);
-
- /* Read hash result */
- buffer = (u32 *)out;
- }
- buffer[0] = s5p_ace_read_sfr(ACE_HASH_RESULT1);
- buffer[1] = s5p_ace_read_sfr(ACE_HASH_RESULT2);
- buffer[2] = s5p_ace_read_sfr(ACE_HASH_RESULT3);
- buffer[3] = s5p_ace_read_sfr(ACE_HASH_RESULT4);
- buffer[4] = s5p_ace_read_sfr(ACE_HASH_RESULT5);
-
- if (sctx->type == TYPE_HASH_SHA256) {
- buffer[5] = s5p_ace_read_sfr(ACE_HASH_RESULT6);
- buffer[6] = s5p_ace_read_sfr(ACE_HASH_RESULT7);
- buffer[7] = s5p_ace_read_sfr(ACE_HASH_RESULT8);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_ACE_HASH_ASYNC
-static int s5p_ace_sha1_init(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
-
- sctx->prelen_high = sctx->prelen_low = 0;
- sctx->buflen = 0;
-
- /* To Do */
-
- return 0;
-}
-
-static int s5p_ace_sha1_update(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
-
- /* To Do */
-
- return 0;
-}
-
-static int s5p_ace_sha1_final(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
-
- /* To Do */
-
- return 0;
-}
-
-static int s5p_ace_sha1_finup(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
-
- /* To Do */
-
- return 0;
-}
-
-static int s5p_ace_sha1_digest(struct ahash_request *req)
-{
- s5p_ace_sha1_init(req);
- s5p_ace_sha1_update(req);
- s5p_ace_sha1_final(req);
-
- return 0;
-}
-#else
-static void sha1_export_ctx_to_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- struct sha1_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
- int i;
-
- if (sctx->prelen_low == 0 && sctx->prelen_high == 0)
- crypto_shash_alg(&sw_tfm[sctx->type])
- ->init(&sctx->sw_desc);
- else {
- for (i = 0; i < SHA1_DIGEST_SIZE/4; i++)
- sw_ctx->state[i] = be32_to_cpu(sctx->state[i]);
- }
-
- sw_ctx->count = (((u64)sctx->prelen_high << 29) |
- (sctx->prelen_low >> 3)) + sctx->buflen;
-
- if (sctx->buflen)
- memcpy(sw_ctx->buffer, sctx->buffer, sctx->buflen);
-}
-
-static void sha256_export_ctx_to_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- struct sha256_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
- int i;
-
- if (sctx->prelen_low == 0 && sctx->prelen_high == 0)
- crypto_shash_alg(&sw_tfm[sctx->type])
- ->init(&sctx->sw_desc);
- else {
- for (i = 0; i < SHA256_DIGEST_SIZE/4; i++)
- sw_ctx->state[i] = be32_to_cpu(sctx->state[i]);
- }
-
- sw_ctx->count = (((u64)sctx->prelen_high << 29) |
- (sctx->prelen_low >> 3)) + sctx->buflen;
-
- if (sctx->buflen)
- memcpy(sw_ctx->buf, sctx->buffer, sctx->buflen);
-}
-
-static void sha1_import_ctx_from_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- struct sha1_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
- int i;
-
- for (i = 0; i < SHA1_DIGEST_SIZE/4; i++)
- sctx->state[i] = cpu_to_be32(sw_ctx->state[i]);
-
- memcpy(sctx->buffer, sw_ctx->buffer, sw_ctx->count &
- (SHA1_BLOCK_SIZE - 1));
- sctx->buflen = sw_ctx->count & (SHA1_BLOCK_SIZE - 1);
-
- sctx->prelen_low = (sw_ctx->count - sctx->buflen) << 3;
- sctx->prelen_high = (sw_ctx->count - sctx->buflen) >> 29;
-}
-
-static void sha256_import_ctx_from_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- struct sha256_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
- int i;
-
- for (i = 0; i < SHA256_DIGEST_SIZE/4; i++)
- sctx->state[i] = cpu_to_be32(sw_ctx->state[i]);
-
- memcpy(sctx->buffer, sw_ctx->buf, sw_ctx->count &
- (SHA256_BLOCK_SIZE - 1));
- sctx->buflen = sw_ctx->count & (SHA256_BLOCK_SIZE - 1);
-
- sctx->prelen_low = (sw_ctx->count - sctx->buflen) << 3;
- sctx->prelen_high = (sw_ctx->count - sctx->buflen) >> 29;
-}
-
-static void hash_export_ctx_to_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- if (!sctx->sw_init) {
- sctx->sw_init = 1;
- if (sctx->prelen_low == 0 && sctx->prelen_high == 0 &&
- sctx->buflen == 0) {
- crypto_shash_alg(&sw_tfm[sctx->type])
- ->init(&sctx->sw_desc);
- return;
- }
- }
-
- if (sctx->type == TYPE_HASH_SHA1)
- sha1_export_ctx_to_sw(desc);
- else
- sha256_export_ctx_to_sw(desc);
-}
-
-static void hash_import_ctx_from_sw(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- if (sctx->type == TYPE_HASH_SHA1)
- sha1_import_ctx_from_sw(desc);
- else
- sha256_import_ctx_from_sw(desc);
-
-}
-
-static int sha_sw_update(struct shash_desc *desc, const u8 *data, unsigned
- int len)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- hash_export_ctx_to_sw(desc);
- crypto_shash_alg(&sw_tfm[sctx->type])->update(&sctx->sw_desc, data,
- len);
- hash_import_ctx_from_sw(desc);
-
- return 0;
-}
-
-static int sha_sw_final(struct shash_desc *desc, u8 *out)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- hash_export_ctx_to_sw(desc);
- crypto_shash_alg(&sw_tfm[sctx->type])->final(&sctx->sw_desc, out);
- hash_import_ctx_from_sw(desc);
-
- return 0;
-}
-
-static int sha_sw_finup(struct shash_desc *desc, const u8 *data, unsigned int
- len, u8 *out)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- hash_export_ctx_to_sw(desc);
- crypto_shash_alg(&sw_tfm[sctx->type])->update(&sctx->sw_desc, data,
- len);
- crypto_shash_alg(&sw_tfm[sctx->type])->final(&sctx->sw_desc, out);
- hash_import_ctx_from_sw(desc);
-
- return 0;
-}
-
-#if defined(CONFIG_ACE_HASH_SHA1)
-static int s5p_ace_sha1_init(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- sctx->prelen_high = sctx->prelen_low = 0;
- sctx->buflen = 0;
- sctx->type = TYPE_HASH_SHA1;
- sctx->sw_init = 0;
-
- return 0;
-}
-#endif
-
-#if defined(CONFIG_ACE_HASH_SHA256)
-static int s5p_ace_sha256_init(struct shash_desc *desc)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- sctx->prelen_high = sctx->prelen_low = 0;
- sctx->buflen = 0;
- sctx->type = TYPE_HASH_SHA256;
- sctx->sw_init = 0;
-
- return 0;
-}
-#endif
-
-static int s5p_ace_sha_update(struct shash_desc *desc,
- const u8 *data, unsigned int len)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- const u8 *src;
- int ret = 0;
- u32 partlen, tmplen, block_size;
-
- S5P_ACE_DEBUG("%s (buflen: 0x%x, len: 0x%x)\n",
- __func__, sctx->buflen, len);
-
- s5p_ace_resume_device(&s5p_ace_dev);
- local_bh_disable();
- while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
- udelay(1);
-
- if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
- return sha_sw_update(desc, data, len);
- }
-
- partlen = sctx->buflen;
- src = data;
-
- block_size = (sctx->type == TYPE_HASH_SHA1) ?
- SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
- s5p_ace_clock_gating(ACE_CLOCK_ON);
-
- if (partlen != 0) {
- if (partlen + len < block_size) {
- memcpy(sctx->buffer + partlen, src, len);
- sctx->buflen += len;
- goto out;
- } else {
- tmplen = block_size - partlen;
- memcpy(sctx->buffer + partlen, src, tmplen);
-
- ret = s5p_ace_sha_engine(sctx, NULL, sctx->buffer,
- block_size);
- if (ret)
- goto out;
-
- len -= tmplen;
- src += tmplen;
- }
- }
-
- partlen = len & (block_size - 1);
- len -= partlen;
- if (len > 0) {
- ret = s5p_ace_sha_engine(sctx, NULL, src, len);
- if (ret)
- goto out;
- }
-
- memcpy(sctx->buffer, src + len, partlen);
- sctx->buflen = partlen;
-
-out:
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
-
- return ret;
-}
-
-static int s5p_ace_sha_final(struct shash_desc *desc, u8 *out)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
-
- S5P_ACE_DEBUG("%s (buflen: 0x%x)\n", __func__, sctx->buflen);
-
- s5p_ace_resume_device(&s5p_ace_dev);
- local_bh_disable();
- while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
- udelay(1);
-
- if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
- return sha_sw_final(desc, out);
- }
-
- s5p_ace_clock_gating(ACE_CLOCK_ON);
- s5p_ace_sha_engine(sctx, out, sctx->buffer, sctx->buflen);
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
-
- /* Wipe context */
- memset(sctx, 0, sizeof(*sctx));
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
-
- return 0;
-}
-
-static int s5p_ace_sha_finup(struct shash_desc *desc, const u8 *data,
- unsigned int len, u8 *out)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- const u8 *src;
- int ret = 0;
- u32 block_size;
-
- S5P_ACE_DEBUG("%s (buflen: 0x%x, len: 0x%x)\n",
- __func__, sctx->buflen, len);
-
- s5p_ace_resume_device(&s5p_ace_dev);
- local_bh_disable();
- while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
- udelay(1);
-
- if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
- return sha_sw_finup(desc, data, len, out);
- }
-
- src = data;
- block_size = (sctx->type == TYPE_HASH_SHA1) ?
- SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
-
- s5p_ace_clock_gating(ACE_CLOCK_ON);
-
- if (sctx->buflen != 0) {
- if (sctx->buflen + len <= block_size) {
- memcpy(sctx->buffer + sctx->buflen, src, len);
-
- len += sctx->buflen;
- src = sctx->buffer;
- } else {
- u32 copylen = block_size - sctx->buflen;
- memcpy(sctx->buffer + sctx->buflen, src, copylen);
-
- ret = s5p_ace_sha_engine(sctx, NULL, sctx->buffer,
- block_size);
- if (ret)
- goto out;
-
- len -= copylen;
- src += copylen;
- }
- }
-
- ret = s5p_ace_sha_engine(sctx, out, src, len);
-
-out:
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
-
- /* Wipe context */
- memset(sctx, 0, sizeof(*sctx));
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
- local_bh_enable();
-
- return ret;
-}
-
-#if defined(CONFIG_ACE_HASH_SHA1)
-static int s5p_ace_sha1_digest(struct shash_desc *desc, const u8 *data,
- unsigned int len, u8 *out)
-{
- int ret;
-
- ret = s5p_ace_sha1_init(desc);
- if (ret)
- return ret;
-
- return s5p_ace_sha_finup(desc, data, len, out);
-}
-#endif
-
-#if defined(CONFIG_ACE_HASH_SHA256)
-static int s5p_ace_sha256_digest(struct shash_desc *desc, const u8 *data,
- unsigned int len, u8 *out)
-{
- int ret;
-
- ret = s5p_ace_sha256_init(desc);
- if (ret)
- return ret;
-
- return s5p_ace_sha_finup(desc, data, len, out);
-}
-#endif
-
-static int s5p_ace_hash_export(struct shash_desc *desc, void *out)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- memcpy(out, sctx, sizeof(*sctx));
- return 0;
-}
-
-static int s5p_ace_hash_import(struct shash_desc *desc, const void *in)
-{
- struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
- memcpy(sctx, in, sizeof(*sctx));
- return 0;
-}
-#endif
-
-static int s5p_ace_hash_cra_init(struct crypto_tfm *tfm)
-{
-#ifdef CONFIG_ACE_HASH_ASYNC
-#endif
-
- S5P_ACE_DEBUG("%s\n", __func__);
-
- return 0;
-}
-
-static void s5p_ace_hash_cra_exit(struct crypto_tfm *tfm)
-{
-#ifdef CONFIG_ACE_HASH_ASYNC
-#endif
-
- S5P_ACE_DEBUG("%s\n", __func__);
-}
-
-#ifdef CONFIG_ACE_HASH_ASYNC
-static struct ahash_alg algs_hash[] = {
-#if defined(CONFIG_ACE_HASH_SHA1)
- {
- .init = s5p_ace_sha1_init,
- .update = s5p_ace_sha_update,
- .final = s5p_ace_sha_final,
- .finup = s5p_ace_sha_finup,
- .digest = s5p_ace_sha1_digest,
- .halg.digestsize = SHA1_DIGEST_SIZE,
- .halg.base = {
- .cra_name = "sha1",
- .cra_driver_name = "sha1-s5p-ace",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH
- | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SHA1_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct s5p_ace_hash_ctx),
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_hash_cra_init,
- .cra_exit = s5p_ace_hash_cra_exit,
- }
- }
-#endif
-};
-#else
-static struct shash_alg algs_hash[] = {
-#if defined(CONFIG_ACE_HASH_SHA1)
- {
- .digestsize = SHA1_DIGEST_SIZE,
- .init = s5p_ace_sha1_init,
- .update = s5p_ace_sha_update,
- .final = s5p_ace_sha_final,
- .finup = s5p_ace_sha_finup,
- .digest = s5p_ace_sha1_digest,
- .export = s5p_ace_hash_export,
- .import = s5p_ace_hash_import,
- .descsize = sizeof(struct s5p_ace_hash_ctx),
- .statesize = sizeof(struct s5p_ace_hash_ctx),
- .base = {
- .cra_name = "sha1",
- .cra_driver_name = "sha1-s5p-ace",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_SHASH,
- .cra_blocksize = SHA1_BLOCK_SIZE,
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_hash_cra_init,
- .cra_exit = s5p_ace_hash_cra_exit,
- }
- },
-#endif
-#if defined(CONFIG_ACE_HASH_SHA256)
- {
- .digestsize = SHA256_DIGEST_SIZE,
- .init = s5p_ace_sha256_init,
- .update = s5p_ace_sha_update,
- .final = s5p_ace_sha_final,
- .finup = s5p_ace_sha_finup,
- .digest = s5p_ace_sha256_digest,
- .export = s5p_ace_hash_export,
- .import = s5p_ace_hash_import,
- .descsize = sizeof(struct s5p_ace_hash_ctx),
- .statesize = sizeof(struct s5p_ace_hash_ctx),
- .base = {
- .cra_name = "sha256",
- .cra_driver_name = "sha256-s5p-ace",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_SHASH,
- .cra_blocksize = SHA256_BLOCK_SIZE,
- .cra_module = THIS_MODULE,
- .cra_init = s5p_ace_hash_cra_init,
- .cra_exit = s5p_ace_hash_cra_exit,
- }
- }
-#endif
-};
-#endif /* CONFIG_ACE_HASH_ASYNC */
-#endif /* CONFIG_ACE_HASH_SHA1 or CONFIG_ACE_HASH_SHA256 */
-
-#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
-static irqreturn_t s5p_ace_interrupt(int irq, void *data)
-{
- struct s5p_ace_device *dev = data;
-
- s5p_ace_write_sfr(ACE_FC_INTPEND,
- ACE_FC_BRDMA | ACE_FC_BTDMA | ACE_FC_HRDMA);
-
-#ifdef CONFIG_ACE_BC_IRQMODE
- s5p_ace_write_sfr(ACE_FC_INTENCLR, ACE_FC_BRDMA | ACE_FC_BTDMA);
-
- tasklet_schedule(&dev->task_bc);
-#endif
-
-#ifdef CONFIG_ACE_HASH_IRQMODE
- s5p_ace_write_sfr(ACE_FC_INTENCLR, ACE_FC_HRDMA);
-#endif
-
- return IRQ_HANDLED;
-}
-#endif
-
-int ace_s5p_get_sync_lock(void)
-{
- unsigned long timeout;
- int get_lock_bc = 0, get_lock_hash = 0;
- unsigned long flags;
-
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
- get_lock_bc = 1;
- break;
- }
- udelay(1);
- }
-
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (!test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags)) {
- get_lock_hash = 1;
- break;
- }
- udelay(1);
- }
-
- /* set lock flag */
- if (get_lock_bc && get_lock_hash) {
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- count_use_sw++;
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
- set_bit(FLAGS_USE_SW, &s5p_ace_dev.flags);
- }
-
- if (get_lock_bc) {
-#ifdef CONFIG_ACE_BC_ASYNC
- if (s5p_ace_dev.queue_bc.qlen > 0) {
- s5p_ace_clock_gating(ACE_CLOCK_ON);
- s5p_ace_dev.rc_depth_bc = 0;
- s5p_ace_aes_handle_req(&s5p_ace_dev);
- } else {
- clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
- }
-#else
- clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
-#endif
- }
-
- if (get_lock_hash)
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
-
- if (!(get_lock_bc && get_lock_hash))
- return -EBUSY;
-
- s5p_ace_clock_gating(ACE_CLOCK_ON);
-
- return 0;
-}
-
-int ace_s5p_release_sync_lock(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s5p_ace_dev.lock, flags);
- count_use_sw--;
- spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
-
- /* clear lock flag */
- if (!count_use_sw)
- clear_bit(FLAGS_USE_SW, &s5p_ace_dev.flags);
-
- s5p_ace_clock_gating(ACE_CLOCK_OFF);
-
- return 0;
-}
-
-static int __devinit s5p_ace_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct s5p_ace_device *s5p_adt = &s5p_ace_dev;
- int i, j, k, m;
- int ret;
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp_base);
- for (i = 0; i < 5; i++)
- do_gettimeofday(&timestamp[i]);
-#endif
-
- memset(s5p_adt, 0, sizeof(*s5p_adt));
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get platform resource\n");
- return -ENOENT;
- }
-
- s5p_adt->ace_base = ioremap(res->start, resource_size(res));
- if (s5p_adt->ace_base == NULL) {
- dev_err(&pdev->dev, "failed to remap register block\n");
- ret = -ENOMEM;
- goto err_mem1;
- }
-
- s5p_adt->clock = clk_get(&pdev->dev, "secss");
- if (IS_ERR(s5p_adt->clock)) {
- dev_err(&pdev->dev, "failed to find clock source\n");
- ret = -EBUSY;
- goto err_clk;
- }
- s5p_ace_init_clock_gating();
- s5p_adt->cputype = platform_get_device_id(pdev)->driver_data;
-
-#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
- s5p_adt->irq = platform_get_irq(pdev, 0);
- if (s5p_adt->irq < 0) {
- dev_err(&pdev->dev, "Failed to get irq#\n");
- s5p_adt->irq = 0;
- ret = -ENODEV;
- goto err_irq;
- }
- ret = request_irq(s5p_adt->irq, s5p_ace_interrupt, 0,
- S5P_ACE_DRIVER_NAME, (void *)s5p_adt);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request IRQ%d: err: %d.\n",
- s5p_adt->irq, ret);
- s5p_adt->irq = 0;
- ret = -ENODEV;
- goto err_irq;
- }
-#endif
-
-#ifdef ACE_USE_ACP
- s5p_adt->sss_usercon = ioremap(PA_SSS_USER_CON & PAGE_MASK, SZ_4K);
- if (s5p_adt->sss_usercon == NULL) {
- dev_err(&pdev->dev, "failed to remap register SSS_USER_CON\n");
- ret = -EBUSY;
- goto err_mem2;
- }
-
- /* Set ARUSER[12:8] and AWUSER[4:0] */
- writel(0x101, s5p_adt->sss_usercon
- + (PA_SSS_USER_CON & (PAGE_SIZE - 1)));
-#endif
-
- spin_lock_init(&s5p_adt->lock);
- s5p_adt->flags = 0;
- hrtimer_init(&s5p_adt->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s5p_adt->timer.function = s5p_ace_timer_func;
- INIT_WORK(&s5p_adt->work, s5p_ace_deferred_clock_disable);
-#ifdef ACE_DEBUG_HEARTBEAT
- hrtimer_init(&s5p_adt->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s5p_adt->heartbeat.function = s5p_ace_heartbeat_func;
- hrtimer_start(&s5p_ace_dev.heartbeat,
- ns_to_ktime((u64)ACE_HEARTBEAT_MS * NSEC_PER_MSEC),
- HRTIMER_MODE_REL);
-#endif
-#ifdef ACE_DEBUG_WATCHDOG
- hrtimer_init(&s5p_adt->watchdog_bc, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s5p_adt->watchdog_bc.function = s5p_ace_watchdog_bc_func;
-#endif
-
-#ifdef CONFIG_ACE_BC_ASYNC
- crypto_init_queue(&s5p_adt->queue_bc, 1);
- tasklet_init(&s5p_adt->task_bc, s5p_ace_bc_task,
- (unsigned long)s5p_adt);
-#endif
-
-#ifdef CONFIG_ACE_HASH_ASYNC
- crypto_init_queue(&s5p_adt->queue_hash, 1);
- tasklet_init(&s5p_adt->task_hash, s5p_ace_hash_task,
- (unsigned long)s5p_adt);
-#endif
-
-#if defined(CONFIG_ACE_BC)
- for (i = 0; i < ARRAY_SIZE(algs_bc); i++) {
- INIT_LIST_HEAD(&algs_bc[i].cra_list);
- algs_bc[i].cra_flags |= CRYPTO_ALG_NEED_FALLBACK;
- ret = crypto_register_alg(&algs_bc[i]);
- if (ret)
- goto err_reg_bc;
- printk(KERN_INFO "ACE: %s\n", algs_bc[i].cra_driver_name);
- }
-#endif
-
-#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
- fallback_hash = (struct crypto_hash **)
- kmalloc(sizeof(struct crypto_hash *) *
- ARRAY_SIZE(algs_hash), GFP_KERNEL);
- sw_tfm = (struct crypto_shash *) kmalloc(sizeof(struct crypto_shash)
- * ARRAY_SIZE(algs_hash),
- GFP_KERNEL);
-
- for (m = 0; m < ARRAY_SIZE(algs_hash); m++) {
- fallback_hash[m] =
- crypto_alloc_hash(algs_hash[m].base.cra_name, 0,
- CRYPTO_ALG_ASYNC);
-
- if (IS_ERR(fallback_hash[m])) {
- printk(KERN_ERR "failed to load transform for %s: %ld\n",
- algs_hash[m].base.cra_name,
- PTR_ERR(fallback_hash[m]));
- goto err_fallback_hash;
- }
-
- sw_tfm[m].base.__crt_alg = fallback_hash[m]->base.__crt_alg;
- }
-
- for (j = 0; j < ARRAY_SIZE(algs_hash); j++) {
-#ifdef CONFIG_ACE_HASH_ASYNC
- ret = crypto_register_ahash(&algs_hash[j]);
-#else
- ret = crypto_register_shash(&algs_hash[j]);
-#endif
- if (ret)
- goto err_reg_hash;
-#ifdef CONFIG_ACE_HASH_ASYNC
- printk(KERN_INFO "ACE: %s\n",
- algs_hash[j].halg.base.cra_driver_name);
-#else
- printk(KERN_INFO "ACE: %s\n",
- algs_hash[j].base.cra_driver_name);
-#endif
- }
-#endif
-
- secmem_ftn.lock = &ace_s5p_get_sync_lock;
- secmem_ftn.release = &ace_s5p_release_sync_lock;
- secmem_crypto_register(&secmem_ftn);
-
- count_use_sw = 0;
-
- printk(KERN_NOTICE "ACE driver is initialized\n");
-
- return 0;
-
-#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
-err_reg_hash:
- for (k = 0; k < j; k++)
-#ifdef CONFIG_ACE_HASH_ASYNC
- crypto_unregister_ahash(&algs_hash[k]);
-#else
- crypto_unregister_shash(&algs_hash[k]);
-#endif
-err_fallback_hash:
- kfree(sw_tfm);
- for (k = 0; k < m; k++)
- crypto_free_hash(fallback_hash[k]);
- kfree(fallback_hash);
-#endif
-#if defined(CONFIG_ACE_BC)
-err_reg_bc:
- for (k = 0; k < i; k++)
- crypto_unregister_alg(&algs_bc[k]);
-#ifdef CONFIG_ACE_BC_ASYNC
- tasklet_kill(&s5p_adt->task_bc);
-#endif
-#endif
-#ifdef CONFIG_ACE_HASH_ASYNC
- tasklet_kill(&s5p_adt->task_hash);
-#endif
-#ifdef ACE_USE_ACP
- iounmap(s5p_adt->sss_usercon);
-err_mem2:
-#endif
-#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
-err_irq:
- free_irq(s5p_adt->irq, (void *)s5p_adt);
- s5p_adt->irq = 0;
-#endif
-err_clk:
- iounmap(s5p_adt->ace_base);
- s5p_adt->ace_base = NULL;
-err_mem1:
-
- printk(KERN_ERR "ACE driver initialization failed.\n");
-
- return ret;
-}
-
-static int s5p_ace_remove(struct platform_device *dev)
-{
- struct s5p_ace_device *s5p_adt = &s5p_ace_dev;
- int i;
-
-#ifdef ACE_DEBUG_HEARTBEAT
- hrtimer_cancel(&s5p_adt->heartbeat);
-#endif
-
-#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
- if (s5p_adt->irq) {
- free_irq(s5p_adt->irq, (void *)s5p_adt);
- s5p_adt->irq = 0;
- }
-#endif
-
- if (s5p_adt->clock) {
- clk_put(s5p_adt->clock);
- s5p_adt->clock = NULL;
- }
-
- if (s5p_adt->ace_base) {
- iounmap(s5p_adt->ace_base);
- s5p_adt->ace_base = NULL;
- }
-
-#ifdef ACE_USE_ACP
- if (s5p_adt->sss_usercon) {
- iounmap(s5p_adt->sss_usercon);
- s5p_adt->sss_usercon = NULL;
- }
-#endif
-
- secmem_crypto_deregister();
-
-#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
- kfree(sw_tfm);
- for (i = 0; i < ARRAY_SIZE(algs_hash); i++)
- crypto_free_hash(fallback_hash[i]);
-
- kfree(fallback_hash);
-
- for (i = 0; i < ARRAY_SIZE(algs_hash); i++)
-#ifdef CONFIG_ACE_HASH_ASYNC
- crypto_unregister_ahash(&algs_hash[i]);
-#else
- crypto_unregister_shash(&algs_hash[i]);
-#endif
-#endif
-
-#if defined(CONFIG_ACE_BC)
- for (i = 0; i < ARRAY_SIZE(algs_bc); i++)
- crypto_unregister_alg(&algs_bc[i]);
-
-#ifdef CONFIG_ACE_BC_ASYNC
- tasklet_kill(&s5p_adt->task_bc);
-#endif
-#endif
-#ifdef CONFIG_ACE_HASH_ASYNC
- tasklet_kill(&s5p_adt->task_hash);
-#endif
-
- flush_work(&s5p_ace_dev.work);
-
- printk(KERN_INFO "ACE driver is removed\n");
-
- return 0;
-}
-
-static int s5p_ace_suspend(struct platform_device *dev, pm_message_t state)
-{
- unsigned long timeout;
- int get_lock_bc = 0, get_lock_hash = 0;
-
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[3]); /* 3: suspend */
-#endif
-
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
- get_lock_bc = 1;
- break;
- }
- udelay(1);
- }
- timeout = jiffies + msecs_to_jiffies(10);
- while (time_before(jiffies, timeout)) {
- if (!test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags)) {
- get_lock_hash = 1;
- break;
- }
- udelay(1);
- }
-
- if (get_lock_bc && get_lock_hash) {
- set_bit(FLAGS_SUSPENDED, &s5p_ace_dev.flags);
- return 0;
- }
-
- printk(KERN_ERR "ACE: suspend: time out.\n");
-
- if (get_lock_bc)
- clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
- if (get_lock_hash)
- clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
-
- return -EBUSY;
-}
-
-static int s5p_ace_resume(struct platform_device *dev)
-{
-#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
- do_gettimeofday(&timestamp[4]); /* 4: resume */
-#endif
-
- s5p_ace_resume_device(&s5p_ace_dev);
-
- return 0;
-}
-
-static struct platform_device_id s5p_ace_driver_ids[] = {
- {
- .name = "s5pv210-ace",
- .driver_data = TYPE_S5PV210,
- }, {
- .name = "exynos-ace",
- .driver_data = TYPE_EXYNOS,
- },
- {}
-};
-MODULE_DEVICE_TABLE(platform, s5p_ace_driver_ids);
-
-static struct platform_driver s5p_ace_driver = {
- .probe = s5p_ace_probe,
- .remove = s5p_ace_remove,
- .suspend = s5p_ace_suspend,
- .resume = s5p_ace_resume,
- .id_table = s5p_ace_driver_ids,
- .driver = {
- .name = S5P_ACE_DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init s5p_ace_init(void)
-{
- printk(KERN_INFO "S5P ACE Driver, (c) 2010 Samsung Electronics\n");
-
- return platform_driver_register(&s5p_ace_driver);
-}
-
-static void __exit s5p_ace_exit(void)
-{
- platform_driver_unregister(&s5p_ace_driver);
-}
-
-module_init(s5p_ace_init);
-module_exit(s5p_ace_exit);
-
-MODULE_DESCRIPTION("S5P ACE(Advanced Crypto Engine) support");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Dong Jin PARK");
-
diff --git a/drivers/crypto/ace.h b/drivers/crypto/ace.h
deleted file mode 100644
index 8d75d14..0000000
--- a/drivers/crypto/ace.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for ACE (Advanced Crypto Engine) for S5PV210/EXYNOS4210.
- *
- * Copyright (c) 2011 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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 _CRYPTO_S5P_ACE_H
-#define _CRYPTO_S5P_ACE_H
-
-
-/*****************************************************************
- Definition - Mechanism
-*****************************************************************/
-#define BC_MODE_ENC 0
-#define BC_MODE_DEC 1
-
-/*
- * Mechanism ID definition
- * : Mech. Type (8-bit) : Algorithm (8-bit) : Info (8-bit)
- * : Reserved (8-bit)
- */
-#define _MECH_ID_(_TYPE_, _NAME_, _MODE_) \
- ((((_TYPE_) & 0xFF) << 24) \
- | (((_NAME_) & 0xFF) << 16) \
- | (((_MODE_) & 0xFF) << 8) \
- | (((0) & 0xFF) << 0))
-
-#define MI_MASK _MECH_ID_(0xFF, 0xFF, 0xFF)
-#define MI_GET_TYPE(_t_) (((_t_) >> 24) & 0xFF)
-#define MI_GET_NAME(_n_) (((_n_) >> 16) & 0xFF)
-#define MI_GET_INFO(_i_) (((_i_) >> 8) & 0xFF)
-
-/* type (8-bits) */
-#define _TYPE_BC_ 0x01
-#define _TYPE_HASH_ 0x02
-#define _TYPE_MAC_ 0x03
-
-/* block cipher: algorithm (8-bits) */
-#define _NAME_DES_ 0x01
-#define _NAME_TDES_ 0x02
-#define _NAME_AES_ 0x03
-
-/* block cipher: mode of operation */
-#define _MODE_ECB_ 0x10
-#define _MODE_CBC_ 0x20
-#define _MODE_CTR_ 0x30
-
-/* block cipher: padding method */
-#define _PAD_NO_ 0x00
-/*#define _PAD_ZERO_ 0x01 */ /* Not supported */
-#define _PAD_PKCS7_ 0x02 /* Default padding method */
-/*#define _PAD_ANSIX923_ 0x03 */ /* Not supported */
-/*#define _PAD_ISO10126_ 0x04 */ /* Not supported */
-
-#define MI_GET_MODE(_m_) (((_m_) >> 8) & 0xF0)
-#define MI_GET_PADDING(_i_) (((_i_) >> 8) & 0x0F)
-
-#define MI_AES_ECB _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_ECB_ | _PAD_NO_)
-#define MI_AES_ECB_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_ECB_ | _PAD_PKCS7_)
-#define MI_AES_CBC _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_CBC_ | _PAD_NO_)
-#define MI_AES_CBC_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_CBC_ | _PAD_PKCS7_)
-#define MI_AES_CTR _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_CTR_ | _PAD_NO_)
-#define MI_AES_CTR_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
- _MODE_CTR_ | _PAD_PKCS7_)
-
-/* hash: algorithm (8-bits) */
-#define _NAME_HASH_SHA1_ 0x01
-#define _NAME_HASH_MD5_ 0x02
-
-#define MI_SHA1 _MECH_ID_(_TYPE_HASH_, _NAME_HASH_SHA1_, 0)
-#define MI_MD5 _MECH_ID_(_TYPE_HASH_, _NAME_HASH_MD5_, 0)
-
-/* hash: algorithm (8-bits) */
-#define _NAME_HMAC_SHA1_ 0x01
-
-#define MI_HMAC_SHA1 _MECH_ID_(_TYPE_MAC_, _NAME_HMAC_SHA1_, 0)
-
-/* Flag bits */
-#define FLAG_ENC_BIT (1 << 0)
-
-#endif /* _CRYPTO_S5P_ACE_H */
diff --git a/drivers/crypto/ace_sfr.h b/drivers/crypto/ace_sfr.h
deleted file mode 100644
index 367bc14..0000000
--- a/drivers/crypto/ace_sfr.h
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Header file for Advanced Crypto Engine - SFR definitions
- *
- * Copyright (c) 2011 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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 __ACE_SFR_H__
-#define __ACE_SFR_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*****************************************************************
- SFR Addresses
-*****************************************************************/
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_SFR_BASE (0xEA000000)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_SFR_BASE (0x10830000)
-#else
-#error No ARCH is defined.
-#endif
-
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_FC_OFFSET (0x0)
-#define ACE_AES_OFFSET (0x4000)
-#define ACE_TDES_OFFSET (0x5000)
-#define ACE_HASH_OFFSET (0x6000)
-#define ACE_PKA_OFFSET (0x7000)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_FC_OFFSET (0x0)
-#define ACE_AES_OFFSET (0x200)
-#define ACE_TDES_OFFSET (0x300)
-#define ACE_HASH_OFFSET (0x400)
-#define ACE_PKA_OFFSET (0x700)
-#endif
-
-/* Feed control registers */
-#define ACE_FC_INTSTAT (ACE_FC_OFFSET + 0x00)
-#define ACE_FC_INTENSET (ACE_FC_OFFSET + 0x04)
-#define ACE_FC_INTENCLR (ACE_FC_OFFSET + 0x08)
-#define ACE_FC_INTPEND (ACE_FC_OFFSET + 0x0C)
-#define ACE_FC_FIFOSTAT (ACE_FC_OFFSET + 0x10)
-#define ACE_FC_FIFOCTRL (ACE_FC_OFFSET + 0x14)
-#define ACE_FC_GLOBAL (ACE_FC_OFFSET + 0x18)
-#define ACE_FC_BRDMAS (ACE_FC_OFFSET + 0x20)
-#define ACE_FC_BRDMAL (ACE_FC_OFFSET + 0x24)
-#define ACE_FC_BRDMAC (ACE_FC_OFFSET + 0x28)
-#define ACE_FC_BTDMAS (ACE_FC_OFFSET + 0x30)
-#define ACE_FC_BTDMAL (ACE_FC_OFFSET + 0x34)
-#define ACE_FC_BTDMAC (ACE_FC_OFFSET + 0x38)
-#define ACE_FC_HRDMAS (ACE_FC_OFFSET + 0x40)
-#define ACE_FC_HRDMAL (ACE_FC_OFFSET + 0x44)
-#define ACE_FC_HRDMAC (ACE_FC_OFFSET + 0x48)
-#define ACE_FC_PKDMAS (ACE_FC_OFFSET + 0x50)
-#define ACE_FC_PKDMAL (ACE_FC_OFFSET + 0x54)
-#define ACE_FC_PKDMAC (ACE_FC_OFFSET + 0x58)
-#define ACE_FC_PKDMAO (ACE_FC_OFFSET + 0x5C)
-
-/* AES control registers */
-#define ACE_AES_CONTROL (ACE_AES_OFFSET + 0x00)
-#define ACE_AES_STATUS (ACE_AES_OFFSET + 0x04)
-
-#define ACE_AES_IN1 (ACE_AES_OFFSET + 0x10)
-#define ACE_AES_IN2 (ACE_AES_OFFSET + 0x14)
-#define ACE_AES_IN3 (ACE_AES_OFFSET + 0x18)
-#define ACE_AES_IN4 (ACE_AES_OFFSET + 0x1C)
-
-#define ACE_AES_OUT1 (ACE_AES_OFFSET + 0x20)
-#define ACE_AES_OUT2 (ACE_AES_OFFSET + 0x24)
-#define ACE_AES_OUT3 (ACE_AES_OFFSET + 0x28)
-#define ACE_AES_OUT4 (ACE_AES_OFFSET + 0x2C)
-
-#define ACE_AES_IV1 (ACE_AES_OFFSET + 0x30)
-#define ACE_AES_IV2 (ACE_AES_OFFSET + 0x34)
-#define ACE_AES_IV3 (ACE_AES_OFFSET + 0x38)
-#define ACE_AES_IV4 (ACE_AES_OFFSET + 0x3C)
-
-#define ACE_AES_CNT1 (ACE_AES_OFFSET + 0x40)
-#define ACE_AES_CNT2 (ACE_AES_OFFSET + 0x44)
-#define ACE_AES_CNT3 (ACE_AES_OFFSET + 0x48)
-#define ACE_AES_CNT4 (ACE_AES_OFFSET + 0x4C)
-
-#define ACE_AES_KEY1 (ACE_AES_OFFSET + 0x80)
-#define ACE_AES_KEY2 (ACE_AES_OFFSET + 0x84)
-#define ACE_AES_KEY3 (ACE_AES_OFFSET + 0x88)
-#define ACE_AES_KEY4 (ACE_AES_OFFSET + 0x8C)
-#define ACE_AES_KEY5 (ACE_AES_OFFSET + 0x90)
-#define ACE_AES_KEY6 (ACE_AES_OFFSET + 0x94)
-#define ACE_AES_KEY7 (ACE_AES_OFFSET + 0x98)
-#define ACE_AES_KEY8 (ACE_AES_OFFSET + 0x9C)
-
-/* TDES control registers */
-#define ACE_TDES_CONTROL (ACE_TDES_OFFSET + 0x00)
-#define ACE_TDES_STATUS (ACE_TDES_OFFSET + 0x04)
-
-#define ACE_TDES_KEY11 (ACE_TDES_OFFSET + 0x10)
-#define ACE_TDES_KEY12 (ACE_TDES_OFFSET + 0x14)
-#define ACE_TDES_KEY21 (ACE_TDES_OFFSET + 0x18)
-#define ACE_TDES_KEY22 (ACE_TDES_OFFSET + 0x1C)
-#define ACE_TDES_KEY31 (ACE_TDES_OFFSET + 0x20)
-#define ACE_TDES_KEY32 (ACE_TDES_OFFSET + 0x24)
-
-#define ACE_TDES_IV1 (ACE_TDES_OFFSET + 0x28)
-#define ACE_TDES_IV2 (ACE_TDES_OFFSET + 0x2C)
-
-#define ACE_TDES_IN1 (ACE_TDES_OFFSET + 0x30)
-#define ACE_TDES_IN2 (ACE_TDES_OFFSET + 0x34)
-
-#define ACE_TDES_OUT1 (ACE_TDES_OFFSET + 0x38)
-#define ACE_TDES_OUT2 (ACE_TDES_OFFSET + 0x3C)
-
-/* HASH control registers */
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_HASH_CONTROL (ACE_HASH_OFFSET + 0x00)
-#define ACE_HASH_CONTROL2 (ACE_HASH_OFFSET + 0x04)
-#define ACE_HASH_FIFO_MODE (ACE_HASH_OFFSET + 0x08)
-#define ACE_HASH_BYTESWAP (ACE_HASH_OFFSET + 0x0C)
-#define ACE_HASH_STATUS (ACE_HASH_OFFSET + 0x10)
-#define ACE_HASH_MSGSIZE_LOW (ACE_HASH_OFFSET + 0x14)
-#define ACE_HASH_MSGSIZE_HIGH (ACE_HASH_OFFSET + 0x18)
-
-#define ACE_HASH_IN1 (ACE_HASH_OFFSET + 0x20)
-#define ACE_HASH_IN2 (ACE_HASH_OFFSET + 0x24)
-#define ACE_HASH_IN3 (ACE_HASH_OFFSET + 0x28)
-#define ACE_HASH_IN4 (ACE_HASH_OFFSET + 0x2C)
-#define ACE_HASH_IN5 (ACE_HASH_OFFSET + 0x30)
-#define ACE_HASH_IN6 (ACE_HASH_OFFSET + 0x34)
-#define ACE_HASH_IN7 (ACE_HASH_OFFSET + 0x38)
-#define ACE_HASH_IN8 (ACE_HASH_OFFSET + 0x3C)
-
-#define ACE_HASH_SEED1 (ACE_HASH_OFFSET + 0x40)
-#define ACE_HASH_SEED2 (ACE_HASH_OFFSET + 0x44)
-#define ACE_HASH_SEED3 (ACE_HASH_OFFSET + 0x48)
-#define ACE_HASH_SEED4 (ACE_HASH_OFFSET + 0x4C)
-#define ACE_HASH_SEED5 (ACE_HASH_OFFSET + 0x50)
-
-#define ACE_HASH_RESULT1 (ACE_HASH_OFFSET + 0x60)
-#define ACE_HASH_RESULT2 (ACE_HASH_OFFSET + 0x64)
-#define ACE_HASH_RESULT3 (ACE_HASH_OFFSET + 0x68)
-#define ACE_HASH_RESULT4 (ACE_HASH_OFFSET + 0x6C)
-#define ACE_HASH_RESULT5 (ACE_HASH_OFFSET + 0x70)
-
-#define ACE_HASH_PRNG1 (ACE_HASH_OFFSET + 0x80)
-#define ACE_HASH_PRNG2 (ACE_HASH_OFFSET + 0x84)
-#define ACE_HASH_PRNG3 (ACE_HASH_OFFSET + 0x88)
-#define ACE_HASH_PRNG4 (ACE_HASH_OFFSET + 0x8C)
-#define ACE_HASH_PRNG5 (ACE_HASH_OFFSET + 0x90)
-
-#define ACE_HASH_IV1 (ACE_HASH_OFFSET + 0xA0)
-#define ACE_HASH_IV2 (ACE_HASH_OFFSET + 0xA4)
-#define ACE_HASH_IV3 (ACE_HASH_OFFSET + 0xA8)
-#define ACE_HASH_IV4 (ACE_HASH_OFFSET + 0xAC)
-#define ACE_HASH_IV5 (ACE_HASH_OFFSET + 0xB0)
-
-#define ACE_HASH_PRELEN_HIGH (ACE_HASH_OFFSET + 0xC0)
-#define ACE_HASH_PRELEN_LOW (ACE_HASH_OFFSET + 0xC4)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_HASH_CONTROL (ACE_HASH_OFFSET + 0x00)
-#define ACE_HASH_CONTROL2 (ACE_HASH_OFFSET + 0x04)
-#define ACE_HASH_FIFO_MODE (ACE_HASH_OFFSET + 0x08)
-#define ACE_HASH_BYTESWAP (ACE_HASH_OFFSET + 0x0C)
-#define ACE_HASH_STATUS (ACE_HASH_OFFSET + 0x10)
-#define ACE_HASH_MSGSIZE_LOW (ACE_HASH_OFFSET + 0x20)
-#define ACE_HASH_MSGSIZE_HIGH (ACE_HASH_OFFSET + 0x24)
-#define ACE_HASH_PRELEN_LOW (ACE_HASH_OFFSET + 0x28)
-#define ACE_HASH_PRELEN_HIGH (ACE_HASH_OFFSET + 0x2C)
-
-#define ACE_HASH_IN1 (ACE_HASH_OFFSET + 0x30)
-#define ACE_HASH_IN2 (ACE_HASH_OFFSET + 0x34)
-#define ACE_HASH_IN3 (ACE_HASH_OFFSET + 0x38)
-#define ACE_HASH_IN4 (ACE_HASH_OFFSET + 0x3C)
-#define ACE_HASH_IN5 (ACE_HASH_OFFSET + 0x40)
-#define ACE_HASH_IN6 (ACE_HASH_OFFSET + 0x44)
-#define ACE_HASH_IN7 (ACE_HASH_OFFSET + 0x48)
-#define ACE_HASH_IN8 (ACE_HASH_OFFSET + 0x4C)
-#define ACE_HASH_IN9 (ACE_HASH_OFFSET + 0x50)
-#define ACE_HASH_IN10 (ACE_HASH_OFFSET + 0x54)
-#define ACE_HASH_IN11 (ACE_HASH_OFFSET + 0x58)
-#define ACE_HASH_IN12 (ACE_HASH_OFFSET + 0x5C)
-#define ACE_HASH_IN13 (ACE_HASH_OFFSET + 0x60)
-#define ACE_HASH_IN14 (ACE_HASH_OFFSET + 0x64)
-#define ACE_HASH_IN15 (ACE_HASH_OFFSET + 0x68)
-#define ACE_HASH_IN16 (ACE_HASH_OFFSET + 0x6C)
-
-#define ACE_HASH_HMAC_KEY_IN1 (ACE_HASH_OFFSET + 0x70)
-#define ACE_HASH_HMAC_KEY_IN2 (ACE_HASH_OFFSET + 0x74)
-#define ACE_HASH_HMAC_KEY_IN3 (ACE_HASH_OFFSET + 0x78)
-#define ACE_HASH_HMAC_KEY_IN4 (ACE_HASH_OFFSET + 0x7C)
-#define ACE_HASH_HMAC_KEY_IN5 (ACE_HASH_OFFSET + 0x80)
-#define ACE_HASH_HMAC_KEY_IN6 (ACE_HASH_OFFSET + 0x84)
-#define ACE_HASH_HMAC_KEY_IN7 (ACE_HASH_OFFSET + 0x88)
-#define ACE_HASH_HMAC_KEY_IN8 (ACE_HASH_OFFSET + 0x8C)
-#define ACE_HASH_HMAC_KEY_IN9 (ACE_HASH_OFFSET + 0x90)
-#define ACE_HASH_HMAC_KEY_IN10 (ACE_HASH_OFFSET + 0x94)
-#define ACE_HASH_HMAC_KEY_IN11 (ACE_HASH_OFFSET + 0x98)
-#define ACE_HASH_HMAC_KEY_IN12 (ACE_HASH_OFFSET + 0x9C)
-#define ACE_HASH_HMAC_KEY_IN13 (ACE_HASH_OFFSET + 0xA0)
-#define ACE_HASH_HMAC_KEY_IN14 (ACE_HASH_OFFSET + 0xA4)
-#define ACE_HASH_HMAC_KEY_IN15 (ACE_HASH_OFFSET + 0xA8)
-#define ACE_HASH_HMAC_KEY_IN16 (ACE_HASH_OFFSET + 0xAC)
-
-#define ACE_HASH_IV1 (ACE_HASH_OFFSET + 0xB0)
-#define ACE_HASH_IV2 (ACE_HASH_OFFSET + 0xB4)
-#define ACE_HASH_IV3 (ACE_HASH_OFFSET + 0xB8)
-#define ACE_HASH_IV4 (ACE_HASH_OFFSET + 0xBC)
-#define ACE_HASH_IV5 (ACE_HASH_OFFSET + 0xC0)
-#define ACE_HASH_IV6 (ACE_HASH_OFFSET + 0xC4)
-#define ACE_HASH_IV7 (ACE_HASH_OFFSET + 0xC8)
-#define ACE_HASH_IV8 (ACE_HASH_OFFSET + 0xCC)
-
-#define ACE_HASH_RESULT1 (ACE_HASH_OFFSET + 0x100)
-#define ACE_HASH_RESULT2 (ACE_HASH_OFFSET + 0x104)
-#define ACE_HASH_RESULT3 (ACE_HASH_OFFSET + 0x108)
-#define ACE_HASH_RESULT4 (ACE_HASH_OFFSET + 0x10C)
-#define ACE_HASH_RESULT5 (ACE_HASH_OFFSET + 0x110)
-#define ACE_HASH_RESULT6 (ACE_HASH_OFFSET + 0x114)
-#define ACE_HASH_RESULT7 (ACE_HASH_OFFSET + 0x118)
-#define ACE_HASH_RESULT8 (ACE_HASH_OFFSET + 0x11C)
-
-#define ACE_HASH_SEED1 (ACE_HASH_OFFSET + 0x140)
-#define ACE_HASH_SEED2 (ACE_HASH_OFFSET + 0x144)
-#define ACE_HASH_SEED3 (ACE_HASH_OFFSET + 0x148)
-#define ACE_HASH_SEED4 (ACE_HASH_OFFSET + 0x14C)
-#define ACE_HASH_SEED5 (ACE_HASH_OFFSET + 0x150)
-
-#define ACE_HASH_PRNG1 (ACE_HASH_OFFSET + 0x160)
-#define ACE_HASH_PRNG2 (ACE_HASH_OFFSET + 0x164)
-#define ACE_HASH_PRNG3 (ACE_HASH_OFFSET + 0x168)
-#define ACE_HASH_PRNG4 (ACE_HASH_OFFSET + 0x16C)
-#define ACE_HASH_PRNG5 (ACE_HASH_OFFSET + 0x170)
-#endif
-
-/* PKA control registers */
-#define ACE_PKA_SFR0 (ACE_PKA_OFFSET + 0x00)
-#define ACE_PKA_SFR1 (ACE_PKA_OFFSET + 0x04)
-#define ACE_PKA_SFR2 (ACE_PKA_OFFSET + 0x08)
-#define ACE_PKA_SFR3 (ACE_PKA_OFFSET + 0x0C)
-#define ACE_PKA_SFR4 (ACE_PKA_OFFSET + 0x10)
-
-
-/*****************************************************************
- OFFSET
-*****************************************************************/
-
-/* ACE_FC_INT */
-#define ACE_FC_PKDMA (1 << 0)
-#define ACE_FC_HRDMA (1 << 1)
-#define ACE_FC_BTDMA (1 << 2)
-#define ACE_FC_BRDMA (1 << 3)
-#define ACE_FC_PRNG_ERROR (1 << 4)
-#define ACE_FC_MSG_DONE (1 << 5)
-#define ACE_FC_PRNG_DONE (1 << 6)
-#define ACE_FC_PARTIAL_DONE (1 << 7)
-
-/* ACE_FC_FIFOSTAT */
-#define ACE_FC_PKFIFO_EMPTY (1 << 0)
-#define ACE_FC_PKFIFO_FULL (1 << 1)
-#define ACE_FC_HRFIFO_EMPTY (1 << 2)
-#define ACE_FC_HRFIFO_FULL (1 << 3)
-#define ACE_FC_BTFIFO_EMPTY (1 << 4)
-#define ACE_FC_BTFIFO_FULL (1 << 5)
-#define ACE_FC_BRFIFO_EMPTY (1 << 6)
-#define ACE_FC_BRFIFO_FULL (1 << 7)
-
-/* ACE_FC_FIFOCTRL */
-#define ACE_FC_SELHASH_MASK (3 << 0)
-#define ACE_FC_SELHASH_EXOUT (0 << 0) /*independent source*/
-#define ACE_FC_SELHASH_BCIN (1 << 0) /*block cipher input*/
-#define ACE_FC_SELHASH_BCOUT (2 << 0) /*block cipher output*/
-#define ACE_FC_SELBC_MASK (1 << 2)
-#define ACE_FC_SELBC_AES (0 << 2) /* AES */
-#define ACE_FC_SELBC_DES (1 << 2) /* DES */
-
-/* ACE_FC_GLOBAL */
-#define ACE_FC_SSS_RESET (1 << 0)
-#define ACE_FC_DMA_RESET (1 << 1)
-#define ACE_FC_AES_RESET (1 << 2)
-#define ACE_FC_DES_RESET (1 << 3)
-#define ACE_FC_HASH_RESET (1 << 4)
-#define ACE_FC_AXI_ENDIAN_MASK (3 << 6)
-#define ACE_FC_AXI_ENDIAN_LE (0 << 6)
-#define ACE_FC_AXI_ENDIAN_BIBE (1 << 6)
-#define ACE_FC_AXI_ENDIAN_WIBE (2 << 6)
-
-/* Feed control - BRDMA control */
-#define ACE_FC_BRDMACFLUSH_OFF (0 << 0)
-#define ACE_FC_BRDMACFLUSH_ON (1 << 0)
-#define ACE_FC_BRDMACSWAP_ON (1 << 1)
-#define ACE_FC_BRDMACARPROT_MASK (0x7 << 2)
-#define ACE_FC_BRDMACARPROT_OFS (2)
-#define ACE_FC_BRDMACARCACHE_MASK (0xF << 5)
-#define ACE_FC_BRDMACARCACHE_OFS (5)
-
-/* Feed control - BTDMA control */
-#define ACE_FC_BTDMACFLUSH_OFF (0 << 0)
-#define ACE_FC_BTDMACFLUSH_ON (1 << 0)
-#define ACE_FC_BTDMACSWAP_ON (1 << 1)
-#define ACE_FC_BTDMACAWPROT_MASK (0x7 << 2)
-#define ACE_FC_BTDMACAWPROT_OFS (2)
-#define ACE_FC_BTDMACAWCACHE_MASK (0xF << 5)
-#define ACE_FC_BTDMACAWCACHE_OFS (5)
-
-/* Feed control - HRDMA control */
-#define ACE_FC_HRDMACFLUSH_OFF (0 << 0)
-#define ACE_FC_HRDMACFLUSH_ON (1 << 0)
-#define ACE_FC_HRDMACSWAP_ON (1 << 1)
-#define ACE_FC_HRDMACARPROT_MASK (0x7 << 2)
-#define ACE_FC_HRDMACARPROT_OFS (2)
-#define ACE_FC_HRDMACARCACHE_MASK (0xF << 5)
-#define ACE_FC_HRDMACARCACHE_OFS (5)
-
-/* Feed control - PKDMA control */
-#define ACE_FC_PKDMACBYTESWAP_ON (1 << 3)
-#define ACE_FC_PKDMACDESEND_ON (1 << 2)
-#define ACE_FC_PKDMACTRANSMIT_ON (1 << 1)
-#define ACE_FC_PKDMACFLUSH_ON (1 << 0)
-
-/* Feed control - PKDMA offset */
-#define ACE_FC_SRAMOFFSET_MASK (0xFFF)
-
-/* AES control */
-#define ACE_AES_MODE_MASK (1 << 0)
-#define ACE_AES_MODE_ENC (0 << 0)
-#define ACE_AES_MODE_DEC (1 << 0)
-#define ACE_AES_OPERMODE_MASK (3 << 1)
-#define ACE_AES_OPERMODE_ECB (0 << 1)
-#define ACE_AES_OPERMODE_CBC (1 << 1)
-#define ACE_AES_OPERMODE_CTR (2 << 1)
-#define ACE_AES_FIFO_MASK (1 << 3)
-#define ACE_AES_FIFO_OFF (0 << 3) /* CPU mode */
-#define ACE_AES_FIFO_ON (1 << 3) /* FIFO mode */
-#define ACE_AES_KEYSIZE_MASK (3 << 4)
-#define ACE_AES_KEYSIZE_128 (0 << 4)
-#define ACE_AES_KEYSIZE_192 (1 << 4)
-#define ACE_AES_KEYSIZE_256 (2 << 4)
-#define ACE_AES_KEYCNGMODE_MASK (1 << 6)
-#define ACE_AES_KEYCNGMODE_OFF (0 << 6)
-#define ACE_AES_KEYCNGMODE_ON (1 << 6)
-#define ACE_AES_SWAP_MASK (0x1F << 7)
-#define ACE_AES_SWAPKEY_OFF (0 << 7)
-#define ACE_AES_SWAPKEY_ON (1 << 7)
-#define ACE_AES_SWAPCNT_OFF (0 << 8)
-#define ACE_AES_SWAPCNT_ON (1 << 8)
-#define ACE_AES_SWAPIV_OFF (0 << 9)
-#define ACE_AES_SWAPIV_ON (1 << 9)
-#define ACE_AES_SWAPDO_OFF (0 << 10)
-#define ACE_AES_SWAPDO_ON (1 << 10)
-#define ACE_AES_SWAPDI_OFF (0 << 11)
-#define ACE_AES_SWAPDI_ON (1 << 11)
-#define ACE_AES_COUNTERSIZE_MASK (3 << 12)
-#define ACE_AES_COUNTERSIZE_128 (0 << 12)
-#define ACE_AES_COUNTERSIZE_64 (1 << 12)
-#define ACE_AES_COUNTERSIZE_32 (2 << 12)
-#define ACE_AES_COUNTERSIZE_16 (3 << 12)
-
-/* AES status */
-#define ACE_AES_OUTRDY_MASK (1 << 0)
-#define ACE_AES_OUTRDY_OFF (0 << 0)
-#define ACE_AES_OUTRDY_ON (1 << 0)
-#define ACE_AES_INRDY_MASK (1 << 1)
-#define ACE_AES_INRDY_OFF (0 << 1)
-#define ACE_AES_INRDY_ON (1 << 1)
-#define ACE_AES_BUSY_MASK (1 << 2)
-#define ACE_AES_BUSY_OFF (0 << 2)
-#define ACE_AES_BUSY_ON (1 << 2)
-
-/* TDES control */
-#define ACE_TDES_MODE_MASK (1 << 0)
-#define ACE_TDES_MODE_ENC (0 << 0)
-#define ACE_TDES_MODE_DEC (1 << 0)
-#define ACE_TDES_OPERMODE_MASK (1 << 1)
-#define ACE_TDES_OPERMODE_ECB (0 << 1)
-#define ACE_TDES_OPERMODE_CBC (1 << 1)
-#define ACE_TDES_SEL_MASK (3 << 3)
-#define ACE_TDES_SEL_DES (0 << 3)
-#define ACE_TDES_SEL_TDESEDE (1 << 3) /* TDES EDE mode */
-#define ACE_TDES_SEL_TDESEEE (3 << 3) /* TDES EEE mode */
-#define ACE_TDES_FIFO_MASK (1 << 5)
-#define ACE_TDES_FIFO_OFF (0 << 5) /* CPU mode */
-#define ACE_TDES_FIFO_ON (1 << 5) /* FIFO mode */
-#define ACE_TDES_SWAP_MASK (0xF << 6)
-#define ACE_TDES_SWAPKEY_OFF (0 << 6)
-#define ACE_TDES_SWAPKEY_ON (1 << 6)
-#define ACE_TDES_SWAPIV_OFF (0 << 7)
-#define ACE_TDES_SWAPIV_ON (1 << 7)
-#define ACE_TDES_SWAPDO_OFF (0 << 8)
-#define ACE_TDES_SWAPDO_ON (1 << 8)
-#define ACE_TDES_SWAPDI_OFF (0 << 9)
-#define ACE_TDES_SWAPDI_ON (1 << 9)
-
-/* TDES status */
-#define ACE_TDES_OUTRDY_MASK (1 << 0)
-#define ACE_TDES_OUTRDY_OFF (0 << 0)
-#define ACE_TDES_OUTRDY_ON (1 << 0)
-#define ACE_TDES_INRDY_MASK (1 << 1)
-#define ACE_TDES_INRDY_OFF (0 << 1)
-#define ACE_TDES_INRDY_ON (1 << 1)
-#define ACE_TDES_BUSY_MASK (1 << 2)
-#define ACE_TDES_BUSY_OFF (0 << 2)
-#define ACE_TDES_BUSY_ON (1 << 2)
-
-/* Hash control */
-#define ACE_HASH_ENGSEL_MASK (0xF << 0)
-#define ACE_HASH_ENGSEL_SHA1HASH (0x0 << 0)
-#define ACE_HASH_ENGSEL_SHA1HMAC (0x1 << 0)
-#define ACE_HASH_ENGSEL_SHA1HMACIN (0x1 << 0)
-#define ACE_HASH_ENGSEL_SHA1HMACOUT (0x9 << 0)
-#define ACE_HASH_ENGSEL_MD5HASH (0x2 << 0)
-#define ACE_HASH_ENGSEL_MD5HMAC (0x3 << 0)
-#define ACE_HASH_ENGSEL_MD5HMACIN (0x3 << 0)
-#define ACE_HASH_ENGSEL_MD5HMACOUT (0xB << 0)
-#define ACE_HASH_ENGSEL_SHA256HASH (0x4 << 0)
-#define ACE_HASH_ENGSEL_SHA256HMAC (0x5 << 0)
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_HASH_ENGSEL_PRNG (0x4 << 0)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_HASH_ENGSEL_PRNG (0x8 << 0)
-#endif
-#define ACE_HASH_STARTBIT_ON (1 << 4)
-#define ACE_HASH_USERIV_EN (1 << 5)
-
-/* Hash control 2 */
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_HASH_PAUSE_ON (1 << 3)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_HASH_PAUSE_ON (1 << 0)
-#endif
-
-/* Hash control - FIFO mode */
-#define ACE_HASH_FIFO_MASK (1 << 0)
-#define ACE_HASH_FIFO_OFF (0 << 0)
-#define ACE_HASH_FIFO_ON (1 << 0)
-
-/* Hash control - byte swap */
-#if defined(CONFIG_ARCH_S5PV210)
-#define ACE_HASH_SWAP_MASK (0x7 << 1)
-#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-#define ACE_HASH_SWAP_MASK (0xF << 0)
-#endif
-#define ACE_HASH_SWAPKEY_OFF (0 << 0)
-#define ACE_HASH_SWAPKEY_ON (1 << 0)
-#define ACE_HASH_SWAPIV_OFF (0 << 1)
-#define ACE_HASH_SWAPIV_ON (1 << 1)
-#define ACE_HASH_SWAPDO_OFF (0 << 2)
-#define ACE_HASH_SWAPDO_ON (1 << 2)
-#define ACE_HASH_SWAPDI_OFF (0 << 3)
-#define ACE_HASH_SWAPDI_ON (1 << 3)
-
-/* Hash status */
-#define ACE_HASH_BUFRDY_MASK (1 << 0)
-#define ACE_HASH_BUFRDY_OFF (0 << 0)
-#define ACE_HASH_BUFRDY_ON (1 << 0)
-#define ACE_HASH_SEEDSETTING_MASK (1 << 1)
-#define ACE_HASH_SEEDSETTING_OFF (0 << 1)
-#define ACE_HASH_SEEDSETTING_ON (1 << 1)
-#define ACE_HASH_PRNGBUSY_MASK (1 << 2)
-#define ACE_HASH_PRNGBUSY_OFF (0 << 2)
-#define ACE_HASH_PRNGBUSY_ON (1 << 2)
-#define ACE_HASH_PARTIALDONE_MASK (1 << 4)
-#define ACE_HASH_PARTIALDONE_OFF (0 << 4)
-#define ACE_HASH_PARTIALDONE_ON (1 << 4)
-#define ACE_HASH_PRNGDONE_MASK (1 << 5)
-#define ACE_HASH_PRNGDONE_OFF (0 << 5)
-#define ACE_HASH_PRNGDONE_ON (1 << 5)
-#define ACE_HASH_MSGDONE_MASK (1 << 6)
-#define ACE_HASH_MSGDONE_OFF (0 << 6)
-#define ACE_HASH_MSGDONE_ON (1 << 6)
-#define ACE_HASH_PRNGERROR_MASK (1 << 7)
-#define ACE_HASH_PRNGERROR_OFF (0 << 7)
-#define ACE_HASH_PRNGERROR_ON (1 << 7)
-
-/* To Do: SFRs for PKA */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 1891252..1d103f9 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -51,6 +51,7 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev)
union ce_io_threshold io_threshold;
u32 rand_num;
union ce_pe_dma_cfg pe_dma_cfg;
+ u32 device_ctrl;
writel(PPC4XX_BYTE_ORDER, dev->ce_base + CRYPTO4XX_BYTE_ORDER_CFG);
/* setup pe dma, include reset sg, pdr and pe, then release reset */
@@ -84,7 +85,9 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev)
writel(ring_size.w, dev->ce_base + CRYPTO4XX_RING_SIZE);
ring_ctrl.w = 0;
writel(ring_ctrl.w, dev->ce_base + CRYPTO4XX_RING_CTRL);
- writel(PPC4XX_DC_3DES_EN, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+ device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+ device_ctrl |= PPC4XX_DC_3DES_EN;
+ writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
writel(dev->gdr_pa, dev->ce_base + CRYPTO4XX_GATH_RING_BASE);
writel(dev->sdr_pa, dev->ce_base + CRYPTO4XX_SCAT_RING_BASE);
part_ring_size.w = 0;
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index a84250a..fe765f4 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -2744,10 +2744,8 @@ static int __init hifn_init(void)
unsigned int freq;
int err;
- if (sizeof(dma_addr_t) > 4) {
- printk(KERN_INFO "HIFN supports only 32-bit addresses.\n");
- return -EINVAL;
- }
+ /* HIFN supports only 32-bit addresses */
+ BUILD_BUG_ON(sizeof(dma_addr_t) != 4);
if (strncmp(hifn_pll_ref, "ext", 3) &&
strncmp(hifn_pll_ref, "pci", 3)) {
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 4c20c5b..8e9a8f0 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -914,7 +914,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
crypt->mode |= NPE_OP_NOT_IN_PLACE;
/* This was never tested by Intel
* for more than one dst buffer, I think. */
- BUG_ON(req->dst->length < nbytes);
req_ctx->dst = NULL;
if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
flags, DMA_FROM_DEVICE))
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index f53dd83..fe79635 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <crypto/internal/hash.h>
#include <crypto/sha.h>
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 2e5b204..8944dab 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -1,6 +1,6 @@
/* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support.
*
- * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2010, 2011 David S. Miller <davem@davemloft.net>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -31,8 +31,8 @@
#include "n2_core.h"
#define DRV_MODULE_NAME "n2_crypto"
-#define DRV_MODULE_VERSION "0.1"
-#define DRV_MODULE_RELDATE "April 29, 2010"
+#define DRV_MODULE_VERSION "0.2"
+#define DRV_MODULE_RELDATE "July 28, 2011"
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -1006,9 +1006,9 @@ static int n2_do_ecb(struct ablkcipher_request *req, bool encrypt)
spin_unlock_irqrestore(&qp->lock, flags);
+out:
put_cpu();
-out:
n2_chunk_complete(req, NULL);
return err;
}
@@ -1096,9 +1096,9 @@ static int n2_do_chaining(struct ablkcipher_request *req, bool encrypt)
spin_unlock_irqrestore(&qp->lock, flags);
+out:
put_cpu();
-out:
n2_chunk_complete(req, err ? NULL : final_iv_addr);
return err;
}
@@ -1823,22 +1823,17 @@ static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *de
static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
struct spu_mdesc_info *ip)
{
- const u64 *intr, *ino;
- int intr_len, ino_len;
+ const u64 *ino;
+ int ino_len;
int i;
- intr = mdesc_get_property(mdesc, node, "intr", &intr_len);
- if (!intr)
- return -ENODEV;
-
ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
- if (!ino)
+ if (!ino) {
+ printk("NO 'ino'\n");
return -ENODEV;
+ }
- if (intr_len != ino_len)
- return -EINVAL;
-
- ip->num_intrs = intr_len / sizeof(u64);
+ ip->num_intrs = ino_len / sizeof(u64);
ip->ino_table = kzalloc((sizeof(struct ino_blob) *
ip->num_intrs),
GFP_KERNEL);
@@ -1847,7 +1842,7 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
for (i = 0; i < ip->num_intrs; i++) {
struct ino_blob *b = &ip->ino_table[i];
- b->intr = intr[i];
+ b->intr = i + 1;
b->ino = ino[i];
}
@@ -2204,6 +2199,10 @@ static struct of_device_id n2_crypto_match[] = {
.name = "n2cp",
.compatible = "SUNW,vf-cwq",
},
+ {
+ .name = "n2cp",
+ .compatible = "SUNW,kt-cwq",
+ },
{},
};
@@ -2228,6 +2227,10 @@ static struct of_device_id n2_mau_match[] = {
.name = "ncp",
.compatible = "SUNW,vf-mau",
},
+ {
+ .name = "ncp",
+ .compatible = "SUNW,kt-mau",
+ },
{},
};
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index ba8f1ea..6399a8f 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -72,17 +72,20 @@
#define DEFAULT_TIMEOUT_INTERVAL HZ
-#define FLAGS_FINUP 0x0002
-#define FLAGS_FINAL 0x0004
-#define FLAGS_SG 0x0008
-#define FLAGS_SHA1 0x0010
-#define FLAGS_DMA_ACTIVE 0x0020
-#define FLAGS_OUTPUT_READY 0x0040
-#define FLAGS_INIT 0x0100
-#define FLAGS_CPU 0x0200
-#define FLAGS_HMAC 0x0400
-#define FLAGS_ERROR 0x0800
-#define FLAGS_BUSY 0x1000
+/* mostly device flags */
+#define FLAGS_BUSY 0
+#define FLAGS_FINAL 1
+#define FLAGS_DMA_ACTIVE 2
+#define FLAGS_OUTPUT_READY 3
+#define FLAGS_INIT 4
+#define FLAGS_CPU 5
+#define FLAGS_DMA_READY 6
+/* 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
@@ -144,7 +147,6 @@ struct omap_sham_dev {
int dma;
int dma_lch;
struct tasklet_struct done_task;
- struct tasklet_struct queue_task;
unsigned long flags;
struct crypto_queue queue;
@@ -223,7 +225,7 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req)
if (!hash)
return;
- if (likely(ctx->flags & FLAGS_SHA1)) {
+ if (likely(ctx->flags & BIT(FLAGS_SHA1))) {
/* SHA1 results are in big endian */
for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
hash[i] = be32_to_cpu(in[i]);
@@ -238,7 +240,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
clk_enable(dd->iclk);
- if (!(dd->flags & FLAGS_INIT)) {
+ if (!test_bit(FLAGS_INIT, &dd->flags)) {
omap_sham_write_mask(dd, SHA_REG_MASK,
SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
@@ -246,7 +248,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
SHA_REG_SYSSTATUS_RESETDONE))
return -ETIMEDOUT;
- dd->flags |= FLAGS_INIT;
+ set_bit(FLAGS_INIT, &dd->flags);
dd->err = 0;
}
@@ -269,7 +271,7 @@ static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
* Setting ALGO_CONST only for the first iteration
* and CLOSE_HASH only for the last one.
*/
- if (ctx->flags & FLAGS_SHA1)
+ if (ctx->flags & BIT(FLAGS_SHA1))
val |= SHA_REG_CTRL_ALGO;
if (!ctx->digcnt)
val |= SHA_REG_CTRL_ALGO_CONST;
@@ -301,7 +303,9 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
return -ETIMEDOUT;
if (final)
- ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
+ set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
+
+ set_bit(FLAGS_CPU, &dd->flags);
len32 = DIV_ROUND_UP(length, sizeof(u32));
@@ -334,9 +338,9 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
ctx->digcnt += length;
if (final)
- ctx->flags |= FLAGS_FINAL; /* catch last interrupt */
+ set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
- dd->flags |= FLAGS_DMA_ACTIVE;
+ set_bit(FLAGS_DMA_ACTIVE, &dd->flags);
omap_start_dma(dd->dma_lch);
@@ -392,7 +396,7 @@ static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
return -EINVAL;
}
- ctx->flags &= ~FLAGS_SG;
+ 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);
@@ -406,7 +410,7 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
omap_sham_append_sg(ctx);
- final = (ctx->flags & FLAGS_FINUP) && !ctx->total;
+ final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
ctx->bufcnt, ctx->digcnt, final);
@@ -452,7 +456,7 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
length = min(ctx->total, sg->length);
if (sg_is_last(sg)) {
- if (!(ctx->flags & FLAGS_FINUP)) {
+ if (!(ctx->flags & BIT(FLAGS_FINUP))) {
/* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */
tail = length & (SHA1_MD5_BLOCK_SIZE - 1);
/* without finup() we need one block to close hash */
@@ -467,12 +471,12 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
return -EINVAL;
}
- ctx->flags |= FLAGS_SG;
+ ctx->flags |= BIT(FLAGS_SG);
ctx->total -= length;
ctx->offset = length; /* offset where to start slow */
- final = (ctx->flags & FLAGS_FINUP) && !ctx->total;
+ 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);
@@ -495,7 +499,7 @@ 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);
- if (ctx->flags & FLAGS_SG) {
+ if (ctx->flags & BIT(FLAGS_SG)) {
dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
if (ctx->sg->length == ctx->offset) {
ctx->sg = sg_next(ctx->sg);
@@ -537,18 +541,18 @@ static int omap_sham_init(struct ahash_request *req)
crypto_ahash_digestsize(tfm));
if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
- ctx->flags |= FLAGS_SHA1;
+ ctx->flags |= BIT(FLAGS_SHA1);
ctx->bufcnt = 0;
ctx->digcnt = 0;
ctx->buflen = BUFLEN;
- if (tctx->flags & FLAGS_HMAC) {
+ if (tctx->flags & BIT(FLAGS_HMAC)) {
struct omap_sham_hmac_ctx *bctx = tctx->base;
memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
- ctx->flags |= FLAGS_HMAC;
+ ctx->flags |= BIT(FLAGS_HMAC);
}
return 0;
@@ -562,9 +566,9 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
int err;
dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
- ctx->total, ctx->digcnt, (ctx->flags & FLAGS_FINUP) != 0);
+ ctx->total, ctx->digcnt, (ctx->flags & BIT(FLAGS_FINUP)) != 0);
- if (ctx->flags & FLAGS_CPU)
+ if (ctx->flags & BIT(FLAGS_CPU))
err = omap_sham_update_cpu(dd);
else
err = omap_sham_update_dma_start(dd);
@@ -624,7 +628,7 @@ static int omap_sham_finish(struct ahash_request *req)
if (ctx->digcnt) {
omap_sham_copy_ready_hash(req);
- if (ctx->flags & FLAGS_HMAC)
+ if (ctx->flags & BIT(FLAGS_HMAC))
err = omap_sham_finish_hmac(req);
}
@@ -639,18 +643,23 @@ 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(ctx->dd->req, 1);
- if (ctx->flags & FLAGS_FINAL)
+ omap_sham_copy_hash(req, 1);
+ if (test_bit(FLAGS_FINAL, &dd->flags))
err = omap_sham_finish(req);
} else {
- ctx->flags |= FLAGS_ERROR;
+ ctx->flags |= BIT(FLAGS_ERROR);
}
+ /* 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);
- dd->flags &= ~FLAGS_BUSY;
if (req->base.complete)
req->base.complete(&req->base, err);
+
+ /* handle new request */
+ tasklet_schedule(&dd->done_task);
}
static int omap_sham_handle_queue(struct omap_sham_dev *dd,
@@ -658,21 +667,20 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
{
struct crypto_async_request *async_req, *backlog;
struct omap_sham_reqctx *ctx;
- struct ahash_request *prev_req;
unsigned long flags;
int err = 0, ret = 0;
spin_lock_irqsave(&dd->lock, flags);
if (req)
ret = ahash_enqueue_request(&dd->queue, req);
- if (dd->flags & FLAGS_BUSY) {
+ if (test_bit(FLAGS_BUSY, &dd->flags)) {
spin_unlock_irqrestore(&dd->lock, flags);
return ret;
}
backlog = crypto_get_backlog(&dd->queue);
async_req = crypto_dequeue_request(&dd->queue);
if (async_req)
- dd->flags |= FLAGS_BUSY;
+ set_bit(FLAGS_BUSY, &dd->flags);
spin_unlock_irqrestore(&dd->lock, flags);
if (!async_req)
@@ -682,16 +690,12 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
backlog->complete(backlog, -EINPROGRESS);
req = ahash_request_cast(async_req);
-
- prev_req = dd->req;
dd->req = req;
-
ctx = ahash_request_ctx(req);
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
ctx->op, req->nbytes);
-
err = omap_sham_hw_init(dd);
if (err)
goto err1;
@@ -712,18 +716,16 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
if (ctx->op == OP_UPDATE) {
err = omap_sham_update_req(dd);
- if (err != -EINPROGRESS && (ctx->flags & FLAGS_FINUP))
+ if (err != -EINPROGRESS && (ctx->flags & BIT(FLAGS_FINUP)))
/* no final() after finup() */
err = omap_sham_final_req(dd);
} else if (ctx->op == OP_FINAL) {
err = omap_sham_final_req(dd);
}
err1:
- if (err != -EINPROGRESS) {
+ if (err != -EINPROGRESS)
/* done_task will not finish it, so do it here */
omap_sham_finish_req(req, err);
- tasklet_schedule(&dd->queue_task);
- }
dev_dbg(dd->dev, "exit, err: %d\n", err);
@@ -752,7 +754,7 @@ static int omap_sham_update(struct ahash_request *req)
ctx->sg = req->src;
ctx->offset = 0;
- if (ctx->flags & FLAGS_FINUP) {
+ if (ctx->flags & BIT(FLAGS_FINUP)) {
if ((ctx->digcnt + ctx->bufcnt + ctx->total) < 9) {
/*
* OMAP HW accel works only with buffers >= 9
@@ -765,7 +767,7 @@ static int omap_sham_update(struct ahash_request *req)
/*
* faster to use CPU for short transfers
*/
- ctx->flags |= FLAGS_CPU;
+ ctx->flags |= BIT(FLAGS_CPU);
}
} else if (ctx->bufcnt + ctx->total < ctx->buflen) {
omap_sham_append_sg(ctx);
@@ -802,9 +804,9 @@ static int omap_sham_final(struct ahash_request *req)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
- ctx->flags |= FLAGS_FINUP;
+ ctx->flags |= BIT(FLAGS_FINUP);
- if (ctx->flags & FLAGS_ERROR)
+ if (ctx->flags & BIT(FLAGS_ERROR))
return 0; /* uncompleted hash is not needed */
/* OMAP HW accel works only with buffers >= 9 */
@@ -823,7 +825,7 @@ static int omap_sham_finup(struct ahash_request *req)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err1, err2;
- ctx->flags |= FLAGS_FINUP;
+ ctx->flags |= BIT(FLAGS_FINUP);
err1 = omap_sham_update(req);
if (err1 == -EINPROGRESS || err1 == -EBUSY)
@@ -895,7 +897,7 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
if (alg_base) {
struct omap_sham_hmac_ctx *bctx = tctx->base;
- tctx->flags |= FLAGS_HMAC;
+ tctx->flags |= BIT(FLAGS_HMAC);
bctx->shash = crypto_alloc_shash(alg_base, 0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(bctx->shash)) {
@@ -932,7 +934,7 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm)
crypto_free_shash(tctx->fallback);
tctx->fallback = NULL;
- if (tctx->flags & FLAGS_HMAC) {
+ if (tctx->flags & BIT(FLAGS_HMAC)) {
struct omap_sham_hmac_ctx *bctx = tctx->base;
crypto_free_shash(bctx->shash);
}
@@ -1036,51 +1038,46 @@ static struct ahash_alg algs[] = {
static void omap_sham_done_task(unsigned long data)
{
struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
- struct ahash_request *req = dd->req;
- struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
- int ready = 0, err = 0;
+ int err = 0;
- if (ctx->flags & FLAGS_OUTPUT_READY) {
- ctx->flags &= ~FLAGS_OUTPUT_READY;
- ready = 1;
+ if (!test_bit(FLAGS_BUSY, &dd->flags)) {
+ omap_sham_handle_queue(dd, NULL);
+ return;
}
- if (dd->flags & FLAGS_DMA_ACTIVE) {
- dd->flags &= ~FLAGS_DMA_ACTIVE;
- omap_sham_update_dma_stop(dd);
- if (!dd->err)
+ if (test_bit(FLAGS_CPU, &dd->flags)) {
+ if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
+ goto finish;
+ } else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
+ if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
+ omap_sham_update_dma_stop(dd);
+ if (dd->err) {
+ err = dd->err;
+ goto finish;
+ }
+ }
+ if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
+ /* hash or semi-hash ready */
+ clear_bit(FLAGS_DMA_READY, &dd->flags);
err = omap_sham_update_dma_start(dd);
+ if (err != -EINPROGRESS)
+ goto finish;
+ }
}
- err = dd->err ? : err;
-
- if (err != -EINPROGRESS && (ready || err)) {
- dev_dbg(dd->dev, "update done: err: %d\n", err);
- /* finish curent request */
- omap_sham_finish_req(req, err);
- /* start new request */
- omap_sham_handle_queue(dd, NULL);
- }
-}
-
-static void omap_sham_queue_task(unsigned long data)
-{
- struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
+ return;
- omap_sham_handle_queue(dd, NULL);
+finish:
+ dev_dbg(dd->dev, "update done: err: %d\n", err);
+ /* finish curent request */
+ omap_sham_finish_req(dd->req, err);
}
static irqreturn_t omap_sham_irq(int irq, void *dev_id)
{
struct omap_sham_dev *dd = dev_id;
- struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
-
- if (!ctx) {
- dev_err(dd->dev, "unknown interrupt.\n");
- return IRQ_HANDLED;
- }
- if (unlikely(ctx->flags & FLAGS_FINAL))
+ if (unlikely(test_bit(FLAGS_FINAL, &dd->flags)))
/* final -> allow device to go to power-saving mode */
omap_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH);
@@ -1088,8 +1085,12 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id)
SHA_REG_CTRL_OUTPUT_READY);
omap_sham_read(dd, SHA_REG_CTRL);
- ctx->flags |= FLAGS_OUTPUT_READY;
- dd->err = 0;
+ if (!test_bit(FLAGS_BUSY, &dd->flags)) {
+ dev_warn(dd->dev, "Interrupt when no active requests.\n");
+ return IRQ_HANDLED;
+ }
+
+ set_bit(FLAGS_OUTPUT_READY, &dd->flags);
tasklet_schedule(&dd->done_task);
return IRQ_HANDLED;
@@ -1102,9 +1103,10 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
if (ch_status != OMAP_DMA_BLOCK_IRQ) {
pr_err("omap-sham DMA error status: 0x%hx\n", ch_status);
dd->err = -EIO;
- dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
+ clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */
}
+ set_bit(FLAGS_DMA_READY, &dd->flags);
tasklet_schedule(&dd->done_task);
}
@@ -1151,7 +1153,6 @@ static int __devinit omap_sham_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dd->list);
spin_lock_init(&dd->lock);
tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd);
- tasklet_init(&dd->queue_task, omap_sham_queue_task, (unsigned long)dd);
crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH);
dd->irq = -1;
@@ -1260,7 +1261,6 @@ static int __devexit omap_sham_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(algs); i++)
crypto_unregister_ahash(&algs[i]);
tasklet_kill(&dd->done_task);
- tasklet_kill(&dd->queue_task);
iounmap(dd->io_base);
clk_put(dd->iclk);
omap_sham_dma_cleanup(dd);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index db33d30..87500e6 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -508,10 +508,8 @@ static int __init padlock_init(void)
int ret;
struct cpuinfo_x86 *c = &cpu_data(0);
- if (!cpu_has_xcrypt) {
- printk(KERN_NOTICE PFX "VIA PadLock not detected.\n");
+ if (!cpu_has_xcrypt)
return -ENODEV;
- }
if (!cpu_has_xcrypt_enabled) {
printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
@@ -561,4 +559,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
-MODULE_ALIAS("aes");
+MODULE_ALIAS_CRYPTO("aes");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 06bdb4b..710f3cb 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -593,7 +593,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
-MODULE_ALIAS("sha1-all");
-MODULE_ALIAS("sha256-all");
-MODULE_ALIAS("sha1-padlock");
-MODULE_ALIAS("sha256-padlock");
+MODULE_ALIAS_CRYPTO("sha1-all");
+MODULE_ALIAS_CRYPTO("sha256-all");
+MODULE_ALIAS_CRYPTO("sha1-padlock");
+MODULE_ALIAS_CRYPTO("sha256-padlock");
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index 230b5b8..a2b553e 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/rtnetlink.h>
@@ -1241,8 +1242,8 @@ static void spacc_spacc_complete(unsigned long data)
spin_unlock_irqrestore(&engine->hw_lock, flags);
list_for_each_entry_safe(req, tmp, &completed, list) {
- req->complete(req);
list_del(&req->list);
+ req->complete(req);
}
}
@@ -1657,10 +1658,33 @@ static struct spacc_alg l2_engine_algs[] = {
},
};
-static int __devinit spacc_probe(struct platform_device *pdev,
- unsigned max_ctxs, size_t cipher_pg_sz,
- size_t hash_pg_sz, size_t fifo_sz,
- struct spacc_alg *algs, size_t num_algs)
+#ifdef CONFIG_OF
+static const struct of_device_id spacc_of_id_table[] = {
+ { .compatible = "picochip,spacc-ipsec" },
+ { .compatible = "picochip,spacc-l2" },
+ {}
+};
+#else /* CONFIG_OF */
+#define spacc_of_id_table NULL
+#endif /* CONFIG_OF */
+
+static bool spacc_is_compatible(struct platform_device *pdev,
+ const char *spacc_type)
+{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
+
+ if (platid && !strcmp(platid->name, spacc_type))
+ return true;
+
+#ifdef CONFIG_OF
+ if (of_device_is_compatible(pdev->dev.of_node, spacc_type))
+ return true;
+#endif /* CONFIG_OF */
+
+ return false;
+}
+
+static int __devinit spacc_probe(struct platform_device *pdev)
{
int i, err, ret = -EINVAL;
struct resource *mem, *irq;
@@ -1669,13 +1693,25 @@ static int __devinit spacc_probe(struct platform_device *pdev,
if (!engine)
return -ENOMEM;
- engine->max_ctxs = max_ctxs;
- engine->cipher_pg_sz = cipher_pg_sz;
- engine->hash_pg_sz = hash_pg_sz;
- engine->fifo_sz = fifo_sz;
- engine->algs = algs;
- engine->num_algs = num_algs;
- engine->name = dev_name(&pdev->dev);
+ if (spacc_is_compatible(pdev, "picochip,spacc-ipsec")) {
+ engine->max_ctxs = SPACC_CRYPTO_IPSEC_MAX_CTXS;
+ engine->cipher_pg_sz = SPACC_CRYPTO_IPSEC_CIPHER_PG_SZ;
+ engine->hash_pg_sz = SPACC_CRYPTO_IPSEC_HASH_PG_SZ;
+ engine->fifo_sz = SPACC_CRYPTO_IPSEC_FIFO_SZ;
+ engine->algs = ipsec_engine_algs;
+ engine->num_algs = ARRAY_SIZE(ipsec_engine_algs);
+ } else if (spacc_is_compatible(pdev, "picochip,spacc-l2")) {
+ engine->max_ctxs = SPACC_CRYPTO_L2_MAX_CTXS;
+ engine->cipher_pg_sz = SPACC_CRYPTO_L2_CIPHER_PG_SZ;
+ engine->hash_pg_sz = SPACC_CRYPTO_L2_HASH_PG_SZ;
+ engine->fifo_sz = SPACC_CRYPTO_L2_FIFO_SZ;
+ engine->algs = l2_engine_algs;
+ engine->num_algs = ARRAY_SIZE(l2_engine_algs);
+ } else {
+ return -EINVAL;
+ }
+
+ engine->name = dev_name(&pdev->dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -1711,7 +1747,7 @@ static int __devinit spacc_probe(struct platform_device *pdev,
spin_lock_init(&engine->hw_lock);
- engine->clk = clk_get(&pdev->dev, NULL);
+ engine->clk = clk_get(&pdev->dev, "ref");
if (IS_ERR(engine->clk)) {
dev_info(&pdev->dev, "clk unavailable\n");
device_remove_file(&pdev->dev, &dev_attr_stat_irq_thresh);
@@ -1800,72 +1836,33 @@ static int __devexit spacc_remove(struct platform_device *pdev)
return 0;
}
-static int __devinit ipsec_probe(struct platform_device *pdev)
-{
- return spacc_probe(pdev, SPACC_CRYPTO_IPSEC_MAX_CTXS,
- SPACC_CRYPTO_IPSEC_CIPHER_PG_SZ,
- SPACC_CRYPTO_IPSEC_HASH_PG_SZ,
- SPACC_CRYPTO_IPSEC_FIFO_SZ, ipsec_engine_algs,
- ARRAY_SIZE(ipsec_engine_algs));
-}
-
-static struct platform_driver ipsec_driver = {
- .probe = ipsec_probe,
- .remove = __devexit_p(spacc_remove),
- .driver = {
- .name = "picoxcell-ipsec",
-#ifdef CONFIG_PM
- .pm = &spacc_pm_ops,
-#endif /* CONFIG_PM */
- },
+static const struct platform_device_id spacc_id_table[] = {
+ { "picochip,spacc-ipsec", },
+ { "picochip,spacc-l2", },
};
-static int __devinit l2_probe(struct platform_device *pdev)
-{
- return spacc_probe(pdev, SPACC_CRYPTO_L2_MAX_CTXS,
- SPACC_CRYPTO_L2_CIPHER_PG_SZ,
- SPACC_CRYPTO_L2_HASH_PG_SZ, SPACC_CRYPTO_L2_FIFO_SZ,
- l2_engine_algs, ARRAY_SIZE(l2_engine_algs));
-}
-
-static struct platform_driver l2_driver = {
- .probe = l2_probe,
+static struct platform_driver spacc_driver = {
+ .probe = spacc_probe,
.remove = __devexit_p(spacc_remove),
.driver = {
- .name = "picoxcell-l2",
+ .name = "picochip,spacc",
#ifdef CONFIG_PM
.pm = &spacc_pm_ops,
#endif /* CONFIG_PM */
+ .of_match_table = spacc_of_id_table,
},
+ .id_table = spacc_id_table,
};
static int __init spacc_init(void)
{
- int ret = platform_driver_register(&ipsec_driver);
- if (ret) {
- pr_err("failed to register ipsec spacc driver");
- goto out;
- }
-
- ret = platform_driver_register(&l2_driver);
- if (ret) {
- pr_err("failed to register l2 spacc driver");
- goto l2_failed;
- }
-
- return 0;
-
-l2_failed:
- platform_driver_unregister(&ipsec_driver);
-out:
- return ret;
+ return platform_driver_register(&spacc_driver);
}
module_init(spacc_init);
static void __exit spacc_exit(void)
{
- platform_driver_unregister(&ipsec_driver);
- platform_driver_unregister(&l2_driver);
+ platform_driver_unregister(&spacc_driver);
}
module_exit(spacc_exit);
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 854e263..90c76fc 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1,7 +1,7 @@
/*
* talitos - Freescale Integrated Security Engine (SEC) device driver
*
- * Copyright (c) 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright (c) 2008-2011 Freescale Semiconductor, Inc.
*
* Scatterlist Crypto API glue code copied from files with the following:
* Copyright (c) 2006-2007 Herbert Xu <herbert@gondor.apana.org.au>
@@ -282,6 +282,7 @@ static int init_device(struct device *dev)
/**
* talitos_submit - submits a descriptor to the device for processing
* @dev: the SEC device to be used
+ * @ch: the SEC device channel to be used
* @desc: the descriptor to be processed by the device
* @callback: whom to call when processing is complete
* @context: a handle for use by caller (optional)
@@ -290,7 +291,7 @@ static int init_device(struct device *dev)
* callback must check err and feedback in descriptor header
* for device processing status.
*/
-static int talitos_submit(struct device *dev, struct talitos_desc *desc,
+static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
void (*callback)(struct device *dev,
struct talitos_desc *desc,
void *context, int error),
@@ -298,15 +299,9 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
{
struct talitos_private *priv = dev_get_drvdata(dev);
struct talitos_request *request;
- unsigned long flags, ch;
+ unsigned long flags;
int head;
- /* select done notification */
- desc->hdr |= DESC_HDR_DONE_NOTIFY;
-
- /* emulate SEC's round-robin channel fifo polling scheme */
- ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1);
-
spin_lock_irqsave(&priv->chan[ch].head_lock, flags);
if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) {
@@ -421,7 +416,7 @@ static void talitos_done(unsigned long data)
/*
* locate current (offending) descriptor
*/
-static struct talitos_desc *current_desc(struct device *dev, int ch)
+static u32 current_desc_hdr(struct device *dev, int ch)
{
struct talitos_private *priv = dev_get_drvdata(dev);
int tail = priv->chan[ch].tail;
@@ -433,23 +428,25 @@ static struct talitos_desc *current_desc(struct device *dev, int ch)
tail = (tail + 1) & (priv->fifo_len - 1);
if (tail == priv->chan[ch].tail) {
dev_err(dev, "couldn't locate current descriptor\n");
- return NULL;
+ return 0;
}
}
- return priv->chan[ch].fifo[tail].desc;
+ return priv->chan[ch].fifo[tail].desc->hdr;
}
/*
* user diagnostics; report root cause of error based on execution unit status
*/
-static void report_eu_error(struct device *dev, int ch,
- struct talitos_desc *desc)
+static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
{
struct talitos_private *priv = dev_get_drvdata(dev);
int i;
- switch (desc->hdr & DESC_HDR_SEL0_MASK) {
+ if (!desc_hdr)
+ desc_hdr = in_be32(priv->reg + TALITOS_DESCBUF(ch));
+
+ switch (desc_hdr & DESC_HDR_SEL0_MASK) {
case DESC_HDR_SEL0_AFEU:
dev_err(dev, "AFEUISR 0x%08x_%08x\n",
in_be32(priv->reg + TALITOS_AFEUISR),
@@ -493,7 +490,7 @@ static void report_eu_error(struct device *dev, int ch,
break;
}
- switch (desc->hdr & DESC_HDR_SEL1_MASK) {
+ switch (desc_hdr & DESC_HDR_SEL1_MASK) {
case DESC_HDR_SEL1_MDEUA:
case DESC_HDR_SEL1_MDEUB:
dev_err(dev, "MDEUISR 0x%08x_%08x\n",
@@ -555,7 +552,7 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
if (v_lo & TALITOS_CCPSR_LO_IEU)
dev_err(dev, "invalid execution unit error\n");
if (v_lo & TALITOS_CCPSR_LO_EU)
- report_eu_error(dev, ch, current_desc(dev, ch));
+ report_eu_error(dev, ch, current_desc_hdr(dev, ch));
if (v_lo & TALITOS_CCPSR_LO_GB)
dev_err(dev, "gather boundary error\n");
if (v_lo & TALITOS_CCPSR_LO_GRL)
@@ -706,6 +703,7 @@ static void talitos_unregister_rng(struct device *dev)
struct talitos_ctx {
struct device *dev;
+ int ch;
__be32 desc_hdr_template;
u8 key[TALITOS_MAX_KEY_SIZE];
u8 iv[TALITOS_MAX_IV_LENGTH];
@@ -1117,7 +1115,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
DMA_FROM_DEVICE);
- ret = talitos_submit(dev, desc, callback, areq);
+ ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
ipsec_esp_unmap(dev, edesc, areq);
kfree(edesc);
@@ -1382,22 +1380,11 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
const u8 *key, unsigned int keylen)
{
struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
- struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher);
-
- if (keylen > TALITOS_MAX_KEY_SIZE)
- goto badkey;
-
- if (keylen < alg->min_keysize || keylen > alg->max_keysize)
- goto badkey;
memcpy(&ctx->key, key, keylen);
ctx->keylen = keylen;
return 0;
-
-badkey:
- crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
- return -EINVAL;
}
static void common_nonsnoop_unmap(struct device *dev,
@@ -1433,7 +1420,6 @@ static void ablkcipher_done(struct device *dev,
static int common_nonsnoop(struct talitos_edesc *edesc,
struct ablkcipher_request *areq,
- u8 *giv,
void (*callback) (struct device *dev,
struct talitos_desc *desc,
void *context, int error))
@@ -1453,7 +1439,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc,
/* cipher iv */
ivsize = crypto_ablkcipher_ivsize(cipher);
- map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0,
+ map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, areq->info, 0,
DMA_TO_DEVICE);
/* cipher key */
@@ -1524,7 +1510,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc,
to_talitos_ptr(&desc->ptr[6], 0);
desc->ptr[6].j_extent = 0;
- ret = talitos_submit(dev, desc, callback, areq);
+ ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
common_nonsnoop_unmap(dev, edesc, areq);
kfree(edesc);
@@ -1556,7 +1542,7 @@ static int ablkcipher_encrypt(struct ablkcipher_request *areq)
/* set encrypt */
edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
- return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+ return common_nonsnoop(edesc, areq, ablkcipher_done);
}
static int ablkcipher_decrypt(struct ablkcipher_request *areq)
@@ -1572,7 +1558,7 @@ static int ablkcipher_decrypt(struct ablkcipher_request *areq)
edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
- return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
+ return common_nonsnoop(edesc, areq, ablkcipher_done);
}
static void common_nonsnoop_hash_unmap(struct device *dev,
@@ -1703,7 +1689,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* last DWORD empty */
desc->ptr[6] = zero_entry;
- ret = talitos_submit(dev, desc, callback, areq);
+ ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
common_nonsnoop_hash_unmap(dev, edesc, areq);
kfree(edesc);
@@ -2244,6 +2230,7 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
struct crypto_alg *alg = tfm->__crt_alg;
struct talitos_crypto_alg *talitos_alg;
struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct talitos_private *priv;
if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
talitos_alg = container_of(__crypto_ahash_alg(alg),
@@ -2256,9 +2243,17 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
/* update context with ptr to dev */
ctx->dev = talitos_alg->dev;
+ /* assign SEC channel to tfm in round-robin fashion */
+ priv = dev_get_drvdata(ctx->dev);
+ ctx->ch = atomic_inc_return(&priv->last_chan) &
+ (priv->num_channels - 1);
+
/* copy descriptor header template value */
ctx->desc_hdr_template = talitos_alg->algt.desc_hdr_template;
+ /* select done notification */
+ ctx->desc_hdr_template |= DESC_HDR_DONE_NOTIFY;
+
return 0;
}
@@ -2389,6 +2384,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
break;
default:
dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
+ kfree(t_alg);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index af1a17d..203361e 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -41,7 +41,7 @@ config EDAC_DEBUG
config EDAC_DECODE_MCE
tristate "Decode MCEs in human-readable form (only on AMD for now)"
- depends on CPU_SUP_AMD && X86_MCE
+ depends on CPU_SUP_AMD && X86_MCE_AMD
default y
---help---
Enable this option if you want to decode Machine Check Exceptions
@@ -71,9 +71,6 @@ config EDAC_MM_EDAC
occurred so that a particular failing memory module can be
replaced. If unsure, select 'Y'.
-config EDAC_MCE
- bool
-
config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h"
depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE
@@ -173,8 +170,7 @@ config EDAC_I5400
config EDAC_I7CORE
tristate "Intel i7 Core (Nehalem) processors"
- depends on EDAC_MM_EDAC && PCI && X86
- select EDAC_MCE
+ depends on EDAC_MM_EDAC && PCI && X86 && X86_MCE_INTEL
help
Support for error detection and correction the Intel
i7 Core (Nehalem) Integrated Memory Controller that exists on
@@ -216,6 +212,14 @@ config EDAC_I7300
Support for error detection and correction the Intel
Clarksboro MCH (Intel 7300 chipset).
+config EDAC_SBRIDGE
+ tristate "Intel Sandy-Bridge Integrated MC"
+ depends on EDAC_MM_EDAC && PCI && X86 && X86_MCE_INTEL
+ depends on EXPERIMENTAL
+ help
+ Support for error detection and correction the Intel
+ Sandy Bridge Integrated Memory Controller.
+
config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx"
depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 3e23913..196a63d 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -8,7 +8,6 @@
obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
-obj-$(CONFIG_EDAC_MCE) += edac_mce.o
edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
edac_core-y += edac_module.o edac_device_sysfs.o
@@ -29,6 +28,7 @@ obj-$(CONFIG_EDAC_I5100) += i5100_edac.o
obj-$(CONFIG_EDAC_I5400) += i5400_edac.o
obj-$(CONFIG_EDAC_I7300) += i7300_edac.o
obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
+obj-$(CONFIG_EDAC_SBRIDGE) += sb_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index feb2d10..a9d5482 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -114,10 +114,22 @@ static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
}
+/*
+ * Select DCT to which PCI cfg accesses are routed
+ */
+static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
+{
+ u32 reg = 0;
+
+ amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
+ reg &= 0xfffffffe;
+ reg |= dct;
+ amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
+}
+
static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
const char *func)
{
- u32 reg = 0;
u8 dct = 0;
if (addr >= 0x140 && addr <= 0x1a0) {
@@ -125,10 +137,7 @@ static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
addr -= 0x100;
}
- amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
- reg &= 0xfffffffe;
- reg |= dct;
- amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
+ f15h_select_dct(pvt, dct);
return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
}
@@ -195,6 +204,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
if (boot_cpu_data.x86 == 0xf)
min_scrubrate = 0x0;
+ /* F15h Erratum #505 */
+ if (boot_cpu_data.x86 == 0x15)
+ f15h_select_dct(pvt, 0);
+
return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
}
@@ -204,6 +217,10 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
u32 scrubval = 0;
int i, retval = -EINVAL;
+ /* F15h Erratum #505 */
+ if (boot_cpu_data.x86 == 0x15)
+ f15h_select_dct(pvt, 0);
+
amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
scrubval = scrubval & 0x001F;
@@ -748,10 +765,10 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
* Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
* are ECC capable.
*/
-static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
+static unsigned long amd64_determine_edac_cap(struct amd64_pvt *pvt)
{
u8 bit;
- enum dev_type edac_cap = EDAC_FLAG_NONE;
+ unsigned long edac_cap = EDAC_FLAG_NONE;
bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
? 19
@@ -1950,11 +1967,9 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
amd64_handle_ue(mci, m);
}
-void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
+void amd64_decode_bus_error(int node_id, struct mce *m)
{
- struct mem_ctl_info *mci = mcis[node_id];
-
- __amd64_decode_bus_error(mci, m);
+ __amd64_decode_bus_error(mcis[node_id], m);
}
/*
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index db1df59..9a6a274 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
@@ -140,7 +140,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
if (of_node_to_nid(np) != priv->node)
continue;
csrow->first_page = r.start >> PAGE_SHIFT;
- csrow->nr_pages = (r.end - r.start + 1) >> PAGE_SHIFT;
+ csrow->nr_pages = resource_size(&r) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
csrow->mtype = MEM_XDR;
csrow->edac_mode = EDAC_SECDED;
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index a687a0d..a774c0d 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -90,6 +90,7 @@ enum apimask_bits {
ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H |
APIMASK_ECC_UE_L | APIMASK_ECC_CE_L),
};
+#define APIMASK_ADI(n) CPC925_BIT(((n)+1))
/************************************************************
* Processor Interface Exception Register (APIEXCP)
@@ -581,16 +582,73 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
}
/******************** CPU err device********************************/
+static u32 cpc925_cpu_mask_disabled(void)
+{
+ struct device_node *cpus;
+ struct device_node *cpunode = NULL;
+ static u32 mask = 0;
+
+ /* use cached value if available */
+ if (mask != 0)
+ return mask;
+
+ mask = APIMASK_ADI0 | APIMASK_ADI1;
+
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == NULL) {
+ cpc925_printk(KERN_DEBUG, "No /cpus node !\n");
+ return 0;
+ }
+
+ while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) {
+ const u32 *reg = of_get_property(cpunode, "reg", NULL);
+
+ if (strcmp(cpunode->type, "cpu")) {
+ cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name);
+ continue;
+ }
+
+ if (reg == NULL || *reg > 2) {
+ cpc925_printk(KERN_ERR, "Bad reg value at %s\n", cpunode->full_name);
+ continue;
+ }
+
+ mask &= ~APIMASK_ADI(*reg);
+ }
+
+ if (mask != (APIMASK_ADI0 | APIMASK_ADI1)) {
+ /* We assume that each CPU sits on it's own PI and that
+ * for present CPUs the reg property equals to the PI
+ * interface id */
+ cpc925_printk(KERN_WARNING,
+ "Assuming PI id is equal to CPU MPIC id!\n");
+ }
+
+ of_node_put(cpunode);
+ of_node_put(cpus);
+
+ return mask;
+}
+
/* Enable CPU Errors detection */
static void cpc925_cpu_init(struct cpc925_dev_info *dev_info)
{
u32 apimask;
+ u32 cpumask;
apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET);
- if ((apimask & CPU_MASK_ENABLE) == 0) {
- apimask |= CPU_MASK_ENABLE;
- __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET);
+
+ cpumask = cpc925_cpu_mask_disabled();
+ if (apimask & cpumask) {
+ cpc925_printk(KERN_WARNING, "CPU(s) not present, "
+ "but enabled in APIMASK, disabling\n");
+ apimask &= ~cpumask;
}
+
+ if ((apimask & CPU_MASK_ENABLE) == 0)
+ apimask |= CPU_MASK_ENABLE;
+
+ __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET);
}
/* Disable CPU Errors detection */
@@ -622,6 +680,9 @@ static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev)
if ((apiexcp & CPU_EXCP_DETECTED) == 0)
return;
+ if ((apiexcp & ~cpc925_cpu_mask_disabled()) == 0)
+ return;
+
apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET);
cpc925_printk(KERN_INFO, "Processor Interface Fault\n"
"Processor Interface register dump:\n");
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 55b8278..fe90cd4 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -34,11 +34,10 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
+#include <linux/edac.h>
-#define EDAC_MC_LABEL_LEN 31
#define EDAC_DEVICE_NAME_LEN 31
#define EDAC_ATTRIB_VALUE_LEN 15
-#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT))
@@ -101,353 +100,6 @@ extern int edac_debug_level;
#define edac_dev_name(dev) (dev)->dev_name
-/* memory devices */
-enum dev_type {
- DEV_UNKNOWN = 0,
- DEV_X1,
- DEV_X2,
- DEV_X4,
- DEV_X8,
- DEV_X16,
- DEV_X32, /* Do these parts exist? */
- DEV_X64 /* Do these parts exist? */
-};
-
-#define DEV_FLAG_UNKNOWN BIT(DEV_UNKNOWN)
-#define DEV_FLAG_X1 BIT(DEV_X1)
-#define DEV_FLAG_X2 BIT(DEV_X2)
-#define DEV_FLAG_X4 BIT(DEV_X4)
-#define DEV_FLAG_X8 BIT(DEV_X8)
-#define DEV_FLAG_X16 BIT(DEV_X16)
-#define DEV_FLAG_X32 BIT(DEV_X32)
-#define DEV_FLAG_X64 BIT(DEV_X64)
-
-/* memory types */
-enum mem_type {
- MEM_EMPTY = 0, /* Empty csrow */
- MEM_RESERVED, /* Reserved csrow type */
- MEM_UNKNOWN, /* Unknown csrow type */
- MEM_FPM, /* Fast page mode */
- MEM_EDO, /* Extended data out */
- MEM_BEDO, /* Burst Extended data out */
- MEM_SDR, /* Single data rate SDRAM */
- MEM_RDR, /* Registered single data rate SDRAM */
- MEM_DDR, /* Double data rate SDRAM */
- MEM_RDDR, /* Registered Double data rate SDRAM */
- MEM_RMBS, /* Rambus DRAM */
- MEM_DDR2, /* DDR2 RAM */
- MEM_FB_DDR2, /* fully buffered DDR2 */
- MEM_RDDR2, /* Registered DDR2 RAM */
- MEM_XDR, /* Rambus XDR */
- MEM_DDR3, /* DDR3 RAM */
- MEM_RDDR3, /* Registered DDR3 RAM */
-};
-
-#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
-#define MEM_FLAG_RESERVED BIT(MEM_RESERVED)
-#define MEM_FLAG_UNKNOWN BIT(MEM_UNKNOWN)
-#define MEM_FLAG_FPM BIT(MEM_FPM)
-#define MEM_FLAG_EDO BIT(MEM_EDO)
-#define MEM_FLAG_BEDO BIT(MEM_BEDO)
-#define MEM_FLAG_SDR BIT(MEM_SDR)
-#define MEM_FLAG_RDR BIT(MEM_RDR)
-#define MEM_FLAG_DDR BIT(MEM_DDR)
-#define MEM_FLAG_RDDR BIT(MEM_RDDR)
-#define MEM_FLAG_RMBS BIT(MEM_RMBS)
-#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
-#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
-#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
-#define MEM_FLAG_XDR BIT(MEM_XDR)
-#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
-#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
-
-/* chipset Error Detection and Correction capabilities and mode */
-enum edac_type {
- EDAC_UNKNOWN = 0, /* Unknown if ECC is available */
- EDAC_NONE, /* Doesn't support ECC */
- EDAC_RESERVED, /* Reserved ECC type */
- EDAC_PARITY, /* Detects parity errors */
- EDAC_EC, /* Error Checking - no correction */
- EDAC_SECDED, /* Single bit error correction, Double detection */
- EDAC_S2ECD2ED, /* Chipkill x2 devices - do these exist? */
- EDAC_S4ECD4ED, /* Chipkill x4 devices */
- EDAC_S8ECD8ED, /* Chipkill x8 devices */
- EDAC_S16ECD16ED, /* Chipkill x16 devices */
-};
-
-#define EDAC_FLAG_UNKNOWN BIT(EDAC_UNKNOWN)
-#define EDAC_FLAG_NONE BIT(EDAC_NONE)
-#define EDAC_FLAG_PARITY BIT(EDAC_PARITY)
-#define EDAC_FLAG_EC BIT(EDAC_EC)
-#define EDAC_FLAG_SECDED BIT(EDAC_SECDED)
-#define EDAC_FLAG_S2ECD2ED BIT(EDAC_S2ECD2ED)
-#define EDAC_FLAG_S4ECD4ED BIT(EDAC_S4ECD4ED)
-#define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED)
-#define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED)
-
-/* scrubbing capabilities */
-enum scrub_type {
- SCRUB_UNKNOWN = 0, /* Unknown if scrubber is available */
- SCRUB_NONE, /* No scrubber */
- SCRUB_SW_PROG, /* SW progressive (sequential) scrubbing */
- SCRUB_SW_SRC, /* Software scrub only errors */
- SCRUB_SW_PROG_SRC, /* Progressive software scrub from an error */
- SCRUB_SW_TUNABLE, /* Software scrub frequency is tunable */
- SCRUB_HW_PROG, /* HW progressive (sequential) scrubbing */
- SCRUB_HW_SRC, /* Hardware scrub only errors */
- SCRUB_HW_PROG_SRC, /* Progressive hardware scrub from an error */
- SCRUB_HW_TUNABLE /* Hardware scrub frequency is tunable */
-};
-
-#define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG)
-#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC)
-#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC)
-#define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE)
-#define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG)
-#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC)
-#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC)
-#define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE)
-
-/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
-
-/* EDAC internal operation states */
-#define OP_ALLOC 0x100
-#define OP_RUNNING_POLL 0x201
-#define OP_RUNNING_INTERRUPT 0x202
-#define OP_RUNNING_POLL_INTR 0x203
-#define OP_OFFLINE 0x300
-
-/*
- * There are several things to be aware of that aren't at all obvious:
- *
- *
- * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
- *
- * These are some of the many terms that are thrown about that don't always
- * mean what people think they mean (Inconceivable!). In the interest of
- * creating a common ground for discussion, terms and their definitions
- * will be established.
- *
- * Memory devices: The individual chip on a memory stick. These devices
- * commonly output 4 and 8 bits each. Grouping several
- * of these in parallel provides 64 bits which is common
- * for a memory stick.
- *
- * Memory Stick: A printed circuit board that aggregates multiple
- * memory devices in parallel. This is the atomic
- * memory component that is purchaseable by Joe consumer
- * and loaded into a memory socket.
- *
- * Socket: A physical connector on the motherboard that accepts
- * a single memory stick.
- *
- * Channel: Set of memory devices on a memory stick that must be
- * grouped in parallel with one or more additional
- * channels from other memory sticks. This parallel
- * grouping of the output from multiple channels are
- * necessary for the smallest granularity of memory access.
- * Some memory controllers are capable of single channel -
- * which means that memory sticks can be loaded
- * individually. Other memory controllers are only
- * capable of dual channel - which means that memory
- * sticks must be loaded as pairs (see "socket set").
- *
- * Chip-select row: All of the memory devices that are selected together.
- * for a single, minimum grain of memory access.
- * This selects all of the parallel memory devices across
- * all of the parallel channels. Common chip-select rows
- * for single channel are 64 bits, for dual channel 128
- * bits.
- *
- * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory.
- * Motherboards commonly drive two chip-select pins to
- * a memory stick. A single-ranked stick, will occupy
- * only one of those rows. The other will be unused.
- *
- * Double-Ranked stick: A double-ranked stick has two chip-select rows which
- * access different sets of memory devices. The two
- * rows cannot be accessed concurrently.
- *
- * Double-sided stick: DEPRECATED TERM, see Double-Ranked stick.
- * A double-sided stick has two chip-select rows which
- * access different sets of memory devices. The two
- * rows cannot be accessed concurrently. "Double-sided"
- * is irrespective of the memory devices being mounted
- * on both sides of the memory stick.
- *
- * Socket set: All of the memory sticks that are required for
- * a single memory access or all of the memory sticks
- * spanned by a chip-select row. A single socket set
- * has two chip-select rows and if double-sided sticks
- * are used these will occupy those chip-select rows.
- *
- * Bank: This term is avoided because it is unclear when
- * needing to distinguish between chip-select rows and
- * socket sets.
- *
- * Controller pages:
- *
- * Physical pages:
- *
- * Virtual pages:
- *
- *
- * STRUCTURE ORGANIZATION AND CHOICES
- *
- *
- *
- * PS - I enjoyed writing all that about as much as you enjoyed reading it.
- */
-
-struct channel_info {
- int chan_idx; /* channel index */
- u32 ce_count; /* Correctable Errors for this CHANNEL */
- char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
- struct csrow_info *csrow; /* the parent */
-};
-
-struct csrow_info {
- unsigned long first_page; /* first page number in dimm */
- unsigned long last_page; /* last page number in dimm */
- unsigned long page_mask; /* used for interleaving -
- * 0UL for non intlv
- */
- u32 nr_pages; /* number of pages in csrow */
- u32 grain; /* granularity of reported error in bytes */
- int csrow_idx; /* the chip-select row */
- enum dev_type dtype; /* memory device type */
- u32 ue_count; /* Uncorrectable Errors for this csrow */
- u32 ce_count; /* Correctable Errors for this csrow */
- enum mem_type mtype; /* memory csrow type */
- enum edac_type edac_mode; /* EDAC mode for this csrow */
- struct mem_ctl_info *mci; /* the parent */
-
- struct kobject kobj; /* sysfs kobject for this csrow */
-
- /* channel information for this csrow */
- u32 nr_channels;
- struct channel_info *channels;
-};
-
-struct mcidev_sysfs_group {
- const char *name; /* group name */
- const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
-};
-
-struct mcidev_sysfs_group_kobj {
- struct list_head list; /* list for all instances within a mc */
-
- struct kobject kobj; /* kobj for the group */
-
- const struct mcidev_sysfs_group *grp; /* group description table */
- struct mem_ctl_info *mci; /* the parent */
-};
-
-/* mcidev_sysfs_attribute structure
- * used for driver sysfs attributes and in mem_ctl_info
- * sysfs top level entries
- */
-struct mcidev_sysfs_attribute {
- /* It should use either attr or grp */
- struct attribute attr;
- const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
-
- /* Ops for show/store values at the attribute - not used on group */
- ssize_t (*show)(struct mem_ctl_info *,char *);
- ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
-};
-
-/* MEMORY controller information structure
- */
-struct mem_ctl_info {
- struct list_head link; /* for global list of mem_ctl_info structs */
-
- struct module *owner; /* Module owner of this control struct */
-
- unsigned long mtype_cap; /* memory types supported by mc */
- unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */
- unsigned long edac_cap; /* configuration capabilities - this is
- * closely related to edac_ctl_cap. The
- * difference is that the controller may be
- * capable of s4ecd4ed which would be listed
- * in edac_ctl_cap, but if channels aren't
- * capable of s4ecd4ed then the edac_cap would
- * not have that capability.
- */
- unsigned long scrub_cap; /* chipset scrub capabilities */
- enum scrub_type scrub_mode; /* current scrub mode */
-
- /* Translates sdram memory scrub rate given in bytes/sec to the
- internal representation and configures whatever else needs
- to be configured.
- */
- int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 bw);
-
- /* Get the current sdram memory scrub rate from the internal
- representation and converts it to the closest matching
- bandwidth in bytes/sec.
- */
- int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci);
-
-
- /* pointer to edac checking routine */
- void (*edac_check) (struct mem_ctl_info * mci);
-
- /*
- * Remaps memory pages: controller pages to physical pages.
- * For most MC's, this will be NULL.
- */
- /* FIXME - why not send the phys page to begin with? */
- unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
- unsigned long page);
- int mc_idx;
- int nr_csrows;
- struct csrow_info *csrows;
- /*
- * FIXME - what about controllers on other busses? - IDs must be
- * unique. dev pointer should be sufficiently unique, but
- * BUS:SLOT.FUNC numbers may not be unique.
- */
- struct device *dev;
- const char *mod_name;
- const char *mod_ver;
- const char *ctl_name;
- const char *dev_name;
- char proc_name[MC_PROC_NAME_MAX_LEN + 1];
- void *pvt_info;
- u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */
- u32 ce_noinfo_count; /* Correctable Errors w/o info */
- u32 ue_count; /* Total Uncorrectable Errors for this MC */
- u32 ce_count; /* Total Correctable Errors for this MC */
- unsigned long start_time; /* mci load start time (in jiffies) */
-
- struct completion complete;
-
- /* edac sysfs device control */
- struct kobject edac_mci_kobj;
-
- /* list for all grp instances within a mc */
- struct list_head grp_kobj_list;
-
- /* Additional top controller level attributes, but specified
- * by the low level driver.
- *
- * Set by the low level driver to provide attributes at the
- * controller level, same level as 'ue_count' and 'ce_count' above.
- * An array of structures, NULL terminated
- *
- * If attributes are desired, then set to array of attributes
- * If no attributes are desired, leave NULL
- */
- const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
-
- /* work struct for this MC */
- struct delayed_work work;
-
- /* the internal state of this controller instance */
- int op_state;
-};
-
/*
* The following are the structures to provide for a generic
* or abstract 'edac_device'. This set of structures and the
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index d69144a..7db101b 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -323,7 +323,8 @@ static void edac_mc_workq_function(struct work_struct *work_req)
*
* called with the mem_ctls_mutex held
*/
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
+ bool init)
{
debugf0("%s()\n", __func__);
@@ -331,7 +332,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
if (mci->op_state != OP_RUNNING_POLL)
return;
- INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ if (init)
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+
queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
}
@@ -391,7 +394,7 @@ void edac_mc_reset_delay_period(int value)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
- edac_mc_workq_setup(mci, (unsigned long) value);
+ edac_mc_workq_setup(mci, value, false);
}
mutex_unlock(&mem_ctls_mutex);
@@ -539,7 +542,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
/* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL;
- edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}
diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c
deleted file mode 100644
index 9ccdc5b..0000000
--- a/drivers/edac/edac_mce.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Provides edac interface to mcelog events
- *
- * This file may be distributed under the terms of the
- * GNU General Public License version 2.
- *
- * Copyright (c) 2009 by:
- * Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * Red Hat Inc. http://www.redhat.com
- */
-
-#include <linux/module.h>
-#include <linux/edac_mce.h>
-#include <asm/mce.h>
-
-int edac_mce_enabled;
-EXPORT_SYMBOL_GPL(edac_mce_enabled);
-
-
-/*
- * Extension interface
- */
-
-static LIST_HEAD(edac_mce_list);
-static DEFINE_MUTEX(edac_mce_lock);
-
-int edac_mce_register(struct edac_mce *edac_mce)
-{
- mutex_lock(&edac_mce_lock);
- list_add_tail(&edac_mce->list, &edac_mce_list);
- mutex_unlock(&edac_mce_lock);
- return 0;
-}
-EXPORT_SYMBOL(edac_mce_register);
-
-void edac_mce_unregister(struct edac_mce *edac_mce)
-{
- mutex_lock(&edac_mce_lock);
- list_del(&edac_mce->list);
- mutex_unlock(&edac_mce_lock);
-}
-EXPORT_SYMBOL(edac_mce_unregister);
-
-int edac_mce_parse(struct mce *mce)
-{
- struct edac_mce *edac_mce;
-
- list_for_each_entry(edac_mce, &edac_mce_list, list) {
- if (edac_mce->check_error(edac_mce->priv, mce))
- return 1;
- }
-
- /* Nobody queued the error */
- return 0;
-}
-EXPORT_SYMBOL_GPL(edac_mce_parse);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors");
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index aab9707..86ad2ee 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -14,7 +14,7 @@
*/
#include <linux/module.h>
#include <linux/edac.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <asm/edac.h>
int edac_op_state = EDAC_OPSTATE_INVAL;
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index a76fe83..1e08426 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -215,8 +215,8 @@ static const char *ferr_fat_fbd_name[] = {
[0] = "Memory Write error on non-redundant retry or "
"FBD configuration Write error on retry",
};
-#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28))
-#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+#define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3)
+#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22))
#define FERR_NF_FBD 0xa0
static const char *ferr_nf_fbd_name[] = {
@@ -243,7 +243,7 @@ static const char *ferr_nf_fbd_name[] = {
[1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
[0] = "Uncorrectable Data ECC on Replay",
};
-#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28))
+#define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3)
#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
(1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
(1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
@@ -372,7 +372,7 @@ static const char *get_err_from_table(const char *table[], int size, int pos)
static void i7300_process_error_global(struct mem_ctl_info *mci)
{
struct i7300_pvt *pvt;
- u32 errnum, value;
+ u32 errnum, error_reg;
unsigned long errors;
const char *specific;
bool is_fatal;
@@ -381,9 +381,9 @@ static void i7300_process_error_global(struct mem_ctl_info *mci)
/* read in the 1st FATAL error register */
pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
- FERR_GLOBAL_HI, &value);
- if (unlikely(value)) {
- errors = value;
+ FERR_GLOBAL_HI, &error_reg);
+ if (unlikely(error_reg)) {
+ errors = error_reg;
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_global_hi_name));
specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum);
@@ -391,15 +391,15 @@ static void i7300_process_error_global(struct mem_ctl_info *mci)
/* Clear the error bit */
pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
- FERR_GLOBAL_HI, value);
+ FERR_GLOBAL_HI, error_reg);
goto error_global;
}
pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
- FERR_GLOBAL_LO, &value);
- if (unlikely(value)) {
- errors = value;
+ FERR_GLOBAL_LO, &error_reg);
+ if (unlikely(error_reg)) {
+ errors = error_reg;
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_global_lo_name));
specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum);
@@ -407,7 +407,7 @@ static void i7300_process_error_global(struct mem_ctl_info *mci)
/* Clear the error bit */
pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
- FERR_GLOBAL_LO, value);
+ FERR_GLOBAL_LO, error_reg);
goto error_global;
}
@@ -427,7 +427,7 @@ error_global:
static void i7300_process_fbd_error(struct mem_ctl_info *mci)
{
struct i7300_pvt *pvt;
- u32 errnum, value;
+ u32 errnum, value, error_reg;
u16 val16;
unsigned branch, channel, bank, rank, cas, ras;
u32 syndrome;
@@ -440,14 +440,14 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
/* read in the 1st FATAL error register */
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
- FERR_FAT_FBD, &value);
- if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) {
- errors = value & FERR_FAT_FBD_ERR_MASK ;
+ FERR_FAT_FBD, &error_reg);
+ if (unlikely(error_reg & FERR_FAT_FBD_ERR_MASK)) {
+ errors = error_reg & FERR_FAT_FBD_ERR_MASK ;
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_fat_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
+ branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0;
- branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
NRECMEMA, &val16);
bank = NRECMEMA_BANK(val16);
@@ -455,11 +455,14 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
NRECMEMB, &value);
-
is_wr = NRECMEMB_IS_WR(value);
cas = NRECMEMB_CAS(value);
ras = NRECMEMB_RAS(value);
+ /* Clean the error register */
+ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_FAT_FBD, error_reg);
+
snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
"FATAL (Branch=%d DRAM-Bank=%d %s "
"RAS=%d CAS=%d Err=0x%lx (%s))",
@@ -476,21 +479,17 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
/* read in the 1st NON-FATAL error register */
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
- FERR_NF_FBD, &value);
- if (unlikely(value & FERR_NF_FBD_ERR_MASK)) {
- errors = value & FERR_NF_FBD_ERR_MASK;
+ FERR_NF_FBD, &error_reg);
+ if (unlikely(error_reg & FERR_NF_FBD_ERR_MASK)) {
+ errors = error_reg & FERR_NF_FBD_ERR_MASK;
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_nf_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
-
- /* Clear the error bit */
- pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
- FERR_GLOBAL_LO, value);
+ branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0;
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
REDMEMA, &syndrome);
- branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
RECMEMA, &val16);
bank = RECMEMA_BANK(val16);
@@ -498,18 +497,20 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
RECMEMB, &value);
-
is_wr = RECMEMB_IS_WR(value);
cas = RECMEMB_CAS(value);
ras = RECMEMB_RAS(value);
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
REDMEMB, &value);
-
channel = (branch << 1);
if (IS_SECOND_CH(value))
channel++;
+ /* Clear the error bit */
+ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+ FERR_NF_FBD, error_reg);
+
/* Form out message */
snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
"Corrected error (Branch=%d, Channel %d), "
@@ -961,33 +962,35 @@ static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
/* Attempt to 'get' the MCH register we want */
pdev = NULL;
- while (!pvt->pci_dev_16_1_fsb_addr_map ||
- !pvt->pci_dev_16_2_fsb_err_regs) {
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
- if (!pdev) {
- /* End of list, leave */
- i7300_printk(KERN_ERR,
- "'system address,Process Bus' "
- "device not found:"
- "vendor 0x%x device 0x%x ERR funcs "
- "(broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
- goto error;
- }
-
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+ pdev))) {
/* Store device 16 funcs 1 and 2 */
switch (PCI_FUNC(pdev->devfn)) {
case 1:
- pvt->pci_dev_16_1_fsb_addr_map = pdev;
+ if (!pvt->pci_dev_16_1_fsb_addr_map)
+ pvt->pci_dev_16_1_fsb_addr_map =
+ pci_dev_get(pdev);
break;
case 2:
- pvt->pci_dev_16_2_fsb_err_regs = pdev;
+ if (!pvt->pci_dev_16_2_fsb_err_regs)
+ pvt->pci_dev_16_2_fsb_err_regs =
+ pci_dev_get(pdev);
break;
}
}
+ if (!pvt->pci_dev_16_1_fsb_addr_map ||
+ !pvt->pci_dev_16_2_fsb_err_regs) {
+ /* At least one device was not found */
+ i7300_printk(KERN_ERR,
+ "'system address,Process Bus' device not found:"
+ "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+ goto error;
+ }
+
debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
pci_name(pvt->pci_dev_16_0_fsb_ctlr),
pvt->pci_dev_16_0_fsb_ctlr->vendor,
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 240966b..4c18b3c 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -31,11 +31,13 @@
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/dmi.h>
#include <linux/edac.h>
#include <linux/mmzone.h>
-#include <linux/edac_mce.h>
#include <linux/smp.h>
+#include <asm/mce.h>
#include <asm/processor.h>
+#include <asm/div64.h>
#include "edac_core.h"
@@ -78,6 +80,8 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
/* OFFSETS for Device 0 Function 0 */
#define MC_CFG_CONTROL 0x90
+ #define MC_CFG_UNLOCK 0x02
+ #define MC_CFG_LOCK 0x00
/* OFFSETS for Device 3 Function 0 */
@@ -98,6 +102,15 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
#define DIMM0_COR_ERR(r) ((r) & 0x7fff)
/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+#define MC_SSRCONTROL 0x48
+ #define SSR_MODE_DISABLE 0x00
+ #define SSR_MODE_ENABLE 0x01
+ #define SSR_MODE_MASK 0x03
+
+#define MC_SCRUB_CONTROL 0x4c
+ #define STARTSCRUB (1 << 24)
+ #define SCRUBINTERVAL_MASK 0xffffff
+
#define MC_COR_ECC_CNT_0 0x80
#define MC_COR_ECC_CNT_1 0x84
#define MC_COR_ECC_CNT_2 0x88
@@ -253,10 +266,7 @@ struct i7core_pvt {
unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS];
int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS];
- unsigned int is_registered;
-
- /* mcelog glue */
- struct edac_mce edac_mce;
+ bool is_registered, enable_scrub;
/* Fifo double buffers */
struct mce mce_entry[MCE_LOG_LEN];
@@ -268,6 +278,9 @@ struct i7core_pvt {
/* Count indicator to show errors not got */
unsigned mce_overrun;
+ /* DCLK Frequency used for computing scrub rate */
+ int dclk_freq;
+
/* Struct to control EDAC polling */
struct edac_pci_ctl_info *i7core_pci;
};
@@ -281,8 +294,7 @@ static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
/* Memory controller */
{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) },
{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) },
-
- /* Exists only for RDIMM */
+ /* Exists only for RDIMM */
{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 },
{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
@@ -303,6 +315,16 @@ static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) },
+
+ /* Generic Non-core registers */
+ /*
+ * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
+ * On Xeon 55xx, however, it has a different id (8086:2c40). So,
+ * the probing code needs to test for the other address in case of
+ * failure of this one
+ */
+ { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) },
+
};
static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
@@ -319,6 +341,12 @@ static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
{ PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
{ PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
{ PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) },
+
+ /*
+ * This is the PCI device has an alternate address on some
+ * processors like Core i7 860
+ */
+ { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) },
};
static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
@@ -346,6 +374,10 @@ static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) },
+
+ /* Generic Non-core registers */
+ { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) },
+
};
#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
@@ -714,6 +746,10 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
csr->edac_mode = mode;
csr->mtype = mtype;
+ snprintf(csr->channels[0].label,
+ sizeof(csr->channels[0].label),
+ "CPU#%uChannel#%u_DIMM#%u",
+ pvt->i7core_dev->socket, i, j);
csrow++;
}
@@ -731,7 +767,7 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
debugf1("\t\t%#x\t%#x\t%#x\n",
(value[j] >> 27) & 0x1,
(value[j] >> 24) & 0x7,
- (value[j] && ((1 << 24) - 1)));
+ (value[j] & ((1 << 24) - 1)));
}
return 0;
@@ -1324,6 +1360,25 @@ static int i7core_get_onedevice(struct pci_dev **prev,
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
dev_descr->dev_id, *prev);
+ /*
+ * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+ * is at addr 8086:2c40, instead of 8086:2c41. So, we need
+ * to probe for the alternate address in case of failure
+ */
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+ }
+
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
+ !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
+ *prev);
+ }
+
if (!pdev) {
if (*prev) {
*prev = pdev;
@@ -1444,8 +1499,10 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
struct i7core_pvt *pvt = mci->pvt_info;
struct pci_dev *pdev;
int i, func, slot;
+ char *family;
- pvt->is_registered = 0;
+ pvt->is_registered = false;
+ pvt->enable_scrub = false;
for (i = 0; i < i7core_dev->n_devs; i++) {
pdev = i7core_dev->pdev[i];
if (!pdev)
@@ -1461,9 +1518,37 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
if (unlikely(func > MAX_CHAN_FUNC))
goto error;
pvt->pci_ch[slot - 4][func] = pdev;
- } else if (!slot && !func)
+ } else if (!slot && !func) {
pvt->pci_noncore = pdev;
- else
+
+ /* Detect the processor family */
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_I7_NONCORE:
+ family = "Xeon 35xx/ i7core";
+ pvt->enable_scrub = false;
+ break;
+ case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT:
+ family = "i7-800/i5-700";
+ pvt->enable_scrub = false;
+ break;
+ case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE:
+ family = "Xeon 34xx";
+ pvt->enable_scrub = false;
+ break;
+ case PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT:
+ family = "Xeon 55xx";
+ pvt->enable_scrub = true;
+ break;
+ case PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2:
+ family = "Xeon 56xx / i7-900";
+ pvt->enable_scrub = true;
+ break;
+ default:
+ family = "unknown";
+ pvt->enable_scrub = false;
+ }
+ debugf0("Detected a processor type %s\n", family);
+ } else
goto error;
debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
@@ -1472,7 +1557,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
if (PCI_SLOT(pdev->devfn) == 3 &&
PCI_FUNC(pdev->devfn) == 2)
- pvt->is_registered = 1;
+ pvt->is_registered = true;
}
return 0;
@@ -1826,31 +1911,37 @@ check_ce_error:
* WARNING: As this routine should be called at NMI time, extra care should
* be taken to avoid deadlocks, and to be as fast as possible.
*/
-static int i7core_mce_check_error(void *priv, struct mce *mce)
+static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val,
+ void *data)
{
- struct mem_ctl_info *mci = priv;
- struct i7core_pvt *pvt = mci->pvt_info;
+ struct mce *mce = (struct mce *)data;
+ struct i7core_dev *i7_dev;
+ struct mem_ctl_info *mci;
+ struct i7core_pvt *pvt;
+
+ i7_dev = get_i7core_dev(mce->socketid);
+ if (!i7_dev)
+ return NOTIFY_BAD;
+
+ mci = i7_dev->mci;
+ pvt = mci->pvt_info;
/*
* Just let mcelog handle it if the error is
* outside the memory controller
*/
if (((mce->status & 0xffff) >> 7) != 1)
- return 0;
+ return NOTIFY_DONE;
/* Bank 8 registers are the only ones that we know how to handle */
if (mce->bank != 8)
- return 0;
-
- /* Only handle if it is the right mc controller */
- if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket)
- return 0;
+ return NOTIFY_DONE;
smp_rmb();
if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
smp_wmb();
pvt->mce_overrun++;
- return 0;
+ return NOTIFY_DONE;
}
/* Copy memory error at the ringbuffer */
@@ -1863,7 +1954,240 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
i7core_check_error(mci);
/* Advise mcelog that the errors were handled */
- return 1;
+ return NOTIFY_STOP;
+}
+
+static struct notifier_block i7_mce_dec = {
+ .notifier_call = i7core_mce_check_error,
+};
+
+struct memdev_dmi_entry {
+ u8 type;
+ u8 length;
+ u16 handle;
+ u16 phys_mem_array_handle;
+ u16 mem_err_info_handle;
+ u16 total_width;
+ u16 data_width;
+ u16 size;
+ u8 form;
+ u8 device_set;
+ u8 device_locator;
+ u8 bank_locator;
+ u8 memory_type;
+ u16 type_detail;
+ u16 speed;
+ u8 manufacturer;
+ u8 serial_number;
+ u8 asset_tag;
+ u8 part_number;
+ u8 attributes;
+ u32 extended_size;
+ u16 conf_mem_clk_speed;
+} __attribute__((__packed__));
+
+
+/*
+ * Decode the DRAM Clock Frequency, be paranoid, make sure that all
+ * memory devices show the same speed, and if they don't then consider
+ * all speeds to be invalid.
+ */
+static void decode_dclk(const struct dmi_header *dh, void *_dclk_freq)
+{
+ int *dclk_freq = _dclk_freq;
+ u16 dmi_mem_clk_speed;
+
+ if (*dclk_freq == -1)
+ return;
+
+ if (dh->type == DMI_ENTRY_MEM_DEVICE) {
+ struct memdev_dmi_entry *memdev_dmi_entry =
+ (struct memdev_dmi_entry *)dh;
+ unsigned long conf_mem_clk_speed_offset =
+ (unsigned long)&memdev_dmi_entry->conf_mem_clk_speed -
+ (unsigned long)&memdev_dmi_entry->type;
+ unsigned long speed_offset =
+ (unsigned long)&memdev_dmi_entry->speed -
+ (unsigned long)&memdev_dmi_entry->type;
+
+ /* Check that a DIMM is present */
+ if (memdev_dmi_entry->size == 0)
+ return;
+
+ /*
+ * Pick the configured speed if it's available, otherwise
+ * pick the DIMM speed, or we don't have a speed.
+ */
+ if (memdev_dmi_entry->length > conf_mem_clk_speed_offset) {
+ dmi_mem_clk_speed =
+ memdev_dmi_entry->conf_mem_clk_speed;
+ } else if (memdev_dmi_entry->length > speed_offset) {
+ dmi_mem_clk_speed = memdev_dmi_entry->speed;
+ } else {
+ *dclk_freq = -1;
+ return;
+ }
+
+ if (*dclk_freq == 0) {
+ /* First pass, speed was 0 */
+ if (dmi_mem_clk_speed > 0) {
+ /* Set speed if a valid speed is read */
+ *dclk_freq = dmi_mem_clk_speed;
+ } else {
+ /* Otherwise we don't have a valid speed */
+ *dclk_freq = -1;
+ }
+ } else if (*dclk_freq > 0 &&
+ *dclk_freq != dmi_mem_clk_speed) {
+ /*
+ * If we have a speed, check that all DIMMS are the same
+ * speed, otherwise set the speed as invalid.
+ */
+ *dclk_freq = -1;
+ }
+ }
+}
+
+/*
+ * The default DCLK frequency is used as a fallback if we
+ * fail to find anything reliable in the DMI. The value
+ * is taken straight from the datasheet.
+ */
+#define DEFAULT_DCLK_FREQ 800
+
+static int get_dclk_freq(void)
+{
+ int dclk_freq = 0;
+
+ dmi_walk(decode_dclk, (void *)&dclk_freq);
+
+ if (dclk_freq < 1)
+ return DEFAULT_DCLK_FREQ;
+
+ return dclk_freq;
+}
+
+/*
+ * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub rate
+ * to hardware according to SCRUBINTERVAL formula
+ * found in datasheet.
+ */
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev;
+ u32 dw_scrub;
+ u32 dw_ssr;
+
+ /* Get data from the MC register, function 2 */
+ pdev = pvt->pci_mcr[2];
+ if (!pdev)
+ return -ENODEV;
+
+ pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &dw_scrub);
+
+ if (new_bw == 0) {
+ /* Prepare to disable petrol scrub */
+ dw_scrub &= ~STARTSCRUB;
+ /* Stop the patrol scrub engine */
+ write_and_test(pdev, MC_SCRUB_CONTROL,
+ dw_scrub & ~SCRUBINTERVAL_MASK);
+
+ /* Get current status of scrub rate and set bit to disable */
+ pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
+ dw_ssr &= ~SSR_MODE_MASK;
+ dw_ssr |= SSR_MODE_DISABLE;
+ } else {
+ const int cache_line_size = 64;
+ const u32 freq_dclk_mhz = pvt->dclk_freq;
+ unsigned long long scrub_interval;
+ /*
+ * Translate the desired scrub rate to a register value and
+ * program the corresponding register value.
+ */
+ scrub_interval = (unsigned long long)freq_dclk_mhz *
+ cache_line_size * 1000000;
+ do_div(scrub_interval, new_bw);
+
+ if (!scrub_interval || scrub_interval > SCRUBINTERVAL_MASK)
+ return -EINVAL;
+
+ dw_scrub = SCRUBINTERVAL_MASK & scrub_interval;
+
+ /* Start the patrol scrub engine */
+ pci_write_config_dword(pdev, MC_SCRUB_CONTROL,
+ STARTSCRUB | dw_scrub);
+
+ /* Get current status of scrub rate and set bit to enable */
+ pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
+ dw_ssr &= ~SSR_MODE_MASK;
+ dw_ssr |= SSR_MODE_ENABLE;
+ }
+ /* Disable or enable scrubbing */
+ pci_write_config_dword(pdev, MC_SSRCONTROL, dw_ssr);
+
+ return new_bw;
+}
+
+/*
+ * get_sdram_scrub_rate This routine convert current scrub rate value
+ * into byte/sec bandwidth accourding to
+ * SCRUBINTERVAL formula found in datasheet.
+ */
+static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev;
+ const u32 cache_line_size = 64;
+ const u32 freq_dclk_mhz = pvt->dclk_freq;
+ unsigned long long scrub_rate;
+ u32 scrubval;
+
+ /* Get data from the MC register, function 2 */
+ pdev = pvt->pci_mcr[2];
+ if (!pdev)
+ return -ENODEV;
+
+ /* Get current scrub control data */
+ pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &scrubval);
+
+ /* Mask highest 8-bits to 0 */
+ scrubval &= SCRUBINTERVAL_MASK;
+ if (!scrubval)
+ return 0;
+
+ /* Calculate scrub rate value into byte/sec bandwidth */
+ scrub_rate = (unsigned long long)freq_dclk_mhz *
+ 1000000 * cache_line_size;
+ do_div(scrub_rate, scrubval);
+ return (int)scrub_rate;
+}
+
+static void enable_sdram_scrub_setting(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 pci_lock;
+
+ /* Unlock writes to pci registers */
+ pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
+ pci_lock &= ~0x3;
+ pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
+ pci_lock | MC_CFG_UNLOCK);
+
+ mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
+ mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
+}
+
+static void disable_sdram_scrub_setting(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 pci_lock;
+
+ /* Lock writes to pci registers */
+ pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
+ pci_lock &= ~0x3;
+ pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
+ pci_lock | MC_CFG_LOCK);
}
static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
@@ -1872,7 +2196,8 @@ static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
&pvt->i7core_dev->pdev[0]->dev,
EDAC_MOD_STR);
if (unlikely(!pvt->i7core_pci))
- pr_warn("Unable to setup PCI error report via EDAC\n");
+ i7core_printk(KERN_WARNING,
+ "Unable to setup PCI error report via EDAC\n");
}
static void i7core_pci_ctl_release(struct i7core_pvt *pvt)
@@ -1904,8 +2229,9 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
__func__, mci, &i7core_dev->pdev[0]->dev);
- /* Disable MCE NMI handler */
- edac_mce_unregister(&pvt->edac_mce);
+ /* Disable scrubrate setting */
+ if (pvt->enable_scrub)
+ disable_sdram_scrub_setting(mci);
/* Disable EDAC polling */
i7core_pci_ctl_release(pvt);
@@ -1977,6 +2303,10 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
/* Set the function pointer to an actual operation function */
mci->edac_check = i7core_check_error;
+ /* Enable scrubrate setting */
+ if (pvt->enable_scrub)
+ enable_sdram_scrub_setting(mci);
+
/* add this new MC control structure to EDAC's list of MCs */
if (unlikely(edac_mc_add_mc(mci))) {
debugf0("MC: " __FILE__
@@ -2000,21 +2330,11 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
/* allocating generic PCI control info */
i7core_pci_ctl_create(pvt);
- /* Registers on edac_mce in order to receive memory errors */
- pvt->edac_mce.priv = mci;
- pvt->edac_mce.check_error = i7core_mce_check_error;
- rc = edac_mce_register(&pvt->edac_mce);
- if (unlikely(rc < 0)) {
- debugf0("MC: " __FILE__
- ": %s(): failed edac_mce_register()\n", __func__);
- goto fail1;
- }
+ /* DCLK for scrub rate setting */
+ pvt->dclk_freq = get_dclk_freq();
return 0;
-fail1:
- i7core_pci_ctl_release(pvt);
- edac_mc_del_mc(mci->dev);
fail0:
kfree(mci->ctl_name);
edac_mc_free(mci);
@@ -2033,7 +2353,7 @@ fail0:
static int __devinit i7core_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- int rc;
+ int rc, count = 0;
struct i7core_dev *i7core_dev;
/* get the pci devices we want to reserve for our use */
@@ -2053,12 +2373,28 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
goto fail0;
list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+ count++;
rc = i7core_register_mci(i7core_dev);
if (unlikely(rc < 0))
goto fail1;
}
- i7core_printk(KERN_INFO, "Driver loaded.\n");
+ /*
+ * Nehalem-EX uses a different memory controller. However, as the
+ * memory controller is not visible on some Nehalem/Nehalem-EP, we
+ * need to indirectly probe via a X58 PCI device. The same devices
+ * are found on (some) Nehalem-EX. So, on those machines, the
+ * probe routine needs to return -ENODEV, as the actual Memory
+ * Controller registers won't be detected.
+ */
+ if (!count) {
+ rc = -ENODEV;
+ goto fail1;
+ }
+
+ i7core_printk(KERN_INFO,
+ "Driver loaded, %d memory controller(s) found.\n",
+ count);
mutex_unlock(&i7core_edac_lock);
return 0;
@@ -2140,8 +2476,10 @@ static int __init i7core_init(void)
pci_rc = pci_register_driver(&i7core_driver);
- if (pci_rc >= 0)
+ if (pci_rc >= 0) {
+ atomic_notifier_chain_register(&x86_mce_decoder_chain, &i7_mce_dec);
return 0;
+ }
i7core_printk(KERN_ERR, "Failed to register device with error %d.\n",
pci_rc);
@@ -2157,6 +2495,7 @@ static void __exit i7core_exit(void)
{
debugf2("MC: " __FILE__ ": %s()\n", __func__);
pci_unregister_driver(&i7core_driver);
+ atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &i7_mce_dec);
}
module_init(i7core_init);
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index a5da732f..01658ca 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -355,10 +355,6 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct pci_dev *pdev, void __iomem *mch_window)
{
- static const char *labels[4] = {
- "DIMM A1", "DIMM A2",
- "DIMM B1", "DIMM B2"
- };
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
@@ -399,9 +395,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
* [0-3] for dual-channel; i.e. csrow->nr_channels = 2
*/
for (chan = 0; chan < csrow->nr_channels; chan++)
- strncpy(csrow->channels[chan].label,
- labels[(index >> 1) + (chan * 2)],
- EDAC_MC_LABEL_LEN);
+
+ snprintf(csrow->channels[chan].label, EDAC_MC_LABEL_LEN, "DIMM %c%d",
+ (chan == 0) ? 'A' : 'B',
+ index);
if (cumul_size == last_cumul_size)
continue; /* not populated */
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 795cfbc..d0864d9 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -9,7 +9,7 @@ static u8 xec_mask = 0xf;
static u8 nb_err_cpumask = 0xf;
static bool report_gart_errors;
-static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg);
+static void (*nb_bus_decoder)(int node_id, struct mce *m);
void amd_report_gart_errors(bool v)
{
@@ -17,13 +17,13 @@ void amd_report_gart_errors(bool v)
}
EXPORT_SYMBOL_GPL(amd_report_gart_errors);
-void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32))
+void amd_register_ecc_decoder(void (*f)(int, struct mce *))
{
nb_bus_decoder = f;
}
EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
-void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32))
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *))
{
if (nb_bus_decoder) {
WARN_ON(nb_bus_decoder != f);
@@ -592,31 +592,14 @@ static bool nb_noop_mce(u16 ec, u8 xec)
return false;
}
-void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
+void amd_decode_nb_mce(struct mce *m)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
- u16 ec = EC(m->status);
- u8 xec = XEC(m->status, 0x1f);
- u32 nbsh = (u32)(m->status >> 32);
- int core = -1;
-
- pr_emerg(HW_ERR "Northbridge Error (node %d", node_id);
-
- /* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */
- if (c->x86 == 0x10 && c->x86_model > 7) {
- if (nbsh & NBSH_ERR_CPU_VAL)
- core = nbsh & nb_err_cpumask;
- } else {
- u8 assoc_cpus = nbsh & nb_err_cpumask;
-
- if (assoc_cpus > 0)
- core = fls(assoc_cpus) - 1;
- }
+ int node_id = amd_get_nb_id(m->extcpu);
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, 0x1f);
- if (core >= 0)
- pr_cont(", core %d): ", core);
- else
- pr_cont("): ");
+ pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
switch (xec) {
case 0x2:
@@ -648,7 +631,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x15)
if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
- nb_bus_decoder(node_id, m, nbcfg);
+ nb_bus_decoder(node_id, m);
return;
@@ -764,13 +747,13 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
{
struct mce *m = (struct mce *)data;
struct cpuinfo_x86 *c = &boot_cpu_data;
- int node, ecc;
+ int ecc;
if (amd_filter_mce(m))
return NOTIFY_STOP;
- pr_emerg(HW_ERR "MC%d_STATUS[%s|%s|%s|%s|%s",
- m->bank,
+ pr_emerg(HW_ERR "CPU:%d\tMC%d_STATUS[%s|%s|%s|%s|%s",
+ m->extcpu, m->bank,
((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
@@ -789,6 +772,8 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
pr_cont("]: 0x%016llx\n", m->status);
+ if (m->status & MCI_STATUS_ADDRV)
+ pr_emerg(HW_ERR "\tMC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
switch (m->bank) {
case 0:
@@ -811,8 +796,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
break;
case 4:
- node = amd_get_nb_id(m->extcpu);
- amd_decode_nb_mce(node, m, 0);
+ amd_decode_nb_mce(m);
break;
case 5:
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 795a320..0106747 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -86,9 +86,9 @@ struct amd_decoder_ops {
};
void amd_report_gart_errors(bool);
-void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32));
-void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32));
-void amd_decode_nb_mce(int, struct mce *, u32);
+void amd_register_ecc_decoder(void (*f)(int, struct mce *));
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *));
+void amd_decode_nb_mce(struct mce *);
int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data);
#endif /* _EDAC_MCE_AMD_H */
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index a4987e0..73c3e26 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -13,6 +13,7 @@
#include <linux/kobject.h>
#include <linux/sysdev.h>
#include <linux/edac.h>
+#include <linux/module.h>
#include <asm/mce.h>
#include "mce_amd.h"
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 38ab8e2..73464a6 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -538,15 +538,15 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
/* we only need the error registers */
r.start += 0xe00;
- if (!devm_request_mem_region(&op->dev, r.start,
- r.end - r.start + 1, pdata->name)) {
+ if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
+ pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
__func__);
res = -EBUSY;
goto err;
}
- pdata->l2_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1);
+ pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
if (!pdata->l2_vbase) {
printk(KERN_ERR "%s: Unable to setup L2 err regs\n", __func__);
res = -ENOMEM;
@@ -854,11 +854,11 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n");
if (err_detect & DDR_EDE_SBE)
- edac_mc_handle_ce(mci, pfn, err_addr & PAGE_MASK,
+ edac_mc_handle_ce(mci, pfn, err_addr & ~PAGE_MASK,
syndrome, row_index, 0, mci->ctl_name);
if (err_detect & DDR_EDE_MBE)
- edac_mc_handle_ue(mci, pfn, err_addr & PAGE_MASK,
+ edac_mc_handle_ue(mci, pfn, err_addr & ~PAGE_MASK,
row_index, mci->ctl_name);
out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
@@ -987,15 +987,15 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
goto err;
}
- if (!devm_request_mem_region(&op->dev, r.start,
- r.end - r.start + 1, pdata->name)) {
+ if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
+ pdata->name)) {
printk(KERN_ERR "%s: Error while requesting mem region\n",
__func__);
res = -EBUSY;
goto err;
}
- pdata->mc_vbase = devm_ioremap(&op->dev, r.start, r.end - r.start + 1);
+ pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
if (!pdata->mc_vbase) {
printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
res = -ENOMEM;
@@ -1128,7 +1128,7 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = {
{ .compatible = "fsl,p1020-memory-controller", },
{ .compatible = "fsl,p1021-memory-controller", },
{ .compatible = "fsl,p2020-memory-controller", },
- { .compatible = "fsl,p4080-memory-controller", },
+ { .compatible = "fsl,qoriq-memory-controller", },
{},
};
MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match);
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 0de7d87..3840096 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -205,7 +205,7 @@ static struct platform_driver ppc4xx_edac_driver = {
.remove = ppc4xx_edac_remove,
.driver = {
.owner = THIS_MODULE,
- .name = PPC4XX_EDAC_MODULE_NAME
+ .name = PPC4XX_EDAC_MODULE_NAME,
.of_match_table = ppc4xx_edac_match,
},
};
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 8a1021f..111d956 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -465,31 +465,29 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
while (new_bus) {
new_bridge = new_bus->self;
- if (new_bridge) {
- /* go through list of devices already registered */
- list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
- bus = same_bridge_vgadev->pdev->bus;
- bridge = bus->self;
-
- /* see if the share a bridge with this device */
- if (new_bridge == bridge) {
- /* if their direct parent bridge is the same
- as any bridge of this device then it can't be used
- for that device */
- same_bridge_vgadev->bridge_has_one_vga = false;
- }
+ /* go through list of devices already registered */
+ list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+ bus = same_bridge_vgadev->pdev->bus;
+ bridge = bus->self;
+
+ /* see if the share a bridge with this device */
+ if (new_bridge == bridge) {
+ /* if their direct parent bridge is the same
+ as any bridge of this device then it can't be used
+ for that device */
+ same_bridge_vgadev->bridge_has_one_vga = false;
+ }
- /* now iterate the previous devices bridge hierarchy */
- /* if the new devices parent bridge is in the other devices
- hierarchy then we can't use it to control this device */
- while (bus) {
- bridge = bus->self;
- if (bridge) {
- if (bridge == vgadev->pdev->bus->self)
- vgadev->bridge_has_one_vga = false;
- }
- bus = bus->parent;
+ /* now iterate the previous devices bridge hierarchy */
+ /* if the new devices parent bridge is in the other devices
+ hierarchy then we can't use it to control this device */
+ while (bus) {
+ bridge = bus->self;
+ if (bridge) {
+ if (bridge == vgadev->pdev->bus->self)
+ vgadev->bridge_has_one_vga = false;
}
+ bus = bus->parent;
}
}
new_bus = new_bus->parent;
@@ -993,14 +991,20 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
uc = &priv->cards[i];
}
- if (!uc)
- return -EINVAL;
+ if (!uc) {
+ ret_val = -EINVAL;
+ goto done;
+ }
- if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0)
- return -EINVAL;
+ if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) {
+ ret_val = -EINVAL;
+ goto done;
+ }
- if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0)
- return -EINVAL;
+ if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) {
+ ret_val = -EINVAL;
+ goto done;
+ }
vga_put(pdev, io_state);
@@ -1171,10 +1175,9 @@ static int vga_arb_open(struct inode *inode, struct file *file)
pr_debug("%s\n", __func__);
- priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
- memset(priv, 0, sizeof(*priv));
spin_lock_init(&priv->lock);
file->private_data = priv;
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index 1f29bab..c7c3128 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -2,22 +2,31 @@
# Generic HWSPINLOCK framework
#
+# HWSPINLOCK always gets selected by whoever wants it.
config HWSPINLOCK
- tristate "Generic Hardware Spinlock framework"
- depends on ARCH_OMAP4
- help
- Say y here to support the generic hardware spinlock framework.
- You only need to enable this if you have hardware spinlock module
- on your system (usually only relevant if your system has remote slave
- coprocessors).
+ tristate
- If unsure, say N.
+menu "Hardware Spinlock drivers"
config HWSPINLOCK_OMAP
tristate "OMAP Hardware Spinlock device"
- depends on HWSPINLOCK && ARCH_OMAP4
+ depends on ARCH_OMAP4
+ select HWSPINLOCK
help
Say y here to support the OMAP Hardware Spinlock device (firstly
introduced in OMAP4).
If unsure, say N.
+
+config HSEM_U8500
+ tristate "STE Hardware Semaphore functionality"
+ depends on ARCH_U8500
+ select HWSPINLOCK
+ help
+ Say y here to support the STE Hardware Semaphore functionality, which
+ provides a synchronisation mechanism for the various processor on the
+ SoC.
+
+ If unsure, say N.
+
+endmenu
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
index 5729a3f..93eb64b 100644
--- a/drivers/hwspinlock/Makefile
+++ b/drivers/hwspinlock/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
+obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 12f7c83..08e7e72 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -117,7 +117,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
return -EBUSY;
/* try to take the hwspinlock device */
- ret = hwlock->ops->trylock(hwlock);
+ ret = hwlock->bank->ops->trylock(hwlock);
/* if hwlock is already taken, undo spin_trylock_* and exit */
if (!ret) {
@@ -199,8 +199,8 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
* Allow platform-specific relax handlers to prevent
* hogging the interconnect (no sleeping, though)
*/
- if (hwlock->ops->relax)
- hwlock->ops->relax(hwlock);
+ if (hwlock->bank->ops->relax)
+ hwlock->bank->ops->relax(hwlock);
}
return ret;
@@ -245,7 +245,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
*/
mb();
- hwlock->ops->unlock(hwlock);
+ hwlock->bank->ops->unlock(hwlock);
/* Undo the spin_trylock{_irq, _irqsave} called while locking */
if (mode == HWLOCK_IRQSTATE)
@@ -257,61 +257,32 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
}
EXPORT_SYMBOL_GPL(__hwspin_unlock);
-/**
- * hwspin_lock_register() - register a new hw spinlock
- * @hwlock: hwspinlock to register.
- *
- * This function should be called from the underlying platform-specific
- * implementation, to register a new hwspinlock instance.
- *
- * Should be called from a process context (might sleep)
- *
- * Returns 0 on success, or an appropriate error code on failure
- */
-int hwspin_lock_register(struct hwspinlock *hwlock)
+static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
{
struct hwspinlock *tmp;
int ret;
- if (!hwlock || !hwlock->ops ||
- !hwlock->ops->trylock || !hwlock->ops->unlock) {
- pr_err("invalid parameters\n");
- return -EINVAL;
- }
-
- spin_lock_init(&hwlock->lock);
-
mutex_lock(&hwspinlock_tree_lock);
- ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock);
- if (ret)
+ ret = radix_tree_insert(&hwspinlock_tree, id, hwlock);
+ if (ret) {
+ if (ret == -EEXIST)
+ pr_err("hwspinlock id %d already exists!\n", id);
goto out;
+ }
/* mark this hwspinlock as available */
- tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id,
- HWSPINLOCK_UNUSED);
+ tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
/* self-sanity check which should never fail */
WARN_ON(tmp != hwlock);
out:
mutex_unlock(&hwspinlock_tree_lock);
- return ret;
+ return 0;
}
-EXPORT_SYMBOL_GPL(hwspin_lock_register);
-/**
- * hwspin_lock_unregister() - unregister an hw spinlock
- * @id: index of the specific hwspinlock to unregister
- *
- * This function should be called from the underlying platform-specific
- * implementation, to unregister an existing (and unused) hwspinlock.
- *
- * Should be called from a process context (might sleep)
- *
- * Returns the address of hwspinlock @id on success, or NULL on failure
- */
-struct hwspinlock *hwspin_lock_unregister(unsigned int id)
+static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
{
struct hwspinlock *hwlock = NULL;
int ret;
@@ -335,6 +306,88 @@ out:
mutex_unlock(&hwspinlock_tree_lock);
return hwlock;
}
+
+/**
+ * hwspin_lock_register() - register a new hw spinlock device
+ * @bank: the hwspinlock device, which usually provides numerous hw locks
+ * @dev: the backing device
+ * @ops: hwspinlock handlers for this device
+ * @base_id: id of the first hardware spinlock in this bank
+ * @num_locks: number of hwspinlocks provided by this device
+ *
+ * This function should be called from the underlying platform-specific
+ * implementation, to register a new hwspinlock device instance.
+ *
+ * Should be called from a process context (might sleep)
+ *
+ * Returns 0 on success, or an appropriate error code on failure
+ */
+int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
+ const struct hwspinlock_ops *ops, int base_id, int num_locks)
+{
+ struct hwspinlock *hwlock;
+ int ret = 0, i;
+
+ if (!bank || !ops || !dev || !num_locks || !ops->trylock ||
+ !ops->unlock) {
+ pr_err("invalid parameters\n");
+ return -EINVAL;
+ }
+
+ bank->dev = dev;
+ bank->ops = ops;
+ bank->base_id = base_id;
+ bank->num_locks = num_locks;
+
+ for (i = 0; i < num_locks; i++) {
+ hwlock = &bank->lock[i];
+
+ spin_lock_init(&hwlock->lock);
+ hwlock->bank = bank;
+
+ ret = hwspin_lock_register_single(hwlock, base_id + i);
+ if (ret)
+ goto reg_failed;
+ }
+
+ return 0;
+
+reg_failed:
+ while (--i >= 0)
+ hwspin_lock_unregister_single(base_id + i);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_register);
+
+/**
+ * hwspin_lock_unregister() - unregister an hw spinlock device
+ * @bank: the hwspinlock device, which usually provides numerous hw locks
+ *
+ * This function should be called from the underlying platform-specific
+ * implementation, to unregister an existing (and unused) hwspinlock.
+ *
+ * Should be called from a process context (might sleep)
+ *
+ * Returns 0 on success, or an appropriate error code on failure
+ */
+int hwspin_lock_unregister(struct hwspinlock_device *bank)
+{
+ struct hwspinlock *hwlock, *tmp;
+ int i;
+
+ for (i = 0; i < bank->num_locks; i++) {
+ hwlock = &bank->lock[i];
+
+ tmp = hwspin_lock_unregister_single(bank->base_id + i);
+ if (!tmp)
+ return -EBUSY;
+
+ /* self-sanity check that should never fail */
+ WARN_ON(tmp != hwlock);
+ }
+
+ return 0;
+}
EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
/**
@@ -349,24 +402,27 @@ EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
*/
static int __hwspin_lock_request(struct hwspinlock *hwlock)
{
+ struct device *dev = hwlock->bank->dev;
struct hwspinlock *tmp;
int ret;
/* prevent underlying implementation from being removed */
- if (!try_module_get(hwlock->owner)) {
- dev_err(hwlock->dev, "%s: can't get owner\n", __func__);
+ if (!try_module_get(dev->driver->owner)) {
+ dev_err(dev, "%s: can't get owner\n", __func__);
return -EINVAL;
}
/* notify PM core that power is now needed */
- ret = pm_runtime_get_sync(hwlock->dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0) {
- dev_err(hwlock->dev, "%s: can't power on device\n", __func__);
+ dev_err(dev, "%s: can't power on device\n", __func__);
+ pm_runtime_put_noidle(dev);
+ module_put(dev->driver->owner);
return ret;
}
/* mark hwspinlock as used, should not fail */
- tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock->id,
+ tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock),
HWSPINLOCK_UNUSED);
/* self-sanity check that should never fail */
@@ -388,7 +444,7 @@ int hwspin_lock_get_id(struct hwspinlock *hwlock)
return -EINVAL;
}
- return hwlock->id;
+ return hwlock_to_id(hwlock);
}
EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
@@ -463,7 +519,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
}
/* sanity check (this shouldn't happen) */
- WARN_ON(hwlock->id != id);
+ WARN_ON(hwlock_to_id(hwlock) != id);
/* make sure this hwspinlock is unused */
ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
@@ -498,6 +554,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
*/
int hwspin_lock_free(struct hwspinlock *hwlock)
{
+ struct device *dev = hwlock->bank->dev;
struct hwspinlock *tmp;
int ret;
@@ -509,28 +566,28 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
mutex_lock(&hwspinlock_tree_lock);
/* make sure the hwspinlock is used */
- ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id,
+ ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
HWSPINLOCK_UNUSED);
if (ret == 1) {
- dev_err(hwlock->dev, "%s: hwlock is already free\n", __func__);
+ dev_err(dev, "%s: hwlock is already free\n", __func__);
dump_stack();
ret = -EINVAL;
goto out;
}
/* notify the underlying device that power is not needed */
- ret = pm_runtime_put(hwlock->dev);
+ ret = pm_runtime_put(dev);
if (ret < 0)
goto out;
/* mark this hwspinlock as available */
- tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id,
+ tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
HWSPINLOCK_UNUSED);
/* sanity check (this shouldn't happen) */
WARN_ON(tmp != hwlock);
- module_put(hwlock->owner);
+ module_put(dev->driver->owner);
out:
mutex_unlock(&hwspinlock_tree_lock);
diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h
index 69935e6..d26f78b 100644
--- a/drivers/hwspinlock/hwspinlock_internal.h
+++ b/drivers/hwspinlock/hwspinlock_internal.h
@@ -21,6 +21,8 @@
#include <linux/spinlock.h>
#include <linux/device.h>
+struct hwspinlock_device;
+
/**
* struct hwspinlock_ops - platform-specific hwspinlock handlers
*
@@ -39,23 +41,37 @@ struct hwspinlock_ops {
/**
* struct hwspinlock - this struct represents a single hwspinlock instance
- *
- * @dev: underlying device, will be used to invoke runtime PM api
- * @ops: platform-specific hwspinlock handlers
- * @id: a global, unique, system-wide, index of the lock.
+ * @bank: the hwspinlock_device structure which owns this lock
* @lock: initialized and used by hwspinlock core
- * @owner: underlying implementation module, used to maintain module ref count
- *
- * Note: currently simplicity was opted for, but later we can squeeze some
- * memory bytes by grouping the dev, ops and owner members in a single
- * per-platform struct, and have all hwspinlocks point at it.
+ * @priv: private data, owned by the underlying platform-specific hwspinlock drv
*/
struct hwspinlock {
+ struct hwspinlock_device *bank;
+ spinlock_t lock;
+ void *priv;
+};
+
+/**
+ * struct hwspinlock_device - a device which usually spans numerous hwspinlocks
+ * @dev: underlying device, will be used to invoke runtime PM api
+ * @ops: platform-specific hwspinlock handlers
+ * @base_id: id index of the first lock in this device
+ * @num_locks: number of locks in this device
+ * @lock: dynamically allocated array of 'struct hwspinlock'
+ */
+struct hwspinlock_device {
struct device *dev;
const struct hwspinlock_ops *ops;
- int id;
- spinlock_t lock;
- struct module *owner;
+ int base_id;
+ int num_locks;
+ struct hwspinlock lock[0];
};
+static inline int hwlock_to_id(struct hwspinlock *hwlock)
+{
+ int local_id = hwlock - &hwlock->bank->lock[0];
+
+ return hwlock->bank->base_id + local_id;
+}
+
#endif /* __HWSPINLOCK_HWSPINLOCK_H */
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index a8f0273..887d34e 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -41,33 +41,20 @@
#define SPINLOCK_NOTTAKEN (0) /* free */
#define SPINLOCK_TAKEN (1) /* locked */
-#define to_omap_hwspinlock(lock) \
- container_of(lock, struct omap_hwspinlock, lock)
-
-struct omap_hwspinlock {
- struct hwspinlock lock;
- void __iomem *addr;
-};
-
-struct omap_hwspinlock_state {
- int num_locks; /* Total number of locks in system */
- void __iomem *io_base; /* Mapped base address */
-};
-
static int omap_hwspinlock_trylock(struct hwspinlock *lock)
{
- struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock);
+ void __iomem *lock_addr = lock->priv;
/* attempt to acquire the lock by reading its value */
- return (SPINLOCK_NOTTAKEN == readl(omap_lock->addr));
+ return (SPINLOCK_NOTTAKEN == readl(lock_addr));
}
static void omap_hwspinlock_unlock(struct hwspinlock *lock)
{
- struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock);
+ void __iomem *lock_addr = lock->priv;
/* release the lock by writing 0 to it */
- writel(SPINLOCK_NOTTAKEN, omap_lock->addr);
+ writel(SPINLOCK_NOTTAKEN, lock_addr);
}
/*
@@ -93,26 +80,23 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
{
- struct omap_hwspinlock *omap_lock;
- struct omap_hwspinlock_state *state;
- struct hwspinlock *lock;
+ struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
+ struct hwspinlock_device *bank;
+ struct hwspinlock *hwlock;
struct resource *res;
void __iomem *io_base;
- int i, ret;
+ int num_locks, i, ret;
+
+ if (!pdata)
+ return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
-
io_base = ioremap(res->start, resource_size(res));
- if (!io_base) {
- ret = -ENOMEM;
- goto free_state;
- }
+ if (!io_base)
+ return -ENOMEM;
/* Determine number of locks */
i = readl(io_base + SYSSTATUS_OFFSET);
@@ -124,10 +108,18 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
goto iounmap_base;
}
- state->num_locks = i * 32;
- state->io_base = io_base;
+ num_locks = i * 32; /* actual number of locks in this device */
+
+ bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL);
+ if (!bank) {
+ ret = -ENOMEM;
+ goto iounmap_base;
+ }
+
+ platform_set_drvdata(pdev, bank);
- platform_set_drvdata(pdev, state);
+ for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
+ hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
/*
* runtime PM will make sure the clock of this module is
@@ -135,79 +127,46 @@ static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
*/
pm_runtime_enable(&pdev->dev);
- for (i = 0; i < state->num_locks; i++) {
- omap_lock = kzalloc(sizeof(*omap_lock), GFP_KERNEL);
- if (!omap_lock) {
- ret = -ENOMEM;
- goto free_locks;
- }
-
- omap_lock->lock.dev = &pdev->dev;
- omap_lock->lock.owner = THIS_MODULE;
- omap_lock->lock.id = i;
- omap_lock->lock.ops = &omap_hwspinlock_ops;
- omap_lock->addr = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
-
- ret = hwspin_lock_register(&omap_lock->lock);
- if (ret) {
- kfree(omap_lock);
- goto free_locks;
- }
- }
+ ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
+ pdata->base_id, num_locks);
+ if (ret)
+ goto reg_fail;
return 0;
-free_locks:
- while (--i >= 0) {
- lock = hwspin_lock_unregister(i);
- /* this should't happen, but let's give our best effort */
- if (!lock) {
- dev_err(&pdev->dev, "%s: cleanups failed\n", __func__);
- continue;
- }
- omap_lock = to_omap_hwspinlock(lock);
- kfree(omap_lock);
- }
+reg_fail:
pm_runtime_disable(&pdev->dev);
+ kfree(bank);
iounmap_base:
iounmap(io_base);
-free_state:
- kfree(state);
return ret;
}
-static int omap_hwspinlock_remove(struct platform_device *pdev)
+static int __devexit omap_hwspinlock_remove(struct platform_device *pdev)
{
- struct omap_hwspinlock_state *state = platform_get_drvdata(pdev);
- struct hwspinlock *lock;
- struct omap_hwspinlock *omap_lock;
- int i;
-
- for (i = 0; i < state->num_locks; i++) {
- lock = hwspin_lock_unregister(i);
- /* this shouldn't happen at this point. if it does, at least
- * don't continue with the remove */
- if (!lock) {
- dev_err(&pdev->dev, "%s: failed on %d\n", __func__, i);
- return -EBUSY;
- }
-
- omap_lock = to_omap_hwspinlock(lock);
- kfree(omap_lock);
+ struct hwspinlock_device *bank = platform_get_drvdata(pdev);
+ void __iomem *io_base = bank->lock[0].priv - LOCK_BASE_OFFSET;
+ int ret;
+
+ ret = hwspin_lock_unregister(bank);
+ if (ret) {
+ dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
+ return ret;
}
pm_runtime_disable(&pdev->dev);
- iounmap(state->io_base);
- kfree(state);
+ iounmap(io_base);
+ kfree(bank);
return 0;
}
static struct platform_driver omap_hwspinlock_driver = {
.probe = omap_hwspinlock_probe,
- .remove = omap_hwspinlock_remove,
+ .remove = __devexit_p(omap_hwspinlock_remove),
.driver = {
.name = "omap_hwspinlock",
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 30f06e9..5f13c62 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -7,7 +7,7 @@ menuconfig I2C
depends on HAS_IOMEM
select RT_MUTEXES
---help---
- I2C (pronounce: I-square-C) is a slow serial bus protocol used in
+ I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,
or System Management Bus is a subset of the I2C protocol. More
information is contained in the directory <file:Documentation/i2c/>,
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index f2ce8c3..24f94f4 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -47,8 +47,8 @@
/* ----- global variables --------------------------------------------- */
static int bit_test; /* see if the line-setting functions work */
-module_param(bit_test, bool, 0);
-MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+module_param(bit_test, int, S_IRUGO);
+MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck");
#ifdef DEBUG
static int i2c_debug = 1;
@@ -256,7 +256,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!scl || !sda) {
- printk(KERN_WARNING "%s: bus seems to be busy\n", name);
+ printk(KERN_WARNING
+ "%s: bus seems to be busy (scl=%d, sda=%d)\n",
+ name, scl, sda);
goto bailout;
}
@@ -447,7 +449,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
acknak(i2c_adap, 0);
dev_err(&i2c_adap->dev, "readbytes: invalid "
"block length (%d)\n", inval);
- return -EREMOTEIO;
+ return -EPROTO;
}
/* The original count value accounts for the extra
bytes, that is, either 1 for a regular transaction,
@@ -476,7 +478,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
* reads, writes as well as 10bit-addresses.
* returns:
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
- * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
+ * -x an error occurred (like: -ENXIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
@@ -499,14 +501,14 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if ((ret != 1) && !nak_ok) {
dev_err(&i2c_adap->dev,
"died at extended address code\n");
- return -EREMOTEIO;
+ return -ENXIO;
}
/* the remaining 8 bit address */
ret = i2c_outb(i2c_adap, msg->addr & 0xff);
if ((ret != 1) && !nak_ok) {
/* the chip did not ack / xmission error occurred */
dev_err(&i2c_adap->dev, "died at 2nd address code\n");
- return -EREMOTEIO;
+ return -ENXIO;
}
if (flags & I2C_M_RD) {
bit_dbg(3, &i2c_adap->dev, "emitting repeated "
@@ -518,7 +520,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if ((ret != 1) && !nak_ok) {
dev_err(&i2c_adap->dev,
"died at repeated address code\n");
- return -EREMOTEIO;
+ return -EIO;
}
}
} else { /* normal 7bit address */
@@ -576,7 +578,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
- ret = -EREMOTEIO;
+ ret = -EIO;
goto bailout;
}
} else {
@@ -587,7 +589,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
- ret = -EREMOTEIO;
+ ret = -EIO;
goto bailout;
}
}
@@ -630,7 +632,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (bit_test) {
ret = test_bus(adap);
- if (ret < 0)
+ if (bit_test >= 2 && ret < 0)
return -ENODEV;
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 4ca9cf9..beb9ffe 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -196,7 +196,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
} else {
dev_dbg(&i2c_adap->dev, "bus is not idle. status is "
"%#04x\n", state);
- return -EAGAIN;
+ return -EBUSY;
}
}
@@ -224,7 +224,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
}
curmsg = 0;
- ret = -EREMOTEIO;
+ ret = -EIO;
while (curmsg < num) {
state = pca_status(adap);
@@ -259,6 +259,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
DEB2("NOT ACK received after SLA+W\n");
pca_stop(adap);
+ ret = -ENXIO;
goto out;
case 0x40: /* SLA+R has been transmitted; ACK has been received */
@@ -283,6 +284,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
DEB2("NOT ACK received after SLA+R\n");
pca_stop(adap);
+ ret = -ENXIO;
goto out;
case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 646068e..949ea64 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -103,6 +103,8 @@ config I2C_I801
Patsburg (PCH)
DH89xxCC (PCH)
Panther Point (PCH)
+ Lynx Point (PCH)
+ Lynx Point-LP (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -110,7 +112,6 @@ config I2C_I801
config I2C_ISCH
tristate "Intel SCH SMBus 1.0"
depends on PCI
- select MFD_CORE
select LPC_SCH
help
Say Y here if you want to use SMBus controller on the Intel SCH
@@ -136,6 +137,8 @@ config I2C_PIIX4
ATI SB700
ATI SB800
AMD Hudson-2
+ AMD ML
+ AMD CZ
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -301,7 +304,7 @@ config I2C_AT91
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
- depends on SOC_AU1550 || SOC_AU1200
+ depends on MIPS_ALCHEMY
help
If you say yes to this option, support will be included for the
Au1550 and Au1200 SMBus interface.
@@ -350,15 +353,30 @@ config I2C_DAVINCI
devices such as DaVinci NIC.
For details please see http://www.ti.com/davinci
-config I2C_DESIGNWARE
- tristate "Synopsys DesignWare"
+config I2C_DESIGNWARE_CORE
+ tristate
+
+config I2C_DESIGNWARE_PLATFORM
+ tristate "Synopsys DesignWare Platfrom"
depends on HAVE_CLK
+ select I2C_DESIGNWARE_CORE
+ help
+ If you say yes to this option, support will be included for the
+ Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-designware-platform.
+
+config I2C_DESIGNWARE_PCI
+ tristate "Synopsys DesignWare PCI"
+ depends on PCI
+ select I2C_DESIGNWARE_CORE
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
This driver can also be built as a module. If so, the module
- will be called i2c-designware.
+ will be called i2c-designware-pci.
config I2C_GPIO
tristate "GPIO-based bitbanging I2C"
@@ -789,7 +807,7 @@ config I2C_ACORN
config I2C_ELEKTOR
tristate "Elektor ISA card"
- depends on ISA && BROKEN_ON_SMP
+ depends on ISA && HAS_IOPORT && BROKEN_ON_SMP
select I2C_ALGOPCF
help
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e6cf294..d6b8779 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,7 +33,11 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
-obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o
+obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
+obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
+i2c-designware-platform-objs := i2c-designware-platdrv.o
+obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
+i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index cd7ac5c..5b667e5 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -1,23 +1,23 @@
/*
- Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- Mark D. Studebaker <mdsxyz123@yahoo.com>,
- Dan Eaton <dan.eaton@rocketlogix.com> and
- Stephen Rousset<stephen.rousset@rocketlogix.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.
+ * Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
+ * Philip Edelbrock <phil@netroedge.com>,
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ * Dan Eaton <dan.eaton@rocketlogix.com> and
+ * Stephen Rousset <stephen.rousset@rocketlogix.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.
*/
/*
@@ -257,8 +257,8 @@ static int ali1535_transaction(struct i2c_adapter *adap)
if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
/* do a clear-on-write */
outb_p(0xFF, SMBHSTSTS);
- if ((temp = inb_p(SMBHSTSTS)) &
- (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+ temp = inb_p(SMBHSTSTS);
+ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
/* This is probably going to be correctable only by a
* power reset as one of the bits now appears to be
* stuck */
@@ -270,9 +270,8 @@ static int ali1535_transaction(struct i2c_adapter *adap)
}
} else {
/* check and clear done bit */
- if (temp & ALI1535_STS_DONE) {
+ if (temp & ALI1535_STS_DONE)
outb_p(temp, SMBHSTSTS);
- }
}
/* start the transaction by writing anything to the start register */
@@ -281,7 +280,7 @@ static int ali1535_transaction(struct i2c_adapter *adap)
/* We will always wait for a fraction of a second! */
timeout = 0;
do {
- msleep(1);
+ usleep_range(1000, 2000);
temp = inb_p(SMBHSTSTS);
} while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
&& (timeout++ < MAX_TIMEOUT));
@@ -328,12 +327,12 @@ static int ali1535_transaction(struct i2c_adapter *adap)
/* take consequent actions for error conditions */
if (!(temp & ALI1535_STS_DONE)) {
/* issue "kill" to reset host controller */
- outb_p(ALI1535_KILL,SMBHSTTYP);
- outb_p(0xFF,SMBHSTSTS);
+ outb_p(ALI1535_KILL, SMBHSTTYP);
+ outb_p(0xFF, SMBHSTSTS);
} else if (temp & ALI1535_STS_ERR) {
/* issue "timeout" to reset all devices on bus */
- outb_p(ALI1535_T_OUT,SMBHSTTYP);
- outb_p(0xFF,SMBHSTSTS);
+ outb_p(ALI1535_T_OUT, SMBHSTTYP);
+ outb_p(0xFF, SMBHSTSTS);
}
return result;
@@ -354,7 +353,7 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
for (timeout = 0;
(timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
timeout++) {
- msleep(1);
+ usleep_range(1000, 2000);
temp = inb_p(SMBHSTSTS);
}
if (timeout >= MAX_TIMEOUT)
@@ -483,12 +482,12 @@ static struct i2c_adapter ali1535_adapter = {
.algo = &smbus_algorithm,
};
-static const struct pci_device_id ali1535_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ },
};
-MODULE_DEVICE_TABLE (pci, ali1535_ids);
+MODULE_DEVICE_TABLE(pci, ali1535_ids);
static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 532828b..f314d7f 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -36,32 +36,44 @@
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
+#define PSC_SEL 0x00
+#define PSC_CTRL 0x04
+#define PSC_SMBCFG 0x08
+#define PSC_SMBMSK 0x0C
+#define PSC_SMBPCR 0x10
+#define PSC_SMBSTAT 0x14
+#define PSC_SMBEVNT 0x18
+#define PSC_SMBTXRX 0x1C
+#define PSC_SMBTMR 0x20
+
struct i2c_au1550_data {
- u32 psc_base;
+ void __iomem *psc_base;
int xfer_timeout;
- int ack_timeout;
struct i2c_adapter adap;
struct resource *ioarea;
};
-static int
-wait_xfer_done(struct i2c_au1550_data *adap)
+static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
{
- u32 stat;
- int i;
- volatile psc_smb_t *sp;
+ __raw_writel(v, a->psc_base + r);
+ wmb();
+}
- sp = (volatile psc_smb_t *)(adap->psc_base);
+static inline unsigned long RD(struct i2c_au1550_data *a, int r)
+{
+ return __raw_readl(a->psc_base + r);
+}
- /* Wait for Tx Buffer Empty
- */
+static int wait_xfer_done(struct i2c_au1550_data *adap)
+{
+ int i;
+
+ /* Wait for Tx Buffer Empty */
for (i = 0; i < adap->xfer_timeout; i++) {
- stat = sp->psc_smbstat;
- au_sync();
- if ((stat & PSC_SMBSTAT_TE) != 0)
+ if (RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_TE)
return 0;
udelay(1);
@@ -70,41 +82,27 @@ wait_xfer_done(struct i2c_au1550_data *adap)
return -ETIMEDOUT;
}
-static int
-wait_ack(struct i2c_au1550_data *adap)
+static int wait_ack(struct i2c_au1550_data *adap)
{
- u32 stat;
- volatile psc_smb_t *sp;
+ unsigned long stat;
if (wait_xfer_done(adap))
return -ETIMEDOUT;
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
- stat = sp->psc_smbevnt;
- au_sync();
-
+ stat = RD(adap, PSC_SMBEVNT);
if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
return -ETIMEDOUT;
return 0;
}
-static int
-wait_master_done(struct i2c_au1550_data *adap)
+static int wait_master_done(struct i2c_au1550_data *adap)
{
- u32 stat;
- int i;
- volatile psc_smb_t *sp;
+ int i;
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
- /* Wait for Master Done.
- */
- for (i = 0; i < adap->xfer_timeout; i++) {
- stat = sp->psc_smbevnt;
- au_sync();
- if ((stat & PSC_SMBEVNT_MD) != 0)
+ /* Wait for Master Done. */
+ for (i = 0; i < 2 * adap->xfer_timeout; i++) {
+ if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0)
return 0;
udelay(1);
}
@@ -115,29 +113,20 @@ wait_master_done(struct i2c_au1550_data *adap)
static int
do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
{
- volatile psc_smb_t *sp;
- u32 stat;
+ unsigned long stat;
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
- /* Reset the FIFOs, clear events.
- */
- stat = sp->psc_smbstat;
- sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
- au_sync();
+ /* Reset the FIFOs, clear events. */
+ stat = RD(adap, PSC_SMBSTAT);
+ WR(adap, PSC_SMBEVNT, PSC_SMBEVNT_ALLCLR);
if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
- sp->psc_smbpcr = PSC_SMBPCR_DC;
- au_sync();
- do {
- stat = sp->psc_smbpcr;
- au_sync();
- } while ((stat & PSC_SMBPCR_DC) != 0);
+ WR(adap, PSC_SMBPCR, PSC_SMBPCR_DC);
+ while ((RD(adap, PSC_SMBPCR) & PSC_SMBPCR_DC) != 0)
+ cpu_relax();
udelay(50);
}
- /* Write out the i2c chip address and specify operation
- */
+ /* Write out the i2c chip address and specify operation */
addr <<= 1;
if (rd)
addr |= 1;
@@ -146,56 +135,42 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
if (q)
addr |= PSC_SMBTXRX_STP;
- /* Put byte into fifo, start up master.
- */
- sp->psc_smbtxrx = addr;
- au_sync();
- sp->psc_smbpcr = PSC_SMBPCR_MS;
- au_sync();
+ /* Put byte into fifo, start up master. */
+ WR(adap, PSC_SMBTXRX, addr);
+ WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS);
if (wait_ack(adap))
return -EIO;
return (q) ? wait_master_done(adap) : 0;
}
-static u32
-wait_for_rx_byte(struct i2c_au1550_data *adap, u32 *ret_data)
+static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out)
{
- int j;
- u32 data, stat;
- volatile psc_smb_t *sp;
+ int j;
if (wait_xfer_done(adap))
return -EIO;
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
j = adap->xfer_timeout * 100;
do {
j--;
if (j <= 0)
return -EIO;
- stat = sp->psc_smbstat;
- au_sync();
- if ((stat & PSC_SMBSTAT_RE) == 0)
+ if ((RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_RE) == 0)
j = 0;
else
udelay(1);
} while (j > 0);
- data = sp->psc_smbtxrx;
- au_sync();
- *ret_data = data;
+
+ *out = RD(adap, PSC_SMBTXRX);
return 0;
}
-static int
-i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
+static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
unsigned int len)
{
- int i;
- u32 data;
- volatile psc_smb_t *sp;
+ int i;
if (len == 0)
return 0;
@@ -204,62 +179,46 @@ i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
* zero bytes for timing, waiting for bytes to appear in the
* receive fifo, then reading the bytes.
*/
-
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
i = 0;
- while (i < (len-1)) {
- sp->psc_smbtxrx = 0;
- au_sync();
- if (wait_for_rx_byte(adap, &data))
+ while (i < (len - 1)) {
+ WR(adap, PSC_SMBTXRX, 0);
+ if (wait_for_rx_byte(adap, &buf[i]))
return -EIO;
- buf[i] = data;
i++;
}
- /* The last byte has to indicate transfer done.
- */
- sp->psc_smbtxrx = PSC_SMBTXRX_STP;
- au_sync();
+ /* The last byte has to indicate transfer done. */
+ WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP);
if (wait_master_done(adap))
return -EIO;
- data = sp->psc_smbtxrx;
- au_sync();
- buf[i] = data;
+ buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff);
return 0;
}
-static int
-i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
+static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
unsigned int len)
{
- int i;
- u32 data;
- volatile psc_smb_t *sp;
+ int i;
+ unsigned long data;
if (len == 0)
return 0;
- sp = (volatile psc_smb_t *)(adap->psc_base);
-
i = 0;
while (i < (len-1)) {
data = buf[i];
- sp->psc_smbtxrx = data;
- au_sync();
+ WR(adap, PSC_SMBTXRX, data);
if (wait_ack(adap))
return -EIO;
i++;
}
- /* The last byte has to indicate transfer done.
- */
+ /* The last byte has to indicate transfer done. */
data = buf[i];
data |= PSC_SMBTXRX_STP;
- sp->psc_smbtxrx = data;
- au_sync();
+ WR(adap, PSC_SMBTXRX, data);
if (wait_master_done(adap))
return -EIO;
return 0;
@@ -269,12 +228,10 @@ static int
au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
{
struct i2c_au1550_data *adap = i2c_adap->algo_data;
- volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base;
struct i2c_msg *p;
int i, err = 0;
- sp->psc_ctrl = PSC_CTRL_ENABLE;
- au_sync();
+ WR(adap, PSC_CTRL, PSC_CTRL_ENABLE);
for (i = 0; !err && i < num; i++) {
p = &msgs[i];
@@ -293,14 +250,12 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
if (err == 0)
err = num;
- sp->psc_ctrl = PSC_CTRL_SUSPEND;
- au_sync();
+ WR(adap, PSC_CTRL, PSC_CTRL_SUSPEND);
return err;
}
-static u32
-au1550_func(struct i2c_adapter *adap)
+static u32 au1550_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
@@ -312,57 +267,45 @@ static const struct i2c_algorithm au1550_algo = {
static void i2c_au1550_setup(struct i2c_au1550_data *priv)
{
- volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
- u32 stat;
-
- sp->psc_ctrl = PSC_CTRL_DISABLE;
- au_sync();
- sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
- sp->psc_smbcfg = 0;
- au_sync();
- sp->psc_ctrl = PSC_CTRL_ENABLE;
- au_sync();
- do {
- stat = sp->psc_smbstat;
- au_sync();
- } while ((stat & PSC_SMBSTAT_SR) == 0);
+ unsigned long cfg;
- sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 |
- PSC_SMBCFG_DD_DISABLE);
+ WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
+ WR(priv, PSC_SEL, PSC_SEL_PS_SMBUSMODE);
+ WR(priv, PSC_SMBCFG, 0);
+ WR(priv, PSC_CTRL, PSC_CTRL_ENABLE);
+ while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+ cpu_relax();
+
+ cfg = PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | PSC_SMBCFG_DD_DISABLE;
+ WR(priv, PSC_SMBCFG, cfg);
/* Divide by 8 to get a 6.25 MHz clock. The later protocol
* timings are based on this clock.
*/
- sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
- sp->psc_smbmsk = PSC_SMBMSK_ALLMASK;
- au_sync();
+ cfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
+ WR(priv, PSC_SMBCFG, cfg);
+ WR(priv, PSC_SMBMSK, PSC_SMBMSK_ALLMASK);
/* Set the protocol timer values. See Table 71 in the
* Au1550 Data Book for standard timing values.
*/
- sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
+ WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
- PSC_SMBTMR_SET_CH(15);
- au_sync();
+ PSC_SMBTMR_SET_CH(15));
- sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE;
- do {
- stat = sp->psc_smbstat;
- au_sync();
- } while ((stat & PSC_SMBSTAT_SR) == 0);
+ cfg |= PSC_SMBCFG_DE_ENABLE;
+ WR(priv, PSC_SMBCFG, cfg);
+ while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+ cpu_relax();
- sp->psc_ctrl = PSC_CTRL_SUSPEND;
- au_sync();
+ WR(priv, PSC_CTRL, PSC_CTRL_SUSPEND);
}
static void i2c_au1550_disable(struct i2c_au1550_data *priv)
{
- volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
-
- sp->psc_smbcfg = 0;
- sp->psc_ctrl = PSC_CTRL_DISABLE;
- au_sync();
+ WR(priv, PSC_SMBCFG, 0);
+ WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
}
/*
@@ -396,9 +339,12 @@ i2c_au1550_probe(struct platform_device *pdev)
goto out_mem;
}
- priv->psc_base = CKSEG1ADDR(r->start);
+ priv->psc_base = ioremap(r->start, resource_size(r));
+ if (!priv->psc_base) {
+ ret = -EIO;
+ goto out_map;
+ }
priv->xfer_timeout = 200;
- priv->ack_timeout = 200;
priv->adap.nr = pdev->id;
priv->adap.algo = &au1550_algo;
@@ -406,8 +352,7 @@ i2c_au1550_probe(struct platform_device *pdev)
priv->adap.dev.parent = &pdev->dev;
strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
- /* Now, set up the PSC for SMBus PIO mode.
- */
+ /* Now, set up the PSC for SMBus PIO mode. */
i2c_au1550_setup(priv);
ret = i2c_add_numbered_adapter(&priv->adap);
@@ -417,7 +362,8 @@ i2c_au1550_probe(struct platform_device *pdev)
}
i2c_au1550_disable(priv);
-
+ iounmap(priv->psc_base);
+out_map:
release_resource(priv->ioarea);
kfree(priv->ioarea);
out_mem:
@@ -426,14 +372,14 @@ out:
return ret;
}
-static int __devexit
-i2c_au1550_remove(struct platform_device *pdev)
+static int __devexit i2c_au1550_remove(struct platform_device *pdev)
{
struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
i2c_del_adapter(&priv->adap);
i2c_au1550_disable(priv);
+ iounmap(priv->psc_base);
release_resource(priv->ioarea);
kfree(priv->ioarea);
kfree(priv);
@@ -441,49 +387,51 @@ i2c_au1550_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int
-i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
+static int i2c_au1550_suspend(struct device *dev)
{
- struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+ struct i2c_au1550_data *priv = dev_get_drvdata(dev);
i2c_au1550_disable(priv);
return 0;
}
-static int
-i2c_au1550_resume(struct platform_device *pdev)
+static int i2c_au1550_resume(struct device *dev)
{
- struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+ struct i2c_au1550_data *priv = dev_get_drvdata(dev);
i2c_au1550_setup(priv);
return 0;
}
+
+static const struct dev_pm_ops i2c_au1550_pmops = {
+ .suspend = i2c_au1550_suspend,
+ .resume = i2c_au1550_resume,
+};
+
+#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops)
+
#else
-#define i2c_au1550_suspend NULL
-#define i2c_au1550_resume NULL
+#define AU1XPSC_SMBUS_PMOPS NULL
#endif
static struct platform_driver au1xpsc_smbus_driver = {
.driver = {
.name = "au1xpsc_smbus",
.owner = THIS_MODULE,
+ .pm = AU1XPSC_SMBUS_PMOPS,
},
.probe = i2c_au1550_probe,
.remove = __devexit_p(i2c_au1550_remove),
- .suspend = i2c_au1550_suspend,
- .resume = i2c_au1550_resume,
};
-static int __init
-i2c_au1550_init(void)
+static int __init i2c_au1550_init(void)
{
return platform_driver_register(&au1xpsc_smbus_driver);
}
-static void __exit
-i2c_au1550_exit(void)
+static void __exit i2c_au1550_exit(void)
{
platform_driver_unregister(&au1xpsc_smbus_driver);
}
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index cbc98ae..cdb59e5 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -631,7 +631,7 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
- IRQF_DISABLED, pdev->name, iface);
+ 0, pdev->name, iface);
if (rc) {
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
return -ENODEV;
@@ -702,7 +702,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
}
rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
- IRQF_DISABLED, pdev->name, iface);
+ 0, pdev->name, iface);
if (rc) {
dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
rc = -ENODEV;
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 3a20961..b1d9cd2 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -662,11 +662,8 @@ static int __devinit cpm_i2c_probe(struct platform_device *ofdev)
/* register new adapter to i2c module... */
data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len);
- if (data && len == 4) {
- cpm->adap.nr = *data;
- result = i2c_add_numbered_adapter(&cpm->adap);
- } else
- result = i2c_add_adapter(&cpm->adap);
+ cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1;
+ result = i2c_add_numbered_adapter(&cpm->adap);
if (result < 0) {
dev_err(&ofdev->dev, "Unable to register with I2C\n");
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 79b4bcb..1837fe6 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -416,11 +416,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return msg->len;
- if (stop) {
- w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
- w |= DAVINCI_I2C_MDR_STP;
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
- }
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
return -EREMOTEIO;
}
return -EIO;
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
deleted file mode 100644
index b7a51c4..0000000
--- a/drivers/i2c/busses/i2c-designware.c
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- * Synopsys DesignWare I2C adapter driver (master only).
- *
- * Based on the TI DAVINCI I2C adapter driver.
- *
- * Copyright (C) 2006 Texas Instruments.
- * Copyright (C) 2007 MontaVista Software Inc.
- * Copyright (C) 2009 Provigent Ltd.
- *
- * ----------------------------------------------------------------------------
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * ----------------------------------------------------------------------------
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/clk.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-/*
- * Registers offset
- */
-#define DW_IC_CON 0x0
-#define DW_IC_TAR 0x4
-#define DW_IC_DATA_CMD 0x10
-#define DW_IC_SS_SCL_HCNT 0x14
-#define DW_IC_SS_SCL_LCNT 0x18
-#define DW_IC_FS_SCL_HCNT 0x1c
-#define DW_IC_FS_SCL_LCNT 0x20
-#define DW_IC_INTR_STAT 0x2c
-#define DW_IC_INTR_MASK 0x30
-#define DW_IC_RAW_INTR_STAT 0x34
-#define DW_IC_RX_TL 0x38
-#define DW_IC_TX_TL 0x3c
-#define DW_IC_CLR_INTR 0x40
-#define DW_IC_CLR_RX_UNDER 0x44
-#define DW_IC_CLR_RX_OVER 0x48
-#define DW_IC_CLR_TX_OVER 0x4c
-#define DW_IC_CLR_RD_REQ 0x50
-#define DW_IC_CLR_TX_ABRT 0x54
-#define DW_IC_CLR_RX_DONE 0x58
-#define DW_IC_CLR_ACTIVITY 0x5c
-#define DW_IC_CLR_STOP_DET 0x60
-#define DW_IC_CLR_START_DET 0x64
-#define DW_IC_CLR_GEN_CALL 0x68
-#define DW_IC_ENABLE 0x6c
-#define DW_IC_STATUS 0x70
-#define DW_IC_TXFLR 0x74
-#define DW_IC_RXFLR 0x78
-#define DW_IC_COMP_PARAM_1 0xf4
-#define DW_IC_TX_ABRT_SOURCE 0x80
-
-#define DW_IC_CON_MASTER 0x1
-#define DW_IC_CON_SPEED_STD 0x2
-#define DW_IC_CON_SPEED_FAST 0x4
-#define DW_IC_CON_10BITADDR_MASTER 0x10
-#define DW_IC_CON_RESTART_EN 0x20
-#define DW_IC_CON_SLAVE_DISABLE 0x40
-
-#define DW_IC_INTR_RX_UNDER 0x001
-#define DW_IC_INTR_RX_OVER 0x002
-#define DW_IC_INTR_RX_FULL 0x004
-#define DW_IC_INTR_TX_OVER 0x008
-#define DW_IC_INTR_TX_EMPTY 0x010
-#define DW_IC_INTR_RD_REQ 0x020
-#define DW_IC_INTR_TX_ABRT 0x040
-#define DW_IC_INTR_RX_DONE 0x080
-#define DW_IC_INTR_ACTIVITY 0x100
-#define DW_IC_INTR_STOP_DET 0x200
-#define DW_IC_INTR_START_DET 0x400
-#define DW_IC_INTR_GEN_CALL 0x800
-
-#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
- DW_IC_INTR_TX_EMPTY | \
- DW_IC_INTR_TX_ABRT | \
- DW_IC_INTR_STOP_DET)
-
-#define DW_IC_STATUS_ACTIVITY 0x1
-
-#define DW_IC_ERR_TX_ABRT 0x1
-
-/*
- * status codes
- */
-#define STATUS_IDLE 0x0
-#define STATUS_WRITE_IN_PROGRESS 0x1
-#define STATUS_READ_IN_PROGRESS 0x2
-
-#define TIMEOUT 20 /* ms */
-
-/*
- * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
- *
- * only expected abort codes are listed here
- * refer to the datasheet for the full list
- */
-#define ABRT_7B_ADDR_NOACK 0
-#define ABRT_10ADDR1_NOACK 1
-#define ABRT_10ADDR2_NOACK 2
-#define ABRT_TXDATA_NOACK 3
-#define ABRT_GCALL_NOACK 4
-#define ABRT_GCALL_READ 5
-#define ABRT_SBYTE_ACKDET 7
-#define ABRT_SBYTE_NORSTRT 9
-#define ABRT_10B_RD_NORSTRT 10
-#define ABRT_MASTER_DIS 11
-#define ARB_LOST 12
-
-#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
-#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
-#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
-#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
-#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
-#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
-#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
-#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
-#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
-#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
-#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
-
-#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
- DW_IC_TX_ABRT_10ADDR1_NOACK | \
- DW_IC_TX_ABRT_10ADDR2_NOACK | \
- DW_IC_TX_ABRT_TXDATA_NOACK | \
- DW_IC_TX_ABRT_GCALL_NOACK)
-
-static char *abort_sources[] = {
- [ABRT_7B_ADDR_NOACK] =
- "slave address not acknowledged (7bit mode)",
- [ABRT_10ADDR1_NOACK] =
- "first address byte not acknowledged (10bit mode)",
- [ABRT_10ADDR2_NOACK] =
- "second address byte not acknowledged (10bit mode)",
- [ABRT_TXDATA_NOACK] =
- "data not acknowledged",
- [ABRT_GCALL_NOACK] =
- "no acknowledgement for a general call",
- [ABRT_GCALL_READ] =
- "read after general call",
- [ABRT_SBYTE_ACKDET] =
- "start byte acknowledged",
- [ABRT_SBYTE_NORSTRT] =
- "trying to send start byte when restart is disabled",
- [ABRT_10B_RD_NORSTRT] =
- "trying to read when restart is disabled (10bit mode)",
- [ABRT_MASTER_DIS] =
- "trying to use disabled adapter",
- [ARB_LOST] =
- "lost arbitration",
-};
-
-/**
- * struct dw_i2c_dev - private i2c-designware data
- * @dev: driver model device node
- * @base: IO registers pointer
- * @cmd_complete: tx completion indicator
- * @lock: protect this struct and IO registers
- * @clk: input reference clock
- * @cmd_err: run time hadware error code
- * @msgs: points to an array of messages currently being transferred
- * @msgs_num: the number of elements in msgs
- * @msg_write_idx: the element index of the current tx message in the msgs
- * array
- * @tx_buf_len: the length of the current tx buffer
- * @tx_buf: the current tx buffer
- * @msg_read_idx: the element index of the current rx message in the msgs
- * array
- * @rx_buf_len: the length of the current rx buffer
- * @rx_buf: the current rx buffer
- * @msg_err: error status of the current transfer
- * @status: i2c master status, one of STATUS_*
- * @abort_source: copy of the TX_ABRT_SOURCE register
- * @irq: interrupt number for the i2c master
- * @adapter: i2c subsystem adapter node
- * @tx_fifo_depth: depth of the hardware tx fifo
- * @rx_fifo_depth: depth of the hardware rx fifo
- */
-struct dw_i2c_dev {
- struct device *dev;
- void __iomem *base;
- struct completion cmd_complete;
- struct mutex lock;
- struct clk *clk;
- int cmd_err;
- struct i2c_msg *msgs;
- int msgs_num;
- int msg_write_idx;
- u32 tx_buf_len;
- u8 *tx_buf;
- int msg_read_idx;
- u32 rx_buf_len;
- u8 *rx_buf;
- int msg_err;
- unsigned int status;
- u32 abort_source;
- int irq;
- struct i2c_adapter adapter;
- unsigned int tx_fifo_depth;
- unsigned int rx_fifo_depth;
-};
-
-static u32
-i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
-{
- /*
- * DesignWare I2C core doesn't seem to have solid strategy to meet
- * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
- * will result in violation of the tHD;STA spec.
- */
- if (cond)
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
- *
- * This is based on the DW manuals, and represents an ideal
- * configuration. The resulting I2C bus speed will be
- * faster than any of the others.
- *
- * If your hardware is free from tHD;STA issue, try this one.
- */
- return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
- else
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
- *
- * This is just experimental rule; the tHD;STA period turned
- * out to be proportinal to (_HCNT + 3). With this setting,
- * we could meet both tHIGH and tHD;STA timing specs.
- *
- * If unsure, you'd better to take this alternative.
- *
- * The reason why we need to take into account "tf" here,
- * is the same as described in i2c_dw_scl_lcnt().
- */
- return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
-}
-
-static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
-{
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
- *
- * DW I2C core starts counting the SCL CNTs for the LOW period
- * of the SCL clock (tLOW) as soon as it pulls the SCL line.
- * In order to meet the tLOW timing spec, we need to take into
- * account the fall time of SCL signal (tf). Default tf value
- * should be 0.3 us, for safety.
- */
- return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
-}
-
-/**
- * i2c_dw_init() - initialize the designware i2c master hardware
- * @dev: device private data
- *
- * This functions configures and enables the I2C master.
- * This function is called during I2C init function, and in case of timeout at
- * run time.
- */
-static void i2c_dw_init(struct dw_i2c_dev *dev)
-{
- u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
- u32 ic_con, hcnt, lcnt;
-
- /* Disable the adapter */
- writel(0, dev->base + DW_IC_ENABLE);
-
- /* set standard and fast speed deviders for high/low periods */
-
- /* Standard-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 40, /* tHD;STA = tHIGH = 4.0 us */
- 3, /* tf = 0.3 us */
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 47, /* tLOW = 4.7 us */
- 3, /* tf = 0.3 us */
- 0); /* No offset */
- writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT);
- writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT);
- dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
-
- /* Fast-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 6, /* tHD;STA = tHIGH = 0.6 us */
- 3, /* tf = 0.3 us */
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 13, /* tLOW = 1.3 us */
- 3, /* tf = 0.3 us */
- 0); /* No offset */
- writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT);
- writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT);
- dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
-
- /* Configure Tx/Rx FIFO threshold levels */
- writel(dev->tx_fifo_depth - 1, dev->base + DW_IC_TX_TL);
- writel(0, dev->base + DW_IC_RX_TL);
-
- /* configure the i2c master */
- ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
- writel(ic_con, dev->base + DW_IC_CON);
-}
-
-/*
- * Waiting for bus not busy
- */
-static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
-{
- int timeout = TIMEOUT;
-
- while (readl(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
- if (timeout <= 0) {
- dev_warn(dev->dev, "timeout waiting for bus ready\n");
- return -ETIMEDOUT;
- }
- timeout--;
- mdelay(1);
- }
-
- return 0;
-}
-
-static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
-{
- struct i2c_msg *msgs = dev->msgs;
- u32 ic_con;
-
- /* Disable the adapter */
- writel(0, dev->base + DW_IC_ENABLE);
-
- /* set the slave (target) address */
- writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR);
-
- /* if the slave address is ten bit address, enable 10BITADDR */
- ic_con = readl(dev->base + DW_IC_CON);
- if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
- ic_con |= DW_IC_CON_10BITADDR_MASTER;
- else
- ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
- writel(ic_con, dev->base + DW_IC_CON);
-
- /* Enable the adapter */
- writel(1, dev->base + DW_IC_ENABLE);
-
- /* Enable interrupts */
- writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK);
-}
-
-/*
- * Initiate (and continue) low level master read/write transaction.
- * This function is only called from i2c_dw_isr, and pumping i2c_msg
- * messages into the tx buffer. Even if the size of i2c_msg data is
- * longer than the size of the tx buffer, it handles everything.
- */
-static void
-i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
-{
- struct i2c_msg *msgs = dev->msgs;
- u32 intr_mask;
- int tx_limit, rx_limit;
- u32 addr = msgs[dev->msg_write_idx].addr;
- u32 buf_len = dev->tx_buf_len;
- u8 *buf = dev->tx_buf;;
-
- intr_mask = DW_IC_INTR_DEFAULT_MASK;
-
- for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
- /*
- * if target address has changed, we need to
- * reprogram the target address in the i2c
- * adapter when we are done with this transfer
- */
- if (msgs[dev->msg_write_idx].addr != addr) {
- dev_err(dev->dev,
- "%s: invalid target address\n", __func__);
- dev->msg_err = -EINVAL;
- break;
- }
-
- if (msgs[dev->msg_write_idx].len == 0) {
- dev_err(dev->dev,
- "%s: invalid message length\n", __func__);
- dev->msg_err = -EINVAL;
- break;
- }
-
- if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
- /* new i2c_msg */
- buf = msgs[dev->msg_write_idx].buf;
- buf_len = msgs[dev->msg_write_idx].len;
- }
-
- tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR);
- rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR);
-
- while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
- if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
- writel(0x100, dev->base + DW_IC_DATA_CMD);
- rx_limit--;
- } else
- writel(*buf++, dev->base + DW_IC_DATA_CMD);
- tx_limit--; buf_len--;
- }
-
- dev->tx_buf = buf;
- dev->tx_buf_len = buf_len;
-
- if (buf_len > 0) {
- /* more bytes to be written */
- dev->status |= STATUS_WRITE_IN_PROGRESS;
- break;
- } else
- dev->status &= ~STATUS_WRITE_IN_PROGRESS;
- }
-
- /*
- * If i2c_msg index search is completed, we don't need TX_EMPTY
- * interrupt any more.
- */
- if (dev->msg_write_idx == dev->msgs_num)
- intr_mask &= ~DW_IC_INTR_TX_EMPTY;
-
- if (dev->msg_err)
- intr_mask = 0;
-
- writel(intr_mask, dev->base + DW_IC_INTR_MASK);
-}
-
-static void
-i2c_dw_read(struct dw_i2c_dev *dev)
-{
- struct i2c_msg *msgs = dev->msgs;
- int rx_valid;
-
- for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
- u32 len;
- u8 *buf;
-
- if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
- continue;
-
- if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
- len = msgs[dev->msg_read_idx].len;
- buf = msgs[dev->msg_read_idx].buf;
- } else {
- len = dev->rx_buf_len;
- buf = dev->rx_buf;
- }
-
- rx_valid = readl(dev->base + DW_IC_RXFLR);
-
- for (; len > 0 && rx_valid > 0; len--, rx_valid--)
- *buf++ = readl(dev->base + DW_IC_DATA_CMD);
-
- if (len > 0) {
- dev->status |= STATUS_READ_IN_PROGRESS;
- dev->rx_buf_len = len;
- dev->rx_buf = buf;
- return;
- } else
- dev->status &= ~STATUS_READ_IN_PROGRESS;
- }
-}
-
-static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
-{
- unsigned long abort_source = dev->abort_source;
- int i;
-
- if (abort_source & DW_IC_TX_ABRT_NOACK) {
- for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
- dev_dbg(dev->dev,
- "%s: %s\n", __func__, abort_sources[i]);
- return -EREMOTEIO;
- }
-
- for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
- dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
-
- if (abort_source & DW_IC_TX_ARB_LOST)
- return -EAGAIN;
- else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
- return -EINVAL; /* wrong msgs[] data */
- else
- return -EIO;
-}
-
-/*
- * Prepare controller for a transaction and call i2c_dw_xfer_msg
- */
-static int
-i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
-{
- struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
- int ret;
-
- dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
-
- mutex_lock(&dev->lock);
-
- INIT_COMPLETION(dev->cmd_complete);
- dev->msgs = msgs;
- dev->msgs_num = num;
- dev->cmd_err = 0;
- dev->msg_write_idx = 0;
- dev->msg_read_idx = 0;
- dev->msg_err = 0;
- dev->status = STATUS_IDLE;
- dev->abort_source = 0;
-
- ret = i2c_dw_wait_bus_not_busy(dev);
- if (ret < 0)
- goto done;
-
- /* start the transfers */
- i2c_dw_xfer_init(dev);
-
- /* wait for tx to complete */
- ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
- if (ret == 0) {
- dev_err(dev->dev, "controller timed out\n");
- i2c_dw_init(dev);
- ret = -ETIMEDOUT;
- goto done;
- } else if (ret < 0)
- goto done;
-
- if (dev->msg_err) {
- ret = dev->msg_err;
- goto done;
- }
-
- /* no error */
- if (likely(!dev->cmd_err)) {
- /* Disable the adapter */
- writel(0, dev->base + DW_IC_ENABLE);
- ret = num;
- goto done;
- }
-
- /* We have an error */
- if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
- ret = i2c_dw_handle_tx_abort(dev);
- goto done;
- }
- ret = -EIO;
-
-done:
- mutex_unlock(&dev->lock);
-
- return ret;
-}
-
-static u32 i2c_dw_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C |
- I2C_FUNC_10BIT_ADDR |
- I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK;
-}
-
-static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
-{
- u32 stat;
-
- /*
- * The IC_INTR_STAT register just indicates "enabled" interrupts.
- * Ths unmasked raw version of interrupt status bits are available
- * in the IC_RAW_INTR_STAT register.
- *
- * That is,
- * stat = readl(IC_INTR_STAT);
- * equals to,
- * stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK);
- *
- * The raw version might be useful for debugging purposes.
- */
- stat = readl(dev->base + DW_IC_INTR_STAT);
-
- /*
- * Do not use the IC_CLR_INTR register to clear interrupts, or
- * you'll miss some interrupts, triggered during the period from
- * readl(IC_INTR_STAT) to readl(IC_CLR_INTR).
- *
- * Instead, use the separately-prepared IC_CLR_* registers.
- */
- if (stat & DW_IC_INTR_RX_UNDER)
- readl(dev->base + DW_IC_CLR_RX_UNDER);
- if (stat & DW_IC_INTR_RX_OVER)
- readl(dev->base + DW_IC_CLR_RX_OVER);
- if (stat & DW_IC_INTR_TX_OVER)
- readl(dev->base + DW_IC_CLR_TX_OVER);
- if (stat & DW_IC_INTR_RD_REQ)
- readl(dev->base + DW_IC_CLR_RD_REQ);
- if (stat & DW_IC_INTR_TX_ABRT) {
- /*
- * The IC_TX_ABRT_SOURCE register is cleared whenever
- * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
- */
- dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE);
- readl(dev->base + DW_IC_CLR_TX_ABRT);
- }
- if (stat & DW_IC_INTR_RX_DONE)
- readl(dev->base + DW_IC_CLR_RX_DONE);
- if (stat & DW_IC_INTR_ACTIVITY)
- readl(dev->base + DW_IC_CLR_ACTIVITY);
- if (stat & DW_IC_INTR_STOP_DET)
- readl(dev->base + DW_IC_CLR_STOP_DET);
- if (stat & DW_IC_INTR_START_DET)
- readl(dev->base + DW_IC_CLR_START_DET);
- if (stat & DW_IC_INTR_GEN_CALL)
- readl(dev->base + DW_IC_CLR_GEN_CALL);
-
- return stat;
-}
-
-/*
- * Interrupt service routine. This gets called whenever an I2C interrupt
- * occurs.
- */
-static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
-{
- struct dw_i2c_dev *dev = dev_id;
- u32 stat;
-
- stat = i2c_dw_read_clear_intrbits(dev);
- dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
-
- if (stat & DW_IC_INTR_TX_ABRT) {
- dev->cmd_err |= DW_IC_ERR_TX_ABRT;
- dev->status = STATUS_IDLE;
-
- /*
- * Anytime TX_ABRT is set, the contents of the tx/rx
- * buffers are flushed. Make sure to skip them.
- */
- writel(0, dev->base + DW_IC_INTR_MASK);
- goto tx_aborted;
- }
-
- if (stat & DW_IC_INTR_RX_FULL)
- i2c_dw_read(dev);
-
- if (stat & DW_IC_INTR_TX_EMPTY)
- i2c_dw_xfer_msg(dev);
-
- /*
- * No need to modify or disable the interrupt mask here.
- * i2c_dw_xfer_msg() will take care of it according to
- * the current transmit status.
- */
-
-tx_aborted:
- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
- complete(&dev->cmd_complete);
-
- return IRQ_HANDLED;
-}
-
-static struct i2c_algorithm i2c_dw_algo = {
- .master_xfer = i2c_dw_xfer,
- .functionality = i2c_dw_func,
-};
-
-static int __devinit dw_i2c_probe(struct platform_device *pdev)
-{
- struct dw_i2c_dev *dev;
- struct i2c_adapter *adap;
- struct resource *mem, *ioarea;
- int irq, r;
-
- /* NOTE: driver uses the static register mapping */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "no irq resource?\n");
- return irq; /* -ENXIO */
- }
-
- ioarea = request_mem_region(mem->start, resource_size(mem),
- pdev->name);
- if (!ioarea) {
- dev_err(&pdev->dev, "I2C region already claimed\n");
- return -EBUSY;
- }
-
- dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
- if (!dev) {
- r = -ENOMEM;
- goto err_release_region;
- }
-
- init_completion(&dev->cmd_complete);
- mutex_init(&dev->lock);
- dev->dev = get_device(&pdev->dev);
- dev->irq = irq;
- platform_set_drvdata(pdev, dev);
-
- dev->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(dev->clk)) {
- r = -ENODEV;
- goto err_free_mem;
- }
- clk_enable(dev->clk);
-
- dev->base = ioremap(mem->start, resource_size(mem));
- if (dev->base == NULL) {
- dev_err(&pdev->dev, "failure mapping io resources\n");
- r = -EBUSY;
- goto err_unuse_clocks;
- }
- {
- u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1);
-
- dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
- dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
- }
- i2c_dw_init(dev);
-
- writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
- r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
- if (r) {
- dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
- goto err_iounmap;
- }
-
- adap = &dev->adapter;
- i2c_set_adapdata(adap, dev);
- adap->owner = THIS_MODULE;
- adap->class = I2C_CLASS_HWMON;
- strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
- sizeof(adap->name));
- adap->algo = &i2c_dw_algo;
- adap->dev.parent = &pdev->dev;
-
- adap->nr = pdev->id;
- r = i2c_add_numbered_adapter(adap);
- if (r) {
- dev_err(&pdev->dev, "failure adding adapter\n");
- goto err_free_irq;
- }
-
- return 0;
-
-err_free_irq:
- free_irq(dev->irq, dev);
-err_iounmap:
- iounmap(dev->base);
-err_unuse_clocks:
- clk_disable(dev->clk);
- clk_put(dev->clk);
- dev->clk = NULL;
-err_free_mem:
- platform_set_drvdata(pdev, NULL);
- put_device(&pdev->dev);
- kfree(dev);
-err_release_region:
- release_mem_region(mem->start, resource_size(mem));
-
- return r;
-}
-
-static int __devexit dw_i2c_remove(struct platform_device *pdev)
-{
- struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
- struct resource *mem;
-
- platform_set_drvdata(pdev, NULL);
- i2c_del_adapter(&dev->adapter);
- put_device(&pdev->dev);
-
- clk_disable(dev->clk);
- clk_put(dev->clk);
- dev->clk = NULL;
-
- writel(0, dev->base + DW_IC_ENABLE);
- free_irq(dev->irq, dev);
- kfree(dev);
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, resource_size(mem));
- return 0;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:i2c_designware");
-
-static struct platform_driver dw_i2c_driver = {
- .remove = __devexit_p(dw_i2c_remove),
- .driver = {
- .name = "i2c_designware",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init dw_i2c_init_driver(void)
-{
- return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
-}
-module_init(dw_i2c_init_driver);
-
-static void __exit dw_i2c_exit_driver(void)
-{
- platform_driver_unregister(&dw_i2c_driver);
-}
-module_exit(dw_i2c_exit_driver);
-
-MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
-MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 656b028..2cda65bf 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -64,6 +64,7 @@
#define TEN_BIT_ADDR_DEFAULT 0xF000
#define TEN_BIT_ADDR_MASK 0xF0
#define PCH_START 0x0020
+#define PCH_RESTART 0x0004
#define PCH_ESR_START 0x0001
#define PCH_BUFF_START 0x1
#define PCH_REPSTART 0x0004
@@ -273,23 +274,24 @@ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
s32 timeout)
{
void __iomem *p = adap->pch_base_address;
+ ktime_t ns_val;
+
+ if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
+ return 0;
/* MAX timeout value is timeout*1000*1000nsec */
- ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
+ ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
do {
- if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
- break;
msleep(20);
+ if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
+ return 0;
} while (ktime_lt(ktime_get(), ns_val));
pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+ pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
+ pch_i2c_init(adap);
- if (timeout == 0) {
- pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
- return -ETIME;
- }
-
- return 0;
+ return -ETIME;
}
/**
@@ -311,21 +313,19 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap)
*/
static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap)
{
- s32 ret;
+ long ret;
ret = wait_event_timeout(pch_event,
- (adap->pch_event_flag != 0), msecs_to_jiffies(50));
- if (ret < 0) {
- pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
- return ret;
- }
+ (adap->pch_event_flag != 0), msecs_to_jiffies(1000));
if (ret == 0) {
pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+ adap->pch_event_flag = 0;
return -ETIMEDOUT;
}
if (adap->pch_event_flag & I2C_ERROR_MASK) {
pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
+ adap->pch_event_flag = 0;
return -EIO;
}
@@ -394,6 +394,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
u32 addr_2_msb;
u32 addr_8_lsb;
s32 wrcount;
+ s32 rtn;
void __iomem *p = adap->pch_base_address;
length = msgs->len;
@@ -412,15 +413,29 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
}
if (msgs->flags & I2C_M_TEN) {
- addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
if (first)
pch_i2c_start(adap);
- if (pch_i2c_wait_for_xfer_complete(adap) == 0 &&
- pch_i2c_getack(adap) == 0) {
+
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
+ return -EIO;
+ }
addr_8_lsb = (addr & I2C_ADDR_MSK);
iowrite32(addr_8_lsb, p + PCH_I2CDR);
- } else {
+ } else if (rtn == -EIO) { /* Arbitration Lost */
+ pch_err(adap, "Lost Arbitration\n");
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ } else { /* wait-event timeout */
pch_i2c_stop(adap);
return -ETIME;
}
@@ -431,30 +446,51 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
pch_i2c_start(adap);
}
- if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
- (pch_i2c_getack(adap) == 0)) {
- for (wrcount = 0; wrcount < length; ++wrcount) {
- /* write buffer value to I2C data register */
- iowrite32(buf[wrcount], p + PCH_I2CDR);
- pch_dbg(adap, "writing %x to Data register\n",
- buf[wrcount]);
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
+ return -EIO;
+ }
+ } else if (rtn == -EIO) { /* Arbitration Lost */
+ pch_err(adap, "Lost Arbitration\n");
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
- if (pch_i2c_wait_for_xfer_complete(adap) != 0)
- return -ETIME;
+ for (wrcount = 0; wrcount < length; ++wrcount) {
+ /* write buffer value to I2C data register */
+ iowrite32(buf[wrcount], p + PCH_I2CDR);
+ pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
- if (pch_i2c_getack(adap))
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
return -EIO;
+ }
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMCF_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMIF_BIT);
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
}
+ }
- /* check if this is the last message */
- if (last)
- pch_i2c_stop(adap);
- else
- pch_i2c_repstart(adap);
- } else {
+ /* check if this is the last message */
+ if (last)
pch_i2c_stop(adap);
- return -EIO;
- }
+ else
+ pch_i2c_repstart(adap);
pch_dbg(adap, "return=%d\n", wrcount);
@@ -484,6 +520,19 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
}
/**
+ * pch_i2c_restart() - Generate I2C restart condition in normal mode.
+ * @adap: Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA.
+ */
+static void pch_i2c_restart(struct i2c_algo_pch_data *adap)
+{
+ void __iomem *p = adap->pch_base_address;
+ pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART);
+}
+
+/**
* pch_i2c_readbytes() - read data from I2C bus in normal mode.
* @i2c_adap: Pointer to the struct i2c_adapter.
* @msgs: Pointer to i2c_msg structure.
@@ -500,7 +549,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
u32 length;
u32 addr;
u32 addr_2_msb;
+ u32 addr_8_lsb;
void __iomem *p = adap->pch_base_address;
+ s32 rtn;
length = msgs->len;
buf = msgs->buf;
@@ -515,9 +566,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
}
if (msgs->flags & I2C_M_TEN) {
- addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD));
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ if (first)
+ pch_i2c_start(adap);
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
+ return -EIO;
+ }
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ } else if (rtn == -EIO) { /* Arbitration Lost */
+ pch_err(adap, "Lost Arbitration\n");
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
+ pch_i2c_restart(adap);
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
+ return -EIO;
+ }
+ addr_2_msb |= I2C_RD;
+ iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK,
+ p + PCH_I2CDR);
+ } else if (rtn == -EIO) { /* Arbitration Lost */
+ pch_err(adap, "Lost Arbitration\n");
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+ I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
} else {
/* 7 address bits + R/W bit */
addr = (((addr) << 1) | (I2C_RD));
@@ -528,56 +625,81 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
if (first)
pch_i2c_start(adap);
- if ((pch_i2c_wait_for_xfer_complete(adap) == 0) &&
- (pch_i2c_getack(adap) == 0)) {
- pch_dbg(adap, "return %d\n", 0);
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave address"
+ "setting\n");
+ return -EIO;
+ }
+ } else if (rtn == -EIO) { /* Arbitration Lost */
+ pch_err(adap, "Lost Arbitration\n");
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
+ pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+ pch_i2c_init(adap);
+ return -EAGAIN;
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
- if (length == 0) {
- pch_i2c_stop(adap);
- ioread32(p + PCH_I2CDR); /* Dummy read needs */
+ if (length == 0) {
+ pch_i2c_stop(adap);
+ ioread32(p + PCH_I2CDR); /* Dummy read needs */
- count = length;
- } else {
- int read_index;
- int loop;
- pch_i2c_sendack(adap);
+ count = length;
+ } else {
+ int read_index;
+ int loop;
+ pch_i2c_sendack(adap);
- /* Dummy read */
- for (loop = 1, read_index = 0; loop < length; loop++) {
- buf[read_index] = ioread32(p + PCH_I2CDR);
+ /* Dummy read */
+ for (loop = 1, read_index = 0; loop < length; loop++) {
+ buf[read_index] = ioread32(p + PCH_I2CDR);
- if (loop != 1)
- read_index++;
+ if (loop != 1)
+ read_index++;
- if (pch_i2c_wait_for_xfer_complete(adap) != 0) {
- pch_i2c_stop(adap);
- return -ETIME;
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave"
+ "address setting\n");
+ return -EIO;
}
- } /* end for */
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
+ }
- pch_i2c_sendnack(adap);
+ } /* end for */
- buf[read_index] = ioread32(p + PCH_I2CDR);
+ pch_i2c_sendnack(adap);
- if (length != 1)
- read_index++;
+ buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
- if (pch_i2c_wait_for_xfer_complete(adap) == 0) {
- if (last)
- pch_i2c_stop(adap);
- else
- pch_i2c_repstart(adap);
+ if (length != 1)
+ read_index++;
- buf[read_index++] = ioread32(p + PCH_I2CDR);
- count = read_index;
- } else {
- count = -ETIME;
+ rtn = pch_i2c_wait_for_xfer_complete(adap);
+ if (rtn == 0) {
+ if (pch_i2c_getack(adap)) {
+ pch_dbg(adap, "Receive NACK for slave"
+ "address setting\n");
+ return -EIO;
}
-
+ } else { /* wait-event timeout */
+ pch_i2c_stop(adap);
+ return -ETIME;
}
- } else {
- count = -ETIME;
- pch_i2c_stop(adap);
+
+ if (last)
+ pch_i2c_stop(adap);
+ else
+ pch_i2c_repstart(adap);
+
+ buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
+ count = read_index;
}
return count;
@@ -673,32 +795,33 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
/* transfer not completed */
adap->pch_i2c_xfer_in_progress = true;
- pmsg = &msgs[0];
- pmsg->flags |= adap->pch_buff_mode_en;
- status = pmsg->flags;
- pch_dbg(adap,
- "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
- /* calculate sub address length and message length */
- /* these are applicable only for buffer mode */
- subaddrlen = pmsg->buf[0];
- /* calculate actual message length excluding
- * the sub address fields */
- msglen = (pmsg->len) - (subaddrlen + 1);
- if (status & (I2C_M_RD)) {
- pch_dbg(adap, "invoking pch_i2c_readbytes\n");
- ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
- (i == 0));
- } else {
- pch_dbg(adap, "invoking pch_i2c_writebytes\n");
- ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
- (i == 0));
+ for (i = 0; i < num && ret >= 0; i++) {
+ pmsg = &msgs[i];
+ pmsg->flags |= adap->pch_buff_mode_en;
+ status = pmsg->flags;
+ pch_dbg(adap,
+ "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
+ /* calculate sub address length and message length */
+ /* these are applicable only for buffer mode */
+ subaddrlen = pmsg->buf[0];
+ /* calculate actual message length excluding
+ * the sub address fields */
+ msglen = (pmsg->len) - (subaddrlen + 1);
+
+ if ((status & (I2C_M_RD)) != false) {
+ ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ } else {
+ ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
+ (i == 0));
+ }
}
adap->pch_i2c_xfer_in_progress = false; /* transfer completed */
mutex_unlock(&pch_mutex);
- return ret;
+ return (ret < 0) ? ret : num;
}
/**
@@ -770,6 +893,13 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
/* Set the number of I2C channel instance */
adap_info->ch_num = id->driver_data;
+ ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+ KBUILD_MODNAME, adap_info);
+ if (ret) {
+ pch_pci_err(pdev, "request_irq FAILED\n");
+ goto err_request_irq;
+ }
+
for (i = 0; i < adap_info->ch_num; i++) {
pch_adap = &adap_info->pch_data[i].pch_adapter;
adap_info->pch_i2c_suspended = false;
@@ -787,28 +917,23 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
pch_adap->dev.parent = &pdev->dev;
+ pch_i2c_init(&adap_info->pch_data[i]);
ret = i2c_add_adapter(pch_adap);
if (ret) {
pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
- goto err_i2c_add_adapter;
+ goto err_add_adapter;
}
-
- pch_i2c_init(&adap_info->pch_data[i]);
- }
- ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
- KBUILD_MODNAME, adap_info);
- if (ret) {
- pch_pci_err(pdev, "request_irq FAILED\n");
- goto err_i2c_add_adapter;
}
pci_set_drvdata(pdev, adap_info);
pch_pci_dbg(pdev, "returns %d.\n", ret);
return 0;
-err_i2c_add_adapter:
+err_add_adapter:
for (j = 0; j < i; j++)
i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
+ free_irq(pdev->irq, adap_info);
+err_request_irq:
pci_iounmap(pdev, base_addr);
err_pci_iomap:
pci_release_regions(pdev);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 53852cb..a651779 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -211,11 +211,7 @@ static int __init i2c_gpio_init(void)
return ret;
}
-#ifdef CONFIG_FAST_RESUME
-beforeresume_initcall(i2c_gpio_init);
-#else
subsys_initcall(i2c_gpio_init);
-#endif
static void __exit i2c_gpio_exit(void)
{
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
index 3df1bc8..63bb1cc 100644
--- a/drivers/i2c/busses/i2c-highlander.c
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -227,7 +227,7 @@ static int highlander_i2c_read(struct highlander_i2c_dev *dev)
/*
* The R0P7780LC0011RL FPGA needs a significant delay between
- * data read cycles, otherwise the transciever gets confused and
+ * data read cycles, otherwise the transceiver gets confused and
* garbage is returned when the read is subsequently aborted.
*
* It is not sufficient to wait for BBSY.
@@ -387,7 +387,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev)
dev->irq = 0;
if (dev->irq) {
- ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+ ret = request_irq(dev->irq, highlander_i2c_irq, 0,
pdev->name, dev);
if (unlikely(ret))
goto err_unmap;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ab26840d..817d025 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -51,6 +51,8 @@
Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
DH89xxCC (PCH) 0x2330 32 hard yes yes yes
Panther Point (PCH) 0x1e22 32 hard yes yes yes
+ Lynx Point (PCH) 0x8c22 32 hard yes yes yes
+ Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -145,6 +147,8 @@
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
struct i801_priv {
struct i2c_adapter adapter;
@@ -633,6 +637,8 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4c2a62b..58832e5 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -48,6 +48,9 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -125,6 +128,11 @@ struct imx_i2c_struct {
unsigned int ifdr; /* IMX_I2C_IFDR */
};
+static const struct of_device_id i2c_imx_dt_ids[] = {
+ { .compatible = "fsl,imx1-i2c", },
+ { /* sentinel */ }
+};
+
/** Functions for IMX I2C adapter driver ***************************************
*******************************************************************************/
@@ -466,10 +474,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx;
struct resource *res;
- struct imxi2c_platform_data *pdata;
+ struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
void __iomem *base;
resource_size_t res_size;
- int irq;
+ int irq, bitrate;
int ret;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
@@ -485,19 +493,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
return -ENOENT;
}
- pdata = pdev->dev.platform_data;
-
- if (pdata && pdata->init) {
- ret = pdata->init(&pdev->dev);
- if (ret)
- return ret;
- }
-
res_size = resource_size(res);
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
- ret = -EBUSY;
- goto fail0;
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ return -EBUSY;
}
base = ioremap(res->start, res_size);
@@ -520,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->irq = irq;
i2c_imx->base = base;
i2c_imx->res = res;
@@ -546,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
/* Set up clock divider */
- if (pdata && pdata->bitrate)
- i2c_imx_set_clk(i2c_imx, pdata->bitrate);
- else
- i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+ bitrate = IMX_I2C_BIT_RATE;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &bitrate);
+ if (ret < 0 && pdata && pdata->bitrate)
+ bitrate = pdata->bitrate;
+ i2c_imx_set_clk(i2c_imx, bitrate);
/* Set up chip registers to defaults */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
@@ -562,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
goto fail5;
}
+ of_i2c_register_devices(&i2c_imx->adapter);
+
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
@@ -586,16 +591,12 @@ fail2:
iounmap(base);
fail1:
release_mem_region(res->start, resource_size(res));
-fail0:
- if (pdata && pdata->exit)
- pdata->exit(&pdev->dev);
return ret; /* Return error number */
}
static int __exit i2c_imx_remove(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
- struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
/* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
@@ -611,10 +612,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
writeb(0, i2c_imx->base + IMX_I2C_I2SR);
- /* Shut down hardware */
- if (pdata && pdata->exit)
- pdata->exit(&pdev->dev);
-
clk_put(i2c_imx->clk);
iounmap(i2c_imx->base);
@@ -628,6 +625,7 @@ static struct platform_driver i2c_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = i2c_imx_dt_ids,
}
};
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index 5d8aed5..c01e951 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -35,7 +35,7 @@
#include <linux/slab.h>
#include <mach/hardware.h> /* Pick up IXP2000-specific bits */
-#include <mach/gpio.h>
+#include <mach/gpio-ixp2000.h>
static inline int ixp2000_scl_pin(void *data)
{
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 0c731ca..5267ab9 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -63,11 +63,11 @@
/* Master controller (MCR) register */
#define I2C_MCR_OP (0x1 << 0) /* Operation */
#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */
-#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
+#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */
#define I2C_MCR_SB (0x1 << 11) /* Extended address */
#define I2C_MCR_AM (0x3 << 12) /* Address type */
-#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
-#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
+#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */
+#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */
/* Status register (SR) */
#define I2C_SR_OP (0x3 << 0) /* Operation */
@@ -77,7 +77,7 @@
#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */
/* Interrupt mask set/clear (IMSCR) bits */
-#define I2C_IT_TXFE (0x1 << 0)
+#define I2C_IT_TXFE (0x1 << 0)
#define I2C_IT_TXFNE (0x1 << 1)
#define I2C_IT_TXFF (0x1 << 2)
#define I2C_IT_TXFOVR (0x1 << 3)
@@ -135,30 +135,31 @@ struct i2c_nmk_client {
};
/**
- * struct nmk_i2c_dev - private data structure of the controller
- * @pdev: parent platform device
- * @adap: corresponding I2C adapter
- * @irq: interrupt line for the controller
- * @virtbase: virtual io memory area
- * @clk: hardware i2c block clock
- * @cfg: machine provided controller configuration
- * @cli: holder of client specific data
- * @stop: stop condition
- * @xfer_complete: acknowledge completion for a I2C message
- * @result: controller propogated result
- * @busy: Busy doing transfer
+ * struct nmk_i2c_dev - private data structure of the controller.
+ * @pdev: parent platform device.
+ * @adap: corresponding I2C adapter.
+ * @irq: interrupt line for the controller.
+ * @virtbase: virtual io memory area.
+ * @clk: hardware i2c block clock.
+ * @cfg: machine provided controller configuration.
+ * @cli: holder of client specific data.
+ * @stop: stop condition.
+ * @xfer_complete: acknowledge completion for a I2C message.
+ * @result: controller propogated result.
+ * @regulator: pointer to i2c regulator.
+ * @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
struct platform_device *pdev;
- struct i2c_adapter adap;
- int irq;
+ struct i2c_adapter adap;
+ int irq;
void __iomem *virtbase;
struct clk *clk;
struct nmk_i2c_controller cfg;
struct i2c_nmk_client cli;
- int stop;
+ int stop;
struct completion xfer_complete;
- int result;
+ int result;
struct regulator *regulator;
bool busy;
};
@@ -216,8 +217,9 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
}
}
- dev_err(&dev->pdev->dev, "flushing operation timed out "
- "giving up after %d attempts", LOOP_ATTEMPTS);
+ dev_err(&dev->pdev->dev,
+ "flushing operation timed out giving up after %d attempts",
+ LOOP_ATTEMPTS);
return -ETIMEDOUT;
}
@@ -269,7 +271,7 @@ exit:
}
/* enable peripheral, master mode operation */
-#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
+#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE)
/**
* load_i2c_mcr_reg() - load the MCR register
@@ -362,8 +364,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
* and high speed (up to 3.4 Mb/s)
*/
if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
- dev_err(&dev->pdev->dev, "do not support this mode "
- "defaulting to std. mode\n");
+ dev_err(&dev->pdev->dev,
+ "do not support this mode defaulting to std. mode\n");
brcr2 = i2c_clk/(100000 * 2) & 0xffff;
writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
writel(I2C_FREQ_MODE_STANDARD << 4,
@@ -417,12 +419,12 @@ static int read_i2c(struct nmk_i2c_dev *dev)
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout "
"returned %d waiting for event\n", timeout);
status = timeout;
}
@@ -504,12 +506,12 @@ static int write_i2c(struct nmk_i2c_dev *dev)
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout "
"returned %d waiting for event\n", timeout);
status = timeout;
}
@@ -555,8 +557,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
if (((i2c_sr >> 2) & 0x3) == 0x3) {
/* get the abort cause */
cause = (i2c_sr >> 4) & 0x7;
- dev_err(&dev->pdev->dev, "%s\n", cause
- >= ARRAY_SIZE(abort_causes) ?
+ dev_err(&dev->pdev->dev, "%s\n",
+ cause >= ARRAY_SIZE(abort_causes) ?
"unknown reason" :
abort_causes[cause]);
}
@@ -581,13 +583,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
*
* NOTE:
* READ TRANSFER : We impose a restriction of the first message to be the
- * index message for any read transaction.
- * - a no index is coded as '0',
- * - 2byte big endian index is coded as '3'
- * !!! msg[0].buf holds the actual index.
- * This is compatible with generic messages of smbus emulator
- * that send a one byte index.
- * eg. a I2C transation to read 2 bytes from index 0
+ * index message for any read transaction.
+ * - a no index is coded as '0',
+ * - 2byte big endian index is coded as '3'
+ * !!! msg[0].buf holds the actual index.
+ * This is compatible with generic messages of smbus emulator
+ * that send a one byte index.
+ * eg. a I2C transation to read 2 bytes from index 0
* idx = 0;
* msg[0].addr = client->addr;
* msg[0].flags = 0x0;
@@ -643,8 +645,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
for (i = 0; i < num_msgs; i++) {
if (unlikely(msgs[i].flags & I2C_M_TEN)) {
- dev_err(&dev->pdev->dev, "10 bit addressing"
- "not supported\n");
+ dev_err(&dev->pdev->dev,
+ "10 bit addressing not supported\n");
status = -EINVAL;
goto out;
@@ -788,8 +790,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
if (dev->cli.count) {
dev->result = -EIO;
- dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
- "xfered\n", dev->cli.count);
+ dev_err(&dev->pdev->dev,
+ "%lu bytes still remain to be xfered\n",
+ dev->cli.count);
(void) init_hw(dev);
}
complete(&dev->xfer_complete);
@@ -922,7 +925,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
}
if (request_mem_region(res->start, resource_size(res),
- DRIVER_NAME "I/O region") == NULL) {
+ DRIVER_NAME "I/O region") == NULL) {
ret = -EBUSY;
goto err_no_region;
}
@@ -934,7 +937,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
}
dev->irq = platform_get_irq(pdev, 0);
- ret = request_irq(dev->irq, i2c_irq_handler, IRQF_DISABLED,
+ ret = request_irq(dev->irq, i2c_irq_handler, 0,
DRIVER_NAME, dev);
if (ret) {
dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
@@ -979,8 +982,9 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, dev);
- dev_info(&pdev->dev, "initialize %s on virtual "
- "base %p\n", adap->name, dev->virtbase);
+ dev_info(&pdev->dev,
+ "initialize %s on virtual base %p\n",
+ adap->name, dev->virtbase);
ret = i2c_add_numbered_adapter(adap);
if (ret) {
diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c
index 7243426..03b6157 100644
--- a/drivers/i2c/busses/i2c-nuc900.c
+++ b/drivers/i2c/busses/i2c-nuc900.c
@@ -593,7 +593,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
- mfp_set_groupg(&pdev->dev);
+ mfp_set_groupg(&pdev->dev, NULL);
clk_get_rate(i2c->clk);
@@ -610,7 +610,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
goto err_iomap;
}
- ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED,
dev_name(&pdev->dev), i2c);
if (ret != 0) {
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 137e1a3..257c1a5 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -42,12 +42,12 @@
#include <linux/pm_runtime.h>
/* I2C controller revisions */
-#define OMAP_I2C_REV_2 0x20
+#define OMAP_I2C_OMAP1_REV_2 0x20
/* I2C controller revisions present on specific hardware */
#define OMAP_I2C_REV_ON_2430 0x36
#define OMAP_I2C_REV_ON_3430 0x3C
-#define OMAP_I2C_REV_ON_4430 0x40
+#define OMAP_I2C_REV_ON_3530_4430 0x40
/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -72,11 +72,12 @@ enum {
OMAP_I2C_SCLH_REG,
OMAP_I2C_SYSTEST_REG,
OMAP_I2C_BUFSTAT_REG,
- OMAP_I2C_REVNB_LO,
- OMAP_I2C_REVNB_HI,
- OMAP_I2C_IRQSTATUS_RAW,
- OMAP_I2C_IRQENABLE_SET,
- OMAP_I2C_IRQENABLE_CLR,
+ /* only on OMAP4430 */
+ OMAP_I2C_IP_V2_REVNB_LO,
+ OMAP_I2C_IP_V2_REVNB_HI,
+ OMAP_I2C_IP_V2_IRQSTATUS_RAW,
+ OMAP_I2C_IP_V2_IRQENABLE_SET,
+ OMAP_I2C_IP_V2_IRQENABLE_CLR,
};
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
@@ -193,7 +194,6 @@ struct omap_i2c_dev {
*/
u8 rev;
unsigned b_hw:1; /* bad h/w fixes */
- unsigned idle:1;
u16 iestate; /* Saved interrupt register */
u16 pscstate;
u16 scllstate;
@@ -204,7 +204,7 @@ struct omap_i2c_dev {
u16 errata;
};
-const static u8 reg_map[] = {
+static const u8 reg_map_ip_v1[] = {
[OMAP_I2C_REV_REG] = 0x00,
[OMAP_I2C_IE_REG] = 0x01,
[OMAP_I2C_STAT_REG] = 0x02,
@@ -225,7 +225,7 @@ const static u8 reg_map[] = {
[OMAP_I2C_BUFSTAT_REG] = 0x10,
};
-const static u8 omap4_reg_map[] = {
+static const u8 reg_map_ip_v2[] = {
[OMAP_I2C_REV_REG] = 0x04,
[OMAP_I2C_IE_REG] = 0x2c,
[OMAP_I2C_STAT_REG] = 0x28,
@@ -244,11 +244,11 @@ const static u8 omap4_reg_map[] = {
[OMAP_I2C_SCLH_REG] = 0xb8,
[OMAP_I2C_SYSTEST_REG] = 0xbC,
[OMAP_I2C_BUFSTAT_REG] = 0xc0,
- [OMAP_I2C_REVNB_LO] = 0x00,
- [OMAP_I2C_REVNB_HI] = 0x04,
- [OMAP_I2C_IRQSTATUS_RAW] = 0x24,
- [OMAP_I2C_IRQENABLE_SET] = 0x2c,
- [OMAP_I2C_IRQENABLE_CLR] = 0x30,
+ [OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
+ [OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
+ [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
+ [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
+ [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
};
static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
@@ -266,17 +266,11 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
{
- struct platform_device *pdev;
struct omap_i2c_bus_platform_data *pdata;
- WARN_ON(!dev->idle);
+ pdata = dev->dev->platform_data;
- pdev = to_platform_device(dev->dev);
- pdata = pdev->dev.platform_data;
-
- pm_runtime_get_sync(&pdev->dev);
-
- if (cpu_is_omap34xx()) {
+ if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
@@ -286,7 +280,6 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
}
- dev->idle = 0;
/*
* Don't write to this register if the IE state is 0 as it can
@@ -298,32 +291,25 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
static void omap_i2c_idle(struct omap_i2c_dev *dev)
{
- struct platform_device *pdev;
struct omap_i2c_bus_platform_data *pdata;
u16 iv;
- WARN_ON(dev->idle);
-
- pdev = to_platform_device(dev->dev);
- pdata = pdev->dev.platform_data;
+ pdata = dev->dev->platform_data;
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
- if (dev->rev >= OMAP_I2C_REV_ON_4430)
- omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1);
+ if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+ omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
else
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
- if (dev->rev < OMAP_I2C_REV_2) {
+ if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
} else {
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
- /* Flush posted write before the dev->idle store occurs */
+ /* Flush posted write */
omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
}
- dev->idle = 1;
-
- pm_runtime_put_sync(&pdev->dev);
}
static int omap_i2c_init(struct omap_i2c_dev *dev)
@@ -334,8 +320,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
unsigned long timeout;
unsigned long internal_clk = 0;
struct clk *fclk;
+ struct omap_i2c_bus_platform_data *pdata;
- if (dev->rev >= OMAP_I2C_REV_2) {
+ pdata = dev->dev->platform_data;
+
+ if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
/* Disable I2C controller before soft reset */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
@@ -378,12 +367,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* REVISIT: Some wkup sources might not be needed.
*/
dev->westate = OMAP_I2C_WE_ALL;
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
+ dev->westate);
}
}
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
- if (cpu_class_is_omap1()) {
+ if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
/*
* The I2C functional clock is the armxor_ck, so there's
* no need to get "armxor_ck" separately. Now, if OMAP2420
@@ -407,7 +397,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
psc = fclk_rate / 12000000;
}
- if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
+ if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
/*
* HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -415,7 +405,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* to get longer filter period for better noise suppression.
* The filter is iclk (fclk for HS) period.
*/
- if (dev->speed > 400 || cpu_is_omap2430())
+ if (dev->speed > 400 ||
+ pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
internal_clk = 19200;
else if (dev->speed > 100)
internal_clk = 9600;
@@ -484,7 +475,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
dev->errata = 0;
- if (cpu_is_omap2430() || cpu_is_omap34xx())
+ if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
dev->errata |= I2C_OMAP_ERRATA_I207;
/* Enable interrupts */
@@ -493,7 +484,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
- if (cpu_is_omap34xx()) {
+ if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
dev->pscstate = psc;
dev->scllstate = scll;
dev->sclhstate = sclh;
@@ -642,7 +633,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
int i;
int r;
- omap_i2c_unidle(dev);
+ pm_runtime_get_sync(dev->dev);
r = omap_i2c_wait_for_bb(dev);
if (r < 0)
@@ -665,7 +656,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
omap_i2c_wait_for_bb(dev);
out:
- omap_i2c_idle(dev);
+ pm_runtime_put(dev->dev);
return r;
}
@@ -720,12 +711,12 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
#ifdef CONFIG_ARCH_OMAP15XX
static irqreturn_t
-omap_i2c_rev1_isr(int this_irq, void *dev_id)
+omap_i2c_omap1_isr(int this_irq, void *dev_id)
{
struct omap_i2c_dev *dev = dev_id;
u16 iv, w;
- if (dev->idle)
+ if (pm_runtime_suspended(dev->dev))
return IRQ_NONE;
iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
@@ -774,7 +765,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
return IRQ_HANDLED;
}
#else
-#define omap_i2c_rev1_isr NULL
+#define omap_i2c_omap1_isr NULL
#endif
/*
@@ -813,8 +804,11 @@ omap_i2c_isr(int this_irq, void *dev_id)
u16 bits;
u16 stat, w;
int err, count = 0;
+ struct omap_i2c_bus_platform_data *pdata;
- if (dev->idle)
+ pdata = dev->dev->platform_data;
+
+ if (pm_runtime_suspended(dev->dev))
return IRQ_NONE;
bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
@@ -881,8 +875,8 @@ complete:
* Data reg in 2430, omap3 and
* omap4 is 8 bit wide
*/
- if (cpu_class_is_omap1() ||
- cpu_is_omap2420()) {
+ if (pdata->flags &
+ OMAP_I2C_FLAG_16BIT_DATA_REG) {
if (dev->buf_len) {
*dev->buf++ = w >> 8;
dev->buf_len--;
@@ -924,8 +918,8 @@ complete:
* Data reg in 2430, omap3 and
* omap4 is 8 bit wide
*/
- if (cpu_class_is_omap1() ||
- cpu_is_omap2420()) {
+ if (pdata->flags &
+ OMAP_I2C_FLAG_16BIT_DATA_REG) {
if (dev->buf_len) {
w |= *dev->buf++ << 8;
dev->buf_len--;
@@ -1016,7 +1010,6 @@ omap_i2c_probe(struct platform_device *pdev)
}
dev->speed = speed;
- dev->idle = 1;
dev->dev = &pdev->dev;
dev->irq = irq->start;
dev->base = ioremap(mem->start, resource_size(mem));
@@ -1027,27 +1020,22 @@ omap_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
- if (cpu_is_omap7xx())
- dev->reg_shift = 1;
- else if (cpu_is_omap44xx())
- dev->reg_shift = 0;
- else
- dev->reg_shift = 2;
+ dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
- if (cpu_is_omap44xx())
- dev->regs = (u8 *) omap4_reg_map;
+ if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+ dev->regs = (u8 *)reg_map_ip_v2;
else
- dev->regs = (u8 *) reg_map;
+ dev->regs = (u8 *)reg_map_ip_v1;
- pm_runtime_enable(&pdev->dev);
- omap_i2c_unidle(dev);
+ pm_runtime_enable(dev->dev);
+ pm_runtime_get_sync(dev->dev);
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
if (dev->rev <= OMAP_I2C_REV_ON_3430)
dev->errata |= I2C_OMAP3_1P153;
- if (!(cpu_class_is_omap1() || cpu_is_omap2420())) {
+ if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) {
u16 s;
/* Set up the fifo size - Get total size */
@@ -1059,13 +1047,14 @@ omap_i2c_probe(struct platform_device *pdev)
* size. This is to ensure that we can handle the status on int
* call back latencies.
*/
- if (dev->rev >= OMAP_I2C_REV_ON_4430) {
- dev->fifo_size = 0;
+
+ dev->fifo_size = (dev->fifo_size / 2);
+
+ if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
dev->b_hw = 0; /* Disable hardware fixes */
- } else {
- dev->fifo_size = (dev->fifo_size / 2);
+ else
dev->b_hw = 1; /* Enable hardware fixes */
- }
+
/* calculate wakeup latency constraint for MPU */
if (dev->set_mpu_wkup_lat != NULL)
dev->latency = (1000000 * dev->fifo_size) /
@@ -1075,7 +1064,8 @@ omap_i2c_probe(struct platform_device *pdev)
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
- isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
+ isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
+ omap_i2c_isr;
r = request_irq(dev->irq, isr, 0, pdev->name, dev);
if (r) {
@@ -1083,10 +1073,10 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_unuse_clocks;
}
- dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
- pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+ dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
+ pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
- omap_i2c_idle(dev);
+ pm_runtime_put(dev->dev);
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
@@ -1110,7 +1100,7 @@ err_free_irq:
free_irq(dev->irq, dev);
err_unuse_clocks:
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
- omap_i2c_idle(dev);
+ pm_runtime_put(dev->dev);
iounmap(dev->base);
err_free_mem:
platform_set_drvdata(pdev, NULL);
@@ -1139,28 +1129,30 @@ omap_i2c_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_SUSPEND
-static int omap_i2c_suspend(struct device *dev)
+#ifdef CONFIG_PM_RUNTIME
+static int omap_i2c_runtime_suspend(struct device *dev)
{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
- dev->bus->pm->runtime_suspend(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+
+ omap_i2c_idle(_dev);
return 0;
}
-static int omap_i2c_resume(struct device *dev)
+static int omap_i2c_runtime_resume(struct device *dev)
{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
- dev->bus->pm->runtime_resume(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+
+ omap_i2c_unidle(_dev);
return 0;
}
static struct dev_pm_ops omap_i2c_pm_ops = {
- .suspend = omap_i2c_suspend,
- .resume = omap_i2c_resume,
+ .runtime_suspend = omap_i2c_runtime_suspend,
+ .runtime_resume = omap_i2c_runtime_resume,
};
#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
#else
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 6d14ac2..c60f8e1 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -22,7 +22,7 @@
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
- AMD Hudson-2
+ AMD Hudson-2, ML, CZ
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -231,7 +231,8 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id)
{
unsigned short smba_idx = 0xcd6;
- u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
+ u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status;
+ u8 i2ccfg, i2ccfg_offset = 0x10;
/* SB800 and later SMBus does not support forcing address */
if (force || force_addr) {
@@ -241,6 +242,16 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
}
/* Determine the address of the SMBus areas */
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+ PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+ PIIX4_dev->revision >= 0x41) ||
+ (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+ PIIX4_dev->device == 0x790b &&
+ PIIX4_dev->revision >= 0x49))
+ smb_en = 0x00;
+ else
+ smb_en = 0x2c;
+
if (!request_region(smba_idx, 2, "smba_idx")) {
dev_err(&PIIX4_dev->dev, "SMBus base address index region "
"0x%x already in use!\n", smba_idx);
@@ -252,13 +263,20 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
smba_en_hi = inb_p(smba_idx + 1);
release_region(smba_idx, 2);
- if ((smba_en_lo & 1) == 0) {
+ if (!smb_en) {
+ smb_en_status = smba_en_lo & 0x10;
+ piix4_smba = smba_en_hi << 8;
+ } else {
+ smb_en_status = smba_en_lo & 0x01;
+ piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+ }
+
+ if (!smb_en_status) {
dev_err(&PIIX4_dev->dev,
"Host SMBus controller not enabled!\n");
return -ENODEV;
}
- piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
return -ENODEV;
@@ -481,6 +499,7 @@ static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index dfa7ae9..127051b 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -306,7 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
if (pmcmsptwi_data.irq) {
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
- IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
pldev->name, &pmcmsptwi_data);
if (rc == 0) {
/*
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 6659d26..632e088 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -3,6 +3,7 @@
* It does not support slave mode, the register slightly moved. This PCI
* device provides three bars, every contains a single I2C controller.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/i2c/pxa-i2c.h>
@@ -109,12 +110,15 @@ static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
return -EINVAL;
}
sds = kzalloc(sizeof(*sds), GFP_KERNEL);
- if (!sds)
+ if (!sds) {
+ ret = -ENOMEM;
goto err_mem;
+ }
for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
sds->pdev[i] = add_i2c_device(dev, i);
if (IS_ERR(sds->pdev[i])) {
+ ret = PTR_ERR(sds->pdev[i]);
while (--i >= 0)
platform_device_unregister(sds->pdev[i]);
goto err_dev_add;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index f59224a..d603646 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1079,7 +1079,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
* The reason to do so is to avoid sysfs names that only make
* sense when there are multiple adapters.
*/
- i2c->adap.nr = dev->id != -1 ? dev->id : 0;
+ i2c->adap.nr = dev->id;
snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u",
i2c->adap.nr);
@@ -1142,10 +1142,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.dev.of_node = dev->dev.of_node;
#endif
- if (i2c_type == REGS_CE4100)
- ret = i2c_add_adapter(&i2c->adap);
- else
- ret = i2c_add_numbered_adapter(&i2c->adap);
+ ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
goto eadapt;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 6344f91..7d6d2b7 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -35,6 +35,8 @@
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
#include <asm/irq.h>
@@ -54,7 +56,6 @@ enum s3c24xx_i2c_state {
enum s3c24xx_i2c_type {
TYPE_S3C2410,
TYPE_S3C2440,
- TYPE_S3C2440_HDMIPHY,
};
struct s3c24xx_i2c {
@@ -79,6 +80,8 @@ struct s3c24xx_i2c {
struct resource *ioarea;
struct i2c_adapter adap;
+ struct s3c2410_platform_i2c *pdata;
+ int gpios[2];
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
@@ -86,17 +89,6 @@ struct s3c24xx_i2c {
/* default platform data removed, dev should always carry data. */
-static inline void dump_i2c_register(struct s3c24xx_i2c *i2c)
-{
- dev_dbg(i2c->dev, "Register dump(%d) : %x %x %x %x %x\n"
- , i2c->suspended
- , readl(i2c->regs + S3C2410_IICCON)
- , readl(i2c->regs + S3C2410_IICSTAT)
- , readl(i2c->regs + S3C2410_IICADD)
- , readl(i2c->regs + S3C2410_IICDS)
- , readl(i2c->regs + S3C2440_IICLC) );
-}
-
/* s3c24xx_i2c_is2440()
*
* return true is this is an s3c2440
@@ -107,21 +99,14 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
struct platform_device *pdev = to_platform_device(i2c->dev);
enum s3c24xx_i2c_type type;
- type = platform_get_device_id(pdev)->driver_data;
- return type == TYPE_S3C2440 || type == TYPE_S3C2440_HDMIPHY;
-}
-
-/* s3c24xx_i2c_is2440_hdmiphy()
- *
- * return true is this is an s3c2440 dedicated for HDMIPHY interface
-*/
-static inline int s3c24xx_i2c_is2440_hdmiphy(struct s3c24xx_i2c *i2c)
-{
- struct platform_device *pdev = to_platform_device(i2c->dev);
- enum s3c24xx_i2c_type type;
+#ifdef CONFIG_OF
+ if (i2c->dev->of_node)
+ return of_device_is_compatible(i2c->dev->of_node,
+ "samsung,s3c2440-i2c");
+#endif
type = platform_get_device_id(pdev)->driver_data;
- return type == TYPE_S3C2440_HDMIPHY;
+ return type == TYPE_S3C2440;
}
/* s3c24xx_i2c_master_complete
@@ -226,29 +211,18 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
{
- unsigned long iicstat;
- unsigned long iiccon;
+ unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
dev_dbg(i2c->dev, "STOP\n");
/* stop the transfer */
-
- /* Disable irq */
- s3c24xx_i2c_disable_irq(i2c);
-
- /* STOP signal generation : MTx(0xD0) */
- iicstat = readl(i2c->regs + S3C2410_IICSTAT);
iicstat &= ~S3C2410_IICSTAT_START;
writel(iicstat, i2c->regs + S3C2410_IICSTAT);
- /* Clear pending bit */
- iiccon = readl(i2c->regs + S3C2410_IICCON);
- iiccon &= ~S3C2410_IICCON_IRQPEND;
- writel(iiccon, i2c->regs + S3C2410_IICCON);
+ i2c->state = STATE_STOP;
s3c24xx_i2c_master_complete(i2c, ret);
-
- i2c->state = STATE_STOP;
+ s3c24xx_i2c_disable_irq(i2c);
}
/* helper functions to determine the current state in the set of
@@ -384,21 +358,12 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* forces us to send a new START
* when we change direction */
- dev_dbg(i2c->dev, "Cannot do this\n");
s3c24xx_i2c_stop(i2c, -EINVAL);
}
- /* For multiple messages,
- * ex)
- * Msg[0]: Slave Addr + Write(Addr)
- * Msg[1]: Write(Data) */
goto retry_write;
} else {
/* send the new start */
- /* For multiple messages,
- * ex)
- * Msg[0]: Slave Addr + Write(Addr)
- * Msg[1]: Slave Addr + Read/Write(Data) */
s3c24xx_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
}
@@ -469,8 +434,6 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
unsigned long status;
unsigned long tmp;
- spin_lock(&i2c->lock);
-
status = readl(i2c->regs + S3C2410_IICSTAT);
if (status & S3C2410_IICSTAT_ARBITR) {
@@ -493,8 +456,6 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
i2c_s3c_irq_nextbyte(i2c, status);
out:
- spin_unlock(&i2c->lock);
-
return IRQ_HANDLED;
}
@@ -539,7 +500,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
ret = s3c24xx_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
- dump_i2c_register(i2c);
ret = -EAGAIN;
goto out;
}
@@ -564,15 +524,9 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
* noisy when doing an i2cdetect */
if (timeout == 0)
- {
dev_dbg(i2c->dev, "timeout\n");
- dump_i2c_register(i2c);
- }
else if (ret != num)
- {
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
- dump_i2c_register(i2c);
- }
/* ensure the stop has been through the bus */
@@ -580,33 +534,18 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
/* first, try busy waiting briefly */
do {
+ cpu_relax();
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
} while ((iicstat & S3C2410_IICSTAT_START) && --spins);
/* if that timed out sleep */
if (!spins) {
- usleep_range(1000, 1000);
+ msleep(1);
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
}
- /* if still not finished, clean it up */
- spin_lock_irq(&i2c->lock);
-
- if (iicstat & S3C2410_IICSTAT_BUSBUSY) {
- dev_dbg(i2c->dev, "timeout waiting for bus idle\n");
- dump_i2c_register(i2c);
-
- if (i2c->state != STATE_STOP) {
- dev_dbg(i2c->dev, "timeout : i2c interrupt hasn't occurred\n");
- s3c24xx_i2c_stop(i2c, 0);
- }
-
- /* Disable Serial Out : To forcely terminate the connection */
- iicstat = readl(i2c->regs + S3C2410_IICSTAT);
- iicstat &= ~S3C2410_IICSTAT_TXRXEN;
- writel(iicstat, i2c->regs + S3C2410_IICSTAT);
- }
- spin_unlock_irq(&i2c->lock);
+ if (iicstat & S3C2410_IICSTAT_START)
+ dev_warn(i2c->dev, "timeout waiting for bus idle\n");
out:
return ret;
@@ -625,13 +564,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int retry;
int ret;
- if (i2c->suspended)
- {
- dev_err(i2c->dev, "I2C is not initialzed.\n");
- dump_i2c_register(i2c);
- return -EIO;
- }
-
clk_enable(i2c->clk);
for (retry = 0; retry < adap->retries; retry++) {
@@ -704,7 +636,7 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
{
- struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
+ struct s3c2410_platform_i2c *pdata = i2c->pdata;
unsigned long clkin = clk_get_rate(i2c->clk);
unsigned int divs, div1;
unsigned long target_frequency;
@@ -789,7 +721,7 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
if (ret < 0)
dev_err(i2c->dev, "cannot find frequency\n");
else
- dev_dbg(i2c->dev, "setting freq %d\n", got);
+ dev_info(i2c->dev, "setting freq %d\n", got);
}
return 0;
@@ -820,6 +752,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
}
#endif
+#ifdef CONFIG_OF
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+ int idx, gpio, ret;
+
+ for (idx = 0; idx < 2; idx++) {
+ gpio = of_get_gpio(i2c->dev->of_node, idx);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
+ goto free_gpio;
+ }
+
+ ret = gpio_request(gpio, "i2c-bus");
+ if (ret) {
+ dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
+ goto free_gpio;
+ }
+ }
+ return 0;
+
+free_gpio:
+ while (--idx >= 0)
+ gpio_free(i2c->gpios[idx]);
+ return -EINVAL;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+ unsigned int idx;
+ for (idx = 0; idx < 2; idx++)
+ gpio_free(i2c->gpios[idx]);
+}
+#else
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+ return 0;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
/* s3c24xx_i2c_init
*
* initialise the controller, set the IO lines and frequency
@@ -833,18 +808,21 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* get the plafrom data */
- pdata = i2c->dev->platform_data;
+ pdata = i2c->pdata;
/* inititalise the gpio */
if (pdata->cfg_gpio)
pdata->cfg_gpio(to_platform_device(i2c->dev));
+ else
+ if (s3c24xx_i2c_parse_dt_gpio(i2c))
+ return -EINVAL;
/* write slave address */
writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
- dev_dbg(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+ dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
writel(iicon, i2c->regs + S3C2410_IICCON);
@@ -858,12 +836,40 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* todo - check that the i2c lines aren't being dragged anywhere */
- dev_dbg(i2c->dev, "bus frequency set to %d KHz\n", freq);
+ dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
return 0;
}
+#ifdef CONFIG_OF
+/* s3c24xx_i2c_parse_dt
+ *
+ * Parse the device tree node and retreive the platform data.
+*/
+
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
+{
+ struct s3c2410_platform_i2c *pdata = i2c->pdata;
+
+ if (!np)
+ return;
+
+ pdata->bus_num = -1; /* i2c bus number is dynamically assigned */
+ of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay);
+ of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
+ of_property_read_u32(np, "samsung,i2c-max-bus-freq",
+ (u32 *)&pdata->frequency);
+}
+#else
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
+{
+ return;
+}
+#endif
+
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
@@ -872,14 +878,16 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c;
- struct s3c2410_platform_i2c *pdata;
+ struct s3c2410_platform_i2c *pdata = NULL;
struct resource *res;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data\n");
- return -EINVAL;
+ if (!pdev->dev.of_node) {
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
}
i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
@@ -888,6 +896,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!i2c->pdata) {
+ ret = -ENOMEM;
+ goto err_noclk;
+ }
+
+ if (pdata)
+ memcpy(i2c->pdata, pdata, sizeof(*pdata));
+ else
+ s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
+
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm;
@@ -962,7 +981,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_iomap;
}
- ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
+ ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
if (ret != 0) {
@@ -982,7 +1001,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
* being bus 0.
*/
- i2c->adap.nr = pdata->bus_num;
+ i2c->adap.nr = i2c->pdata->bus_num;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
@@ -990,6 +1010,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_cpufreq;
}
+ of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
@@ -1038,6 +1059,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
iounmap(i2c->regs);
release_resource(i2c->ioarea);
+ s3c24xx_i2c_dt_gpio_free(i2c);
kfree(i2c->ioarea);
kfree(i2c);
@@ -1055,7 +1077,7 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
return 0;
}
-static int s3c24xx_i2c_resume_noirq(struct device *dev)
+static int s3c24xx_i2c_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
@@ -1070,12 +1092,7 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
- .resume_noirq = s3c24xx_i2c_resume_noirq,
-#ifdef CONFIG_HIBERNATION
- .freeze_noirq = s3c24xx_i2c_suspend_noirq,
- .thaw_noirq = s3c24xx_i2c_resume_noirq,
- .restore_noirq = s3c24xx_i2c_resume_noirq,
-#endif
+ .resume = s3c24xx_i2c_resume,
};
#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
@@ -1092,13 +1109,21 @@ static struct platform_device_id s3c24xx_driver_ids[] = {
}, {
.name = "s3c2440-i2c",
.driver_data = TYPE_S3C2440,
- }, {
- .name = "s3c2440-hdmiphy-i2c",
- .driver_data = TYPE_S3C2440_HDMIPHY,
}, { },
};
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+#ifdef CONFIG_OF
+static const struct of_device_id s3c24xx_i2c_match[] = {
+ { .compatible = "samsung,s3c2410-i2c" },
+ { .compatible = "samsung,s3c2440-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
+#else
+#define s3c24xx_i2c_match NULL
+#endif
+
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
@@ -1107,6 +1132,7 @@ static struct platform_driver s3c24xx_i2c_driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
+ .of_match_table = s3c24xx_i2c_match,
},
};
@@ -1114,11 +1140,7 @@ static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
}
-#ifdef CONFIG_FAST_RESUME
-beforeresume_initcall(i2c_adap_s3c_init);
-#else
subsys_initcall(i2c_adap_s3c_init);
-#endif
static void __exit i2c_adap_s3c_exit(void)
{
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
index cb5d01e..c64ba73 100644
--- a/drivers/i2c/busses/i2c-s6000.c
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -341,10 +341,7 @@ static int __devinit s6i2c_probe(struct platform_device *dev)
i2c_wr16(iface, S6_I2C_TXTL, 0);
platform_set_drvdata(dev, iface);
- if (bus_num < 0)
- rc = i2c_add_adapter(p_adap);
- else
- rc = i2c_add_numbered_adapter(p_adap);
+ rc = i2c_add_numbered_adapter(p_adap);
if (rc)
goto err_irq_free;
return 0;
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
index 3cad8fe..a67132b 100644
--- a/drivers/i2c/busses/i2c-sh7760.c
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/clock.h>
#include <asm/i2c-sh7760.h>
@@ -502,7 +503,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
}
OUT32(id, I2CCCR, ret);
- if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED,
+ if (request_irq(id->irq, sh7760_i2c_irq, 0,
SH7760_I2C_DEVNAME, id)) {
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
ret = -EBUSY;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index f633a53..675c969 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -543,7 +543,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
for (n = res->start; hook && n <= res->end; n++) {
- if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
+ if (request_irq(n, sh_mobile_i2c_isr, 0,
dev_name(&dev->dev), dev)) {
for (n--; n >= res->start; n--)
free_irq(n, dev);
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index 9987961..4d44af1 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -916,7 +916,7 @@ stu300_probe(struct platform_device *pdev)
}
dev->irq = platform_get_irq(pdev, 0);
- if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED,
+ if (request_irq(dev->irq, stu300_irh, 0,
NAME, dev)) {
ret = -EIO;
goto err_no_irq;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index fb3b4f8..3056ea4 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -26,6 +26,8 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/i2c-tegra.h>
+#include <linux/of_i2c.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
@@ -269,14 +271,30 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
/* Rounds down to not include partial word at the end of buf */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
- if (words_to_transfer > tx_fifo_avail)
- words_to_transfer = tx_fifo_avail;
- i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
-
- buf += words_to_transfer * BYTES_PER_FIFO_WORD;
- buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
- tx_fifo_avail -= words_to_transfer;
+ /* It's very common to have < 4 bytes, so optimize that case. */
+ if (words_to_transfer) {
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
+
+ /*
+ * Update state before writing to FIFO. If this casues us
+ * to finish writing all bytes (AKA buf_remaining goes to 0) we
+ * have a potential for an interrupt (PACKET_XFER_COMPLETE is
+ * not maskable). We need to make sure that the isr sees
+ * buf_remaining as 0 and doesn't call us back re-entrantly.
+ */
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf +
+ words_to_transfer * BYTES_PER_FIFO_WORD;
+ barrier();
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ }
/*
* If there is a partial word at the end of buf, handle it manually to
@@ -286,14 +304,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ i2c_dev->msg_buf_remaining = 0;
+ i2c_dev->msg_buf = NULL;
+ barrier();
+
i2c_writel(i2c_dev, val, I2C_TX_FIFO);
- buf_remaining = 0;
- tx_fifo_avail--;
}
- BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0);
- i2c_dev->msg_buf_remaining = buf_remaining;
- i2c_dev->msg_buf = buf;
return 0;
}
@@ -322,7 +341,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
u32 val;
int err = 0;
- clk_enable(i2c_dev->clk);
+ err = clk_enable(i2c_dev->clk);
+ if (err < 0) {
+ dev_err(i2c_dev->dev, "Clock enable failed %d\n", err);
+ return err;
+ }
tegra_periph_reset_assert(i2c_dev->clk);
udelay(2);
@@ -382,8 +405,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
disable_irq_nosync(i2c_dev->irq);
i2c_dev->irq_disabled = 1;
}
-
- complete(&i2c_dev->msg_complete);
goto err;
}
@@ -392,7 +413,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
i2c_dev->msg_err |= I2C_ERR_NO_ACK;
if (status & I2C_INT_ARBITRATION_LOST)
i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
- complete(&i2c_dev->msg_complete);
goto err;
}
@@ -410,13 +430,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
}
- if ((status & I2C_INT_PACKET_XFER_COMPLETE) &&
- !i2c_dev->msg_buf_remaining)
- complete(&i2c_dev->msg_complete);
-
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
if (i2c_dev->is_dvc)
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+ if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+ BUG_ON(i2c_dev->msg_buf_remaining);
+ complete(&i2c_dev->msg_complete);
+ }
return IRQ_HANDLED;
err:
/* An error occurred, mask all interrupts */
@@ -426,6 +447,8 @@ err:
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
if (i2c_dev->is_dvc)
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+ complete(&i2c_dev->msg_complete);
return IRQ_HANDLED;
}
@@ -517,7 +540,12 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
if (i2c_dev->is_suspended)
return -EBUSY;
- clk_enable(i2c_dev->clk);
+ ret = clk_enable(i2c_dev->clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret);
+ return ret;
+ }
+
for (i = 0; i < num; i++) {
int stop = (i == (num - 1)) ? 1 : 0;
ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
@@ -530,7 +558,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
static u32 tegra_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm tegra_i2c_algo = {
@@ -546,7 +574,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
struct resource *iomem;
struct clk *clk;
struct clk *i2c_clk;
- void *base;
+ const unsigned int *prop;
+ void __iomem *base;
int irq;
int ret = 0;
@@ -603,7 +632,17 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->irq = irq;
i2c_dev->cont_id = pdev->id;
i2c_dev->dev = &pdev->dev;
- i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000;
+
+ i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+ if (pdata) {
+ i2c_dev->bus_clk_rate = pdata->bus_clk_rate;
+
+ } else if (i2c_dev->dev->of_node) { /* if there is a device tree node ... */
+ prop = of_get_property(i2c_dev->dev->of_node,
+ "clock-frequency", NULL);
+ if (prop)
+ i2c_dev->bus_clk_rate = be32_to_cpup(prop);
+ }
if (pdev->id == 3)
i2c_dev->is_dvc = 1;
@@ -633,6 +672,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->adapter.algo = &tegra_i2c_algo;
i2c_dev->adapter.dev.parent = &pdev->dev;
i2c_dev->adapter.nr = pdev->id;
+ i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
if (ret) {
@@ -640,6 +680,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto err_free_irq;
}
+ of_i2c_register_devices(&i2c_dev->adapter);
+
return 0;
err_free_irq:
free_irq(i2c_dev->irq, i2c_dev);
@@ -704,6 +746,17 @@ static int tegra_i2c_resume(struct platform_device *pdev)
}
#endif
+#if defined(CONFIG_OF)
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#else
+#define tegra_i2c_of_match NULL
+#endif
+
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove = tegra_i2c_remove,
@@ -714,6 +767,7 @@ static struct platform_driver tegra_i2c_driver = {
.driver = {
.name = "tegra-i2c",
.owner = THIS_MODULE,
+ .of_match_table = tegra_i2c_of_match,
},
};
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 986e5f6..91e349c 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -550,7 +550,7 @@ static int __devexit scx200_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver scx200_pci_drv = {
+static struct platform_driver scx200_pci_driver = {
.driver = {
.name = "cs5535-smb",
.owner = THIS_MODULE,
@@ -593,14 +593,14 @@ static int __init scx200_acb_init(void)
return 0;
/* No ISA devices; register the platform driver for PCI-based devices */
- return platform_driver_register(&scx200_pci_drv);
+ return platform_driver_register(&scx200_pci_driver);
}
static void __exit scx200_acb_cleanup(void)
{
struct scx200_acb_iface *iface;
- platform_driver_unregister(&scx200_pci_drv);
+ platform_driver_unregister(&scx200_pci_driver);
mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) {
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 3ca2e01..10274ff 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include <linux/rwsem.h>
#include "i2c-core.h"
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 9a58994..1e56061 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -539,8 +539,10 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
+ /* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
- client->addr);
+ client->addr | ((client->flags & I2C_CLIENT_TEN)
+ ? 0xa000 : 0));
status = device_register(&client->dev);
if (status)
goto out_err;
@@ -925,6 +927,9 @@ EXPORT_SYMBOL(i2c_add_adapter);
* or otherwise built in to the system's mainboard, and where i2c_board_info
* is used to properly configure I2C devices.
*
+ * If the requested bus number is set to -1, then this function will behave
+ * identically to i2c_add_adapter, and will dynamically assign a bus number.
+ *
* If no devices have pre-been declared for this bus, then be sure to
* register the adapter before any dynamically allocated ones. Otherwise
* the required bus ID may not be available.
@@ -940,6 +945,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap)
int id;
int status;
+ if (adap->nr == -1) /* -1 means dynamically assign bus id */
+ return i2c_add_adapter(adap);
if (adap->nr & ~MAX_ID_MASK)
return -EINVAL;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index c90ce50..57a45ce8 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -579,7 +579,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
return 0;
}
-int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
+static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
void *data)
{
struct device *dev = data;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 9827c5e..5a26584 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -327,7 +327,7 @@ config BLK_DEV_OPTI621
select BLK_DEV_IDEPCI
help
This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
+ Please read the comments at the top of <file:drivers/ide/opti621.c>.
config BLK_DEV_RZ1000
tristate "RZ1000 chipset bugfix/support"
@@ -365,7 +365,7 @@ config BLK_DEV_ALI15X3
normal dual channel support.
Please read the comments at the top of
- <file:drivers/ide/pci/alim15x3.c>.
+ <file:drivers/ide/alim15x3.c>.
If unsure, say N.
@@ -528,7 +528,7 @@ config BLK_DEV_NS87415
This driver adds detection and support for the NS87415 chip
(used mainly on SPARC64 and PA-RISC machines).
- Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
+ Please read the comments at the top of <file:drivers/ide/ns87415.c>.
config BLK_DEV_PDC202XX_OLD
tristate "PROMISE PDC202{46|62|65|67} support"
@@ -547,7 +547,7 @@ config BLK_DEV_PDC202XX_OLD
for more than one card.
Please read the comments at the top of
- <file:drivers/ide/pci/pdc202xx_old.c>.
+ <file:drivers/ide/pdc202xx_old.c>.
If unsure, say N.
@@ -593,7 +593,7 @@ config BLK_DEV_SIS5513
ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
SiS745, SiS750
- Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+ Please read the comments at the top of <file:drivers/ide/sis5513.c>.
config BLK_DEV_SL82C105
tristate "Winbond SL82c105 support"
@@ -616,7 +616,7 @@ config BLK_DEV_SLC90E66
look-a-like to the PIIX4 it should be a nice addition.
Please read the comments at the top of
- <file:drivers/ide/pci/slc90e66.c>.
+ <file:drivers/ide/slc90e66.c>.
config BLK_DEV_TRM290
tristate "Tekram TRM290 chipset support"
@@ -625,7 +625,7 @@ config BLK_DEV_TRM290
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
needed for further tweaking and development.
- Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
+ Please read the comments at the top of <file:drivers/ide/trm290.c>.
config BLK_DEV_VIA82CXXX
tristate "VIA82CXXX chipset support"
@@ -677,19 +677,19 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST
config BLK_DEV_IDE_AU1XXX
bool "IDE for AMD Alchemy Au1200"
- depends on SOC_AU1200
+ depends on MIPS_ALCHEMY
select IDE_XFER_MODE
choice
prompt "IDE Mode for AMD Alchemy Au1200"
- default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
- depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
+ default BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+ depends on BLK_DEV_IDE_AU1XXX
config BLK_DEV_IDE_AU1XXX_PIO_DBDMA
bool "PIO+DbDMA IDE for AMD Alchemy Au1200"
config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200"
- depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
+ depends on BLK_DEV_IDE_AU1XXX
endchoice
config BLK_DEV_IDE_TX4938
@@ -836,7 +836,7 @@ config BLK_DEV_ALI14XX
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well.
See the files <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/ali14xx.c> for more info.
+ <file:drivers/ide/ali14xx.c> for more info.
config BLK_DEV_DTC2278
tristate "DTC-2278 support"
@@ -847,7 +847,7 @@ config BLK_DEV_DTC2278
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
well. See the <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/dtc2278.c> files for more info.
+ <file:drivers/ide/dtc2278.c> files for more info.
config BLK_DEV_HT6560B
tristate "Holtek HT6560B support"
@@ -858,7 +858,7 @@ config BLK_DEV_HT6560B
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
See the <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/ht6560b.c> files for more info.
+ <file:drivers/ide/ht6560b.c> files for more info.
config BLK_DEV_QD65XX
tristate "QDI QD65xx support"
@@ -867,7 +867,7 @@ config BLK_DEV_QD65XX
help
This driver is enabled at runtime using the "qd65xx.probe" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/qd65xx.c>
+ <file:Documentation/ide/ide.txt> and <file:drivers/ide/qd65xx.c>
for more info.
config BLK_DEV_UMC8672
@@ -879,7 +879,7 @@ config BLK_DEV_UMC8672
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
See the files <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/umc8672.c> for more info.
+ <file:drivers/ide/umc8672.c> for more info.
endif
diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
index 000a78e..6dede8f 100644
--- a/drivers/ide/at91_ide.c
+++ b/drivers/ide/at91_ide.c
@@ -28,7 +28,7 @@
#include <linux/platform_device.h>
#include <mach/board.h>
-#include <mach/gpio.h>
+#include <asm/gpio.h>
#include <mach/at91sam9_smc.h>
#define DRV_NAME "at91_ide"
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index b26c234..259786c 100644
--- a/drivers/ide/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
@@ -36,13 +36,17 @@
#include <linux/ide.h>
#include <linux/scatterlist.h>
-#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_ide.h>
#define DRV_NAME "au1200-ide"
#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
+#ifndef IDE_REG_SHIFT
+#define IDE_REG_SHIFT 5
+#endif
+
/* enable the burstmode in the dbdma */
#define IDE_AU1XXX_BURSTMODE 1
@@ -317,10 +321,11 @@ static void auide_ddma_rx_callback(int irq, void *param)
}
#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
-static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
+static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize,
+ u32 devwidth, u32 flags, u32 regbase)
{
dev->dev_id = dev_id;
- dev->dev_physaddr = (u32)IDE_PHYS_ADDR;
+ dev->dev_physaddr = CPHYSADDR(regbase);
dev->dev_intlevel = 0;
dev->dev_intpolarity = 0;
dev->dev_tsize = tsize;
@@ -344,7 +349,7 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
dbdev_tab_t source_dev_tab, target_dev_tab;
u32 dev_id, tsize, devwidth, flags;
- dev_id = IDE_DDMA_REQ;
+ dev_id = hwif->ddma_id;
tsize = 8; /* 1 */
devwidth = 32; /* 16 */
@@ -356,20 +361,17 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
#endif
/* setup dev_tab for tx channel */
- auide_init_dbdma_dev( &source_dev_tab,
- dev_id,
- tsize, devwidth, DEV_FLAGS_OUT | flags);
+ auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
+ DEV_FLAGS_OUT | flags, auide->regbase);
auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
- auide_init_dbdma_dev( &source_dev_tab,
- dev_id,
- tsize, devwidth, DEV_FLAGS_IN | flags);
+ auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
+ DEV_FLAGS_IN | flags, auide->regbase);
auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
/* We also need to add a target device for the DMA */
- auide_init_dbdma_dev( &target_dev_tab,
- (u32)DSCR_CMD0_ALWAYS,
- tsize, devwidth, DEV_FLAGS_ANYUSE);
+ auide_init_dbdma_dev(&target_dev_tab, (u32)DSCR_CMD0_ALWAYS, tsize,
+ devwidth, DEV_FLAGS_ANYUSE, auide->regbase);
auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab);
/* Get a channel for TX */
@@ -411,14 +413,12 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
#endif
/* setup dev_tab for tx channel */
- auide_init_dbdma_dev( &source_dev_tab,
- (u32)DSCR_CMD0_ALWAYS,
- 8, 32, DEV_FLAGS_OUT | flags);
+ auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
+ DEV_FLAGS_OUT | flags, auide->regbase);
auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
- auide_init_dbdma_dev( &source_dev_tab,
- (u32)DSCR_CMD0_ALWAYS,
- 8, 32, DEV_FLAGS_IN | flags);
+ auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
+ DEV_FLAGS_IN | flags, auide->regbase);
auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
/* Get a channel for TX */
@@ -540,6 +540,14 @@ static int au_ide_probe(struct platform_device *dev)
goto out;
}
+ res = platform_get_resource(dev, IORESOURCE_DMA, 0);
+ if (!res) {
+ pr_debug("%s: no DDMA ID resource\n", DRV_NAME);
+ ret = -ENODEV;
+ goto out;
+ }
+ ahwif->ddma_id = res->start;
+
memset(&hw, 0, sizeof(hw));
auide_setup_ports(&hw, ahwif);
hw.irq = ahwif->irq;
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index ab4f169..b1d3859 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -23,6 +23,7 @@
#include <linux/zorro.h>
#include <linux/ide.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index cb10201..a81bd75 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -105,6 +105,7 @@
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/io.h>
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index 3be60da..847553f 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz
*
* CYPRESS CY82C693 chipset IDE controller
*
@@ -90,7 +90,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
u8 time_16, time_8;
/* select primary or secondary channel */
- if (hwif->index > 0) { /* drive is on the secondary channel */
+ if (drive->dn > 1) { /* drive is on the secondary channel */
dev = pci_get_slot(dev->bus, dev->devfn+1);
if (!dev) {
printk(KERN_ERR "%s: tune_drive: "
@@ -141,6 +141,8 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
}
+ if (drive->dn > 1)
+ pci_dev_put(dev);
}
static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index 4a697a2..8716066 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -521,8 +521,8 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
d.init_dma = icside_dma_init;
d.port_ops = &icside_v6_port_ops;
+ } else
d.dma_ops = NULL;
- }
ret = ide_host_register(host, &d, hws);
if (ret)
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 2af8cb4..f22edc6 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -17,6 +17,7 @@
#include <linux/ide.h>
#include <linux/pci.h>
#include <linux/dmi.h>
+#include <linux/module.h>
#include <acpi/acpi_bus.h>
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 6f218e01..fac3d9d 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/ide.h>
#include <linux/scatterlist.h>
#include <linux/gfp.h>
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 04b0956..8126824 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -43,7 +43,6 @@
/* For SCSI -> ATAPI command conversion */
#include <scsi/scsi.h>
-#include <linux/irq.h>
#include <linux/io.h>
#include <asm/byteorder.h>
#include <linux/uaccess.h>
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
index f9bbd90..8b570a1 100644
--- a/drivers/ide/ide-disk_proc.c
+++ b/drivers/ide/ide-disk_proc.c
@@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/ide.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include <linux/seq_file.h>
#include "ide-disk.h"
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
index e4cdf78..289d16c 100644
--- a/drivers/ide/ide-dma-sff.c
+++ b/drivers/ide/ide-dma-sff.c
@@ -1,5 +1,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index d413690..17a65ac 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -31,6 +31,7 @@
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
index c0aa93f..3297066 100644
--- a/drivers/ide/ide-eh.c
+++ b/drivers/ide/ide-eh.c
@@ -1,5 +1,6 @@
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
#include <linux/delay.h>
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 61fdf54..3d42043 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -35,7 +35,6 @@
#include <scsi/scsi_ioctl.h>
#include <asm/byteorder.h>
-#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/unaligned.h>
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
index d711d9b..1600720 100644
--- a/drivers/ide/ide-floppy_proc.c
+++ b/drivers/ide/ide-floppy_proc.c
@@ -1,4 +1,5 @@
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
#include <linux/seq_file.h>
diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c
index 46721c4..1976397 100644
--- a/drivers/ide/ide-io-std.c
+++ b/drivers/ide/ide-io-std.c
@@ -1,5 +1,6 @@
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index 9965ecd..4d19eb9 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -2,6 +2,7 @@
* IDE ioctls handling.
*/
+#include <linux/export.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/slab.h>
diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c
index b9654a7..30fe363 100644
--- a/drivers/ide/ide-legacy.c
+++ b/drivers/ide/ide-legacy.c
@@ -1,4 +1,5 @@
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/ide.h>
static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw,
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index e386a32..d9c9829 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -1,6 +1,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/ide.h>
#include <linux/bitops.h>
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 017b1df..e5f3db8 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/pnp.h>
#include <linux/ide.h>
+#include <linux/module.h>
#define DRV_NAME "ide-pnp"
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 7ecb1ad..ce8237d 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -41,7 +41,6 @@
#include <scsi/scsi.h>
#include <asm/byteorder.h>
-#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/unaligned.h>
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 600c89a..5bc2839 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c
index 5fc8d5c..eb42188 100644
--- a/drivers/ide/ide-xfer-mode.c
+++ b/drivers/ide/ide-xfer-mode.c
@@ -1,6 +1,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/ide.h>
#include <linux/bitops.h>
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
index 542603b..962693b 100644
--- a/drivers/ide/ide_platform.c
+++ b/drivers/ide/ide_platform.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/ata_platform.h>
#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
static void __devinit plat_ide_setup_ports(struct ide_hw *hw,
@@ -95,7 +96,10 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
hw.dev = &pdev->dev;
- d.irq_flags = res_irq->flags;
+ d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+ if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
+ d.irq_flags |= IRQF_SHARED;
+
if (mmio)
d.host_flags |= IDE_HFLAG_MMIO;
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
index 505ec43..adc5fe9 100644
--- a/drivers/ide/macide.c
+++ b/drivers/ide/macide.c
@@ -17,6 +17,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/ide.h>
+#include <linux/module.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
index 9e8f4e1..712c790 100644
--- a/drivers/ide/palm_bk3710.c
+++ b/drivers/ide/palm_bk3710.c
@@ -342,7 +342,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
return -ENODEV;
}
- mem_size = mem->end - mem->start + 1;
+ mem_size = resource_size(mem);
if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) {
printk(KERN_ERR "failed to request memory region\n");
return -EBUSY;
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index b59d04c..1892e81 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -331,7 +331,7 @@ static const struct ide_port_ops ich_port_ops = {
.udma_mask = udma, \
}
-#define DECLARE_ICH_DEV(udma) \
+#define DECLARE_ICH_DEV(mwdma, udma) \
{ \
.name = DRV_NAME, \
.init_chipset = init_chipset_ich, \
@@ -340,7 +340,7 @@ static const struct ide_port_ops ich_port_ops = {
.port_ops = &ich_port_ops, \
.pio_mask = ATA_PIO4, \
.swdma_mask = ATA_SWDMA2_ONLY, \
- .mwdma_mask = ATA_MWDMA12_ONLY, \
+ .mwdma_mask = mwdma, \
.udma_mask = udma, \
}
@@ -362,13 +362,15 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = {
/* 2: PIIX4 */
DECLARE_PIIX_DEV(ATA_UDMA2),
/* 3: ICH0 */
- DECLARE_ICH_DEV(ATA_UDMA2),
+ DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2),
/* 4: ICH */
- DECLARE_ICH_DEV(ATA_UDMA4),
+ DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4),
/* 5: PIIX4 */
DECLARE_PIIX_DEV(ATA_UDMA4),
- /* 6: ICH[2-7]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
- DECLARE_ICH_DEV(ATA_UDMA5),
+ /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
+ DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5),
+ /* 7: ICH7/7-R, no MWDMA1 */
+ DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5),
};
/**
@@ -438,9 +440,9 @@ static const struct pci_device_id piix_pci_tbl[] = {
#endif
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 7 },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 7 },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 },
{ 0, },
};
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index 1db7c43..e944c7f 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/notifier.h>
+#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/pci.h>
#include <linux/adb.h>
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
index 9078608..ecd0a69 100644
--- a/drivers/ide/q40ide.c
+++ b/drivers/ide/q40ide.c
@@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/ide.h>
+#include <linux/module.h>
#include <asm/ide.h>
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index ab3db61..34a5e52 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c
index e444d24..4799d5c 100644
--- a/drivers/ide/tc86c001.c
+++ b/drivers/ide/tc86c001.c
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/ide.h>
+#include <linux/module.h>
#define DRV_NAME "tc86c001"
diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c
index e53a1b7..281c914 100644
--- a/drivers/ide/triflex.c
+++ b/drivers/ide/triflex.c
@@ -113,12 +113,26 @@ static const struct pci_device_id triflex_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
+#ifdef CONFIG_PM
+static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ /*
+ * We must not disable or powerdown the device.
+ * APM bios refuses to suspend if IDE is not accessible.
+ */
+ pci_save_state(dev);
+ return 0;
+}
+#else
+#define triflex_ide_pci_suspend NULL
+#endif
+
static struct pci_driver triflex_pci_driver = {
.name = "TRIFLEX_IDE",
.id_table = triflex_pci_tbl,
.probe = triflex_init_one,
.remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
+ .suspend = triflex_ide_pci_suspend,
.resume = ide_pci_resume,
};
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index bed3e39..71c2319 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -551,10 +551,10 @@ static int __init tx4939ide_probe(struct platform_device *pdev)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res->start,
- res->end - res->start + 1, "tx4938ide"))
+ resource_size(res), "tx4938ide"))
return -EBUSY;
mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
- res->end - res->start + 1);
+ resource_size(res));
if (!mapbase)
return -EBUSY;
memset(&hw, 0, sizeof(hw));
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 8da42e4..d63d0a8 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -1,6 +1,7 @@
config USB_PWC
tristate "USB Philips Cameras"
depends on VIDEO_V4L2
+ select VIDEOBUF2_VMALLOC
---help---
Say Y or M here if you want to use one of these Philips & OEM
webcams:
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 760b4de..3977add 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -3,6 +3,7 @@
video modes.
(C) 1999-2003 Nemosoft Unv.
(C) 2004-2006 Luc Saillard (luc@saillard.org)
+ (C) 2011 Hans de Goede <hdegoede@redhat.com>
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -43,61 +44,12 @@
#include <asm/errno.h>
#include "pwc.h"
-#include "pwc-uncompress.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
#include "pwc-dec1.h"
#include "pwc-dec23.h"
-/* Request types: video */
-#define SET_LUM_CTL 0x01
-#define GET_LUM_CTL 0x02
-#define SET_CHROM_CTL 0x03
-#define GET_CHROM_CTL 0x04
-#define SET_STATUS_CTL 0x05
-#define GET_STATUS_CTL 0x06
-#define SET_EP_STREAM_CTL 0x07
-#define GET_EP_STREAM_CTL 0x08
-#define GET_XX_CTL 0x09
-#define SET_XX_CTL 0x0A
-#define GET_XY_CTL 0x0B
-#define SET_XY_CTL 0x0C
-#define SET_MPT_CTL 0x0D
-#define GET_MPT_CTL 0x0E
-
-/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
-#define AGC_MODE_FORMATTER 0x2000
-#define PRESET_AGC_FORMATTER 0x2100
-#define SHUTTER_MODE_FORMATTER 0x2200
-#define PRESET_SHUTTER_FORMATTER 0x2300
-#define PRESET_CONTOUR_FORMATTER 0x2400
-#define AUTO_CONTOUR_FORMATTER 0x2500
-#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600
-#define CONTRAST_FORMATTER 0x2700
-#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800
-#define FLICKERLESS_MODE_FORMATTER 0x2900
-#define AE_CONTROL_SPEED 0x2A00
-#define BRIGHTNESS_FORMATTER 0x2B00
-#define GAMMA_FORMATTER 0x2C00
-
-/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
-#define WB_MODE_FORMATTER 0x1000
-#define AWB_CONTROL_SPEED_FORMATTER 0x1100
-#define AWB_CONTROL_DELAY_FORMATTER 0x1200
-#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300
-#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400
-#define COLOUR_MODE_FORMATTER 0x1500
-#define SATURATION_MODE_FORMATTER1 0x1600
-#define SATURATION_MODE_FORMATTER2 0x1700
-
-/* Selectors for the Status controls [GS]ET_STATUS_CTL */
-#define SAVE_USER_DEFAULTS_FORMATTER 0x0200
-#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300
-#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400
-#define READ_AGC_FORMATTER 0x0500
-#define READ_SHUTTER_FORMATTER 0x0600
-#define READ_RED_GAIN_FORMATTER 0x0700
-#define READ_BLUE_GAIN_FORMATTER 0x0800
+/* Selectors for status controls used only in this file */
#define GET_STATUS_B00 0x0B00
#define SENSOR_TYPE_FORMATTER1 0x0C00
#define GET_STATUS_3000 0x3000
@@ -116,11 +68,6 @@
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
-/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
-#define PT_RELATIVE_CONTROL_FORMATTER 0x01
-#define PT_RESET_CONTROL_FORMATTER 0x02
-#define PT_STATUS_FORMATTER 0x03
-
static const char *size2name[PSZ_MAX] =
{
"subQCIF",
@@ -160,7 +107,7 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev);
/****************************************************************************/
static int _send_control_msg(struct pwc_device *pdev,
- u8 request, u16 value, int index, void *buf, int buflen, int timeout)
+ u8 request, u16 value, int index, void *buf, int buflen)
{
int rc;
void *kbuf = NULL;
@@ -177,7 +124,7 @@ static int _send_control_msg(struct pwc_device *pdev,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
index,
- kbuf, buflen, timeout);
+ kbuf, buflen, USB_CTRL_SET_TIMEOUT);
kfree(kbuf);
return rc;
@@ -197,9 +144,13 @@ static int recv_control_msg(struct pwc_device *pdev,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
pdev->vcinterface,
- kbuf, buflen, 500);
+ kbuf, buflen, USB_CTRL_GET_TIMEOUT);
memcpy(buf, kbuf, buflen);
kfree(kbuf);
+
+ if (rc < 0)
+ PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
+ rc, request, value);
return rc;
}
@@ -210,18 +161,16 @@ static inline int send_video_command(struct pwc_device *pdev,
SET_EP_STREAM_CTL,
VIDEO_OUTPUT_CONTROL_FORMATTER,