From c2c62e61fb8559420bb0346953843e557cdddba7 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 19 Apr 2013 21:01:31 +0400 Subject: [PATCH 0001/1910] xtensa: xtfpga: add audio card to xtfpga DTS This includes OpenCores I2C host controller, TI CDCE706 clock generator, xtfpga I2S master controller, xtfpga SPI master controller, TI TLV320AIC23 audio codec and a simple audio card. Signed-off-by: Max Filippov --- arch/xtensa/boot/dts/xtfpga.dtsi | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi index dec9178840f6..cd0b9e34adc8 100644 --- a/arch/xtensa/boot/dts/xtfpga.dtsi +++ b/arch/xtensa/boot/dts/xtfpga.dtsi @@ -40,6 +40,12 @@ #clock-cells = <0>; compatible = "fixed-clock"; }; + + clk54: clk54 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <54000000>; + }; }; soc { @@ -65,5 +71,63 @@ local-mac-address = [00 50 c2 13 6f 00]; clocks = <&osc>; }; + + i2s0: xtfpga-i2s@0d080000 { + #sound-dai-cells = <0>; + compatible = "cdns,xtfpga-i2s"; + reg = <0x0d080000 0x40>; + interrupts = <2 1>; /* external irq 2 */ + clocks = <&cdce706 4>; + }; + + i2c0: i2c-master@0d090000 { + compatible = "opencores,i2c-ocores"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0d090000 0x20>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <4 1>; + clocks = <&osc>; + + cdce706: clock-synth@69 { + compatible = "ti,cdce706"; + #clock-cells = <1>; + reg = <0x69>; + clocks = <&clk54>; + clock-names = "clk_in0"; + }; + }; + + spi0: spi-master@0d0a0000 { + compatible = "cdns,xtfpga-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0d0a0000 0xc>; + + tlv320aic23: sound-codec@0 { + #sound-dai-cells = <0>; + compatible = "tlv320aic23"; + reg = <0>; + spi-max-frequency = <12500000>; + }; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + + simple-audio-card,cpu { + sound-dai = <&i2s0>; + }; + + simple-audio-card,codec { + sound-dai = <&tlv320aic23>; + simple-audio-card,bitclock-master = <0>; + simple-audio-card,frame-master = <0>; + clocks = <&cdce706 4>; + }; }; }; -- GitLab From 04ddc5b5ad4eca2b96160663431f041bec2efc2e Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sat, 7 Feb 2015 12:47:56 +0300 Subject: [PATCH 0002/1910] xtensa: xtfpga: provide defconfig with audio subsystem This is the generic KC705 defconfig with all pieces of xtfpga audio subsystem enabled: I2C, SPI and ASoC support, I2C master, SPI master, clock synthesizer, I2S master, audio codec and audio card drivers. Signed-off-by: Max Filippov --- arch/xtensa/configs/audio_kc705_defconfig | 142 ++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 arch/xtensa/configs/audio_kc705_defconfig diff --git a/arch/xtensa/configs/audio_kc705_defconfig b/arch/xtensa/configs/audio_kc705_defconfig new file mode 100644 index 000000000000..c4904db15582 --- /dev/null +++ b/arch/xtensa/configs/audio_kc705_defconfig @@ -0,0 +1,142 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_FHANDLE=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_XTENSA_VARIANT_CUSTOM=y +CONFIG_XTENSA_VARIANT_CUSTOM_NAME="test_kc705_hifi" +CONFIG_XTENSA_UNALIGNED_USER=y +CONFIG_PREEMPT=y +CONFIG_HIGHMEM=y +# CONFIG_PCI is not set +CONFIG_XTENSA_PLATFORM_XTFPGA=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug" +CONFIG_USE_OF=y +CONFIG_BUILTIN_DTB="kc705" +# CONFIG_COMPACTION is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_MARVELL_PHY=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_OCORES=y +CONFIG_SPI=y +CONFIG_SPI_XTENSA_XTFPGA=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_SOFT_WATCHDOG=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_XTFPGA_I2S=y +CONFIG_SND_SOC_TLV320AIC23_SPI=y +CONFIG_SND_SIMPLE_CARD=y +# CONFIG_USB_SUPPORT is not set +CONFIG_COMMON_CLK_CDCE706=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_FANOTIFY=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_ROOT_NFS=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_STACKTRACE=y +CONFIG_RCU_TRACE=y +# CONFIG_FTRACE is not set +# CONFIG_S32C1I_SELFTEST is not set +CONFIG_CRYPTO_ANSI_CPRNG=y -- GitLab From 5163c1eede8e9073e5b6bf1a988ed07d35820343 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 9 Feb 2015 13:26:01 +0200 Subject: [PATCH 0003/1910] ASoC: omap: Kconfig: Support for omap5-uevm analog audio The analog audio is supported via omap-abe-twl6040 machine driver on omap5-uevm. Update the Kconfig file to reflect this and select the Palmas clock driver which is providing the 32K clock for audio on omap5-uevm. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a2cd3486ac55..e7c78b0406b5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -100,17 +100,19 @@ config SND_OMAP_SOC_OMAP_TWL4030 config SND_OMAP_SOC_OMAP_ABE_TWL6040 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" - depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST) + depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST) select SND_OMAP_SOC_DMIC select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 select SND_SOC_DMIC + select COMMON_CLK_PALMAS if SOC_OMAP5 help Say Y if you want to add support for SoC audio on OMAP boards using ABE and twl6040 codec. This driver currently supports: - SDP4430/Blaze boards - PandaBoard (4430) - PandaBoardES (4460) + - omap5-uevm (5432) config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" -- GitLab From b6d6c6e95ff0e78f9b8393e6b9f25d5a4341ae1a Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 9 Feb 2015 16:08:25 +0100 Subject: [PATCH 0004/1910] ASoC: atmel_ssc_dai: Allow more rates When the SSC acts as BCK master, use a ratnum rule to limit the rate instead of only doing the standard rates. When the SSC acts as BCK slave, allow any BCK frequency up to the SSC master clock, divided by either of 2, 3 or 6. Put a cap at 384kHz. Who's /ever/ going to need more than that? The divider of 2, 3 or 6 is selected based on the Serial Clock Ratio Considerations section from the SSC documentation: The Transmitter and the Receiver can be programmed to operate with the clock signals provided on either the TK or RK pins. This allows the SSC to support many slave-mode data transfers. In this case, the maximum clock speed allowed on the RK pin is: - Peripheral clock divided by 2 if Receiver Frame Synchro is input - Peripheral clock divided by 3 if Receiver Frame Synchro is output In addition, the maximum clock speed allowed on the TK pin is: - Peripheral clock divided by 6 if Transmit Frame Synchro is input - Peripheral clock divided by 2 if Transmit Frame Synchro is output Signed-off-by: Peter Rosin Acked-by: Bo Shen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 111 ++++++++++++++++++++++++++++++-- sound/soc/atmel/atmel_ssc_dai.h | 1 + 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 379ac2a6ab16..6b8e64899205 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * When the bit clock is input, limit the maximum rate according to the + * Serial Clock Ratio Considerations section from the SSC documentation: + * + * The Transmitter and the Receiver can be programmed to operate + * with the clock signals provided on either the TK or RK pins. + * This allows the SSC to support many slave-mode data transfers. + * In this case, the maximum clock speed allowed on the RK pin is: + * - Peripheral clock divided by 2 if Receiver Frame Synchro is input + * - Peripheral clock divided by 3 if Receiver Frame Synchro is output + * In addition, the maximum clock speed allowed on the TK pin is: + * - Peripheral clock divided by 6 if Transmit Frame Synchro is input + * - Peripheral clock divided by 2 if Transmit Frame Synchro is output + * + * When the bit clock is output, limit the rate according to the + * SSC divider restrictions. + */ +static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct atmel_ssc_info *ssc_p = rule->private; + struct ssc_device *ssc = ssc_p->ssc; + struct snd_interval *i = hw_param_interval(params, rule->var); + struct snd_interval t; + struct snd_ratnum r = { + .den_min = 1, + .den_max = 4095, + .den_step = 1, + }; + unsigned int num = 0, den = 0; + int frame_size; + int mck_div = 2; + int ret; + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) + return frame_size; + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: + if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) + && ssc->clk_from_rk_pin) + /* Receiver Frame Synchro (i.e. capture) + * is output (format is _CFS) and the RK pin + * is used for input (format is _CBM_). + */ + mck_div = 3; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) + && !ssc->clk_from_rk_pin) + /* Transmit Frame Synchro (i.e. playback) + * is input (format is _CFM) and the TK pin + * is used for input (format _CBM_ but not + * using the RK pin). + */ + mck_div = 6; + break; + } + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + r.num = ssc_p->mck_rate / mck_div / frame_size; + + ret = snd_interval_ratnum(i, 1, &r, &num, &den); + if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { + params->rate_num = num; + params->rate_den = den; + } + break; + + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBM_CFM: + t.min = 8000; + t.max = ssc_p->mck_rate / mck_div / frame_size; + t.openmin = t.openmax = 0; + t.integer = 0; + ret = snd_interval_refine(i, &t); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} /*-------------------------------------------------------------------------*\ * DAI functions @@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; + int ret; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); @@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); clk_enable(ssc_p->ssc->clk); + ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC to keep it at a clean status */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); @@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, dir_mask = SSC_DIR_MASK_CAPTURE; } + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + atmel_ssc_hw_rule_rate, + ssc_p, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret < 0) { + dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret); + return ret; + } + dma_params = &ssc_dma_params[dai->id][dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; @@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ -#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) - #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { .channels_min = 1, .channels_max = 2, - .rates = ATMEL_SSC_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, }; diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index b1f08d511495..80b153857a88 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -115,6 +115,7 @@ struct atmel_ssc_info { unsigned short rcmr_period; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; + unsigned long mck_rate; }; int atmel_ssc_set_audio(int ssc_id); -- GitLab From b6a42670e074da39b5a9f990774359e0733ca9cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Feb 2015 22:37:16 +0100 Subject: [PATCH 0005/1910] ALSA: seq: Move EXPORT_SYMBOL() after each function ... to follow the standard coding style. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_device.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 0631bdadd12b..a752a79a8d3a 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -133,11 +133,13 @@ void snd_seq_autoload_lock(void) { atomic_inc(&snd_seq_in_init); } +EXPORT_SYMBOL(snd_seq_autoload_lock); void snd_seq_autoload_unlock(void) { atomic_dec(&snd_seq_in_init); } +EXPORT_SYMBOL(snd_seq_autoload_unlock); static void autoload_drivers(void) { @@ -195,10 +197,12 @@ void snd_seq_autoload_init(void) queue_autoload_drivers(); #endif } +EXPORT_SYMBOL(snd_seq_autoload_init); #else #define try_autoload(ops) /* NOP */ #endif + void snd_seq_device_load_drivers(void) { #ifdef CONFIG_MODULES @@ -206,6 +210,7 @@ void snd_seq_device_load_drivers(void) flush_work(&autoload_work); #endif } +EXPORT_SYMBOL(snd_seq_device_load_drivers); /* * register a sequencer device @@ -268,6 +273,7 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, return 0; } +EXPORT_SYMBOL(snd_seq_device_new); /* * free the existing device @@ -326,6 +332,7 @@ static int snd_seq_device_dev_register(struct snd_device *device) unlock_driver(ops); return 0; } +EXPORT_SYMBOL(snd_seq_device_register_driver); /* * disconnect the device @@ -344,6 +351,7 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) unlock_driver(ops); return 0; } +EXPORT_SYMBOL(snd_seq_device_unregister_driver); /* * register device driver @@ -604,13 +612,3 @@ static void __exit alsa_seq_device_exit(void) module_init(alsa_seq_device_init) module_exit(alsa_seq_device_exit) - -EXPORT_SYMBOL(snd_seq_device_load_drivers); -EXPORT_SYMBOL(snd_seq_device_new); -EXPORT_SYMBOL(snd_seq_device_register_driver); -EXPORT_SYMBOL(snd_seq_device_unregister_driver); -#ifdef CONFIG_MODULES -EXPORT_SYMBOL(snd_seq_autoload_init); -EXPORT_SYMBOL(snd_seq_autoload_lock); -EXPORT_SYMBOL(snd_seq_autoload_unlock); -#endif -- GitLab From 72496edcf85e048b4c5373d518e4f27938d9594e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Feb 2015 22:39:51 +0100 Subject: [PATCH 0006/1910] ALSA: seq: Don't compile snd_seq_device_load_drivers() for built-in Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 4 ++++ sound/core/seq/seq_device.c | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index 2b5f24cc7548..d52433563da2 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -67,7 +67,11 @@ struct snd_seq_dev_ops { /* * prototypes */ +#ifdef CONFIG_MODULES void snd_seq_device_load_drivers(void); +#else +#define snd_seq_device_load_drivers() +#endif int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result); int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize); int snd_seq_device_unregister_driver(char *id); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index a752a79a8d3a..075a66c0cc6a 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -198,19 +198,16 @@ void snd_seq_autoload_init(void) #endif } EXPORT_SYMBOL(snd_seq_autoload_init); -#else -#define try_autoload(ops) /* NOP */ -#endif - void snd_seq_device_load_drivers(void) { -#ifdef CONFIG_MODULES queue_autoload_drivers(); flush_work(&autoload_work); -#endif } EXPORT_SYMBOL(snd_seq_device_load_drivers); +#else +#define try_autoload(ops) /* NOP */ +#endif /* * register a sequencer device -- GitLab From 7c37ae5c625aaa4836466cfaea829a3199dfc571 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 10:51:59 +0100 Subject: [PATCH 0007/1910] ALSA: seq: Rewrite sequencer device binding with standard bus We've used the old house-made code for binding the sequencer device and driver. This can be far better implemented with the standard bus nowadays. This patch refactors the whole sequencer binding code with the bus /sys/bus/snd_seq. The devices appear as id-card-device on this bus and are bound with the drivers corresponding to the given id like the former implementation. The module autoload is also kept like before. There is no change in API functions by this patch, and almost all transitions are kept inside seq_device.c. The proc file output will change slightly but kept compatible as much as possible. Further integration works will follow in later patches. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 3 + sound/core/seq/seq_device.c | 541 +++++++++++------------------------- 2 files changed, 170 insertions(+), 374 deletions(-) diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index d52433563da2..ea256b825146 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -43,8 +43,11 @@ struct snd_seq_device { void *private_data; /* private data for the caller */ void (*private_free)(struct snd_seq_device *device); struct list_head list; /* link to next device */ + struct device dev; }; +#define to_seq_dev(_dev) \ + container_of(_dev, struct snd_seq_device, dev) /* driver operators * init_device: diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 075a66c0cc6a..d3320ffe43c2 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -36,6 +36,7 @@ * */ +#include #include #include #include @@ -51,77 +52,57 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_LICENSE("GPL"); -/* driver state */ -#define DRIVER_EMPTY 0 -#define DRIVER_LOADED (1<<0) -#define DRIVER_REQUESTED (1<<1) -#define DRIVER_LOCKED (1<<2) -#define DRIVER_REQUESTING (1<<3) +struct snd_seq_driver { + struct device_driver driver; + char id[ID_LEN]; + int argsize; + struct snd_seq_dev_ops ops; +}; -struct ops_list { - char id[ID_LEN]; /* driver id */ - int driver; /* driver state */ - int used; /* reference counter */ - int argsize; /* argument size */ +#define to_seq_drv(_drv) \ + container_of(_drv, struct snd_seq_driver, driver) - /* operators */ - struct snd_seq_dev_ops ops; +/* + * bus definition + */ +static int snd_seq_bus_match(struct device *dev, struct device_driver *drv) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + struct snd_seq_driver *sdrv = to_seq_drv(drv); - /* registered devices */ - struct list_head dev_list; /* list of devices */ - int num_devices; /* number of associated devices */ - int num_init_devices; /* number of initialized devices */ - struct mutex reg_mutex; + return strcmp(sdrv->id, sdev->id) == 0 && + sdrv->argsize == sdev->argsize; +} - struct list_head list; /* next driver */ +static struct bus_type snd_seq_bus_type = { + .name = "snd_seq", + .match = snd_seq_bus_match, }; - -static LIST_HEAD(opslist); -static int num_ops; -static DEFINE_MUTEX(ops_mutex); +/* + * proc interface -- just for compatibility + */ #ifdef CONFIG_PROC_FS static struct snd_info_entry *info_entry; -#endif -/* - * prototypes - */ -static int snd_seq_device_free(struct snd_seq_device *dev); -static int snd_seq_device_dev_free(struct snd_device *device); -static int snd_seq_device_dev_register(struct snd_device *device); -static int snd_seq_device_dev_disconnect(struct snd_device *device); - -static int init_device(struct snd_seq_device *dev, struct ops_list *ops); -static int free_device(struct snd_seq_device *dev, struct ops_list *ops); -static struct ops_list *find_driver(char *id, int create_if_empty); -static struct ops_list *create_driver(char *id); -static void unlock_driver(struct ops_list *ops); -static void remove_drivers(void); +static int print_dev_info(struct device *dev, void *data) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + struct snd_info_buffer *buffer = data; -/* - * show all drivers and their status - */ + snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id, + dev->driver ? "loaded" : "empty", + dev->driver ? 1 : 0); + return 0; +} -#ifdef CONFIG_PROC_FS static void snd_seq_device_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", - ops->id, - ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), - ops->driver & DRIVER_REQUESTED ? ",requested" : "", - ops->driver & DRIVER_LOCKED ? ",locked" : "", - ops->num_devices); - } - mutex_unlock(&ops_mutex); + bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info); } #endif - + /* * load all registered drivers (called from seq_clientmgr.c) */ @@ -141,52 +122,29 @@ void snd_seq_autoload_unlock(void) } EXPORT_SYMBOL(snd_seq_autoload_unlock); -static void autoload_drivers(void) +static int request_seq_drv(struct device *dev, void *data) { - /* avoid reentrance */ - if (atomic_inc_return(&snd_seq_in_init) == 1) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if ((ops->driver & DRIVER_REQUESTING) && - !(ops->driver & DRIVER_REQUESTED)) { - ops->used++; - mutex_unlock(&ops_mutex); - ops->driver |= DRIVER_REQUESTED; - request_module("snd-%s", ops->id); - mutex_lock(&ops_mutex); - ops->used--; - } - } - mutex_unlock(&ops_mutex); - } - atomic_dec(&snd_seq_in_init); -} + struct snd_seq_device *sdev = to_seq_dev(dev); -static void call_autoload(struct work_struct *work) -{ - autoload_drivers(); + if (!dev->driver) + request_module("snd-%s", sdev->id); + return 0; } -static DECLARE_WORK(autoload_work, call_autoload); - -static void try_autoload(struct ops_list *ops) +static void autoload_drivers(struct work_struct *work) { - if (!ops->driver) { - ops->driver |= DRIVER_REQUESTING; - schedule_work(&autoload_work); - } + /* avoid reentrance */ + if (atomic_inc_return(&snd_seq_in_init) == 1) + bus_for_each_dev(&snd_seq_bus_type, NULL, NULL, + request_seq_drv); + atomic_dec(&snd_seq_in_init); } +static DECLARE_WORK(autoload_work, autoload_drivers); + static void queue_autoload_drivers(void) { - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) - try_autoload(ops); - mutex_unlock(&ops_mutex); + schedule_work(&autoload_work); } void snd_seq_autoload_init(void) @@ -206,9 +164,50 @@ void snd_seq_device_load_drivers(void) } EXPORT_SYMBOL(snd_seq_device_load_drivers); #else -#define try_autoload(ops) /* NOP */ +#define queue_autoload_drivers() /* NOP */ #endif +/* + * device management + */ +static int snd_seq_device_dev_free(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + + put_device(&dev->dev); + return 0; +} + +static int snd_seq_device_dev_register(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + int err; + + err = device_add(&dev->dev); + if (err < 0) + return err; + if (!dev->dev.driver) + queue_autoload_drivers(); + return 0; +} + +static int snd_seq_device_dev_disconnect(struct snd_device *device) +{ + struct snd_seq_device *dev = device->device_data; + + device_del(&dev->dev); + return 0; +} + +static void snd_seq_dev_release(struct device *dev) +{ + struct snd_seq_device *sdev = to_seq_dev(dev); + + if (sdev->private_free) + sdev->private_free(sdev); + kfree(sdev); +} + /* * register a sequencer device * card = card info @@ -220,7 +219,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result) { struct snd_seq_device *dev; - struct ops_list *ops; int err; static struct snd_device_ops dops = { .dev_free = snd_seq_device_dev_free, @@ -234,15 +232,9 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, if (snd_BUG_ON(!id)) return -EINVAL; - ops = find_driver(id, 1); - if (ops == NULL) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); - if (dev == NULL) { - unlock_driver(ops); + dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL); + if (!dev) return -ENOMEM; - } /* set up device info */ dev->card = card; @@ -251,20 +243,19 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, dev->argsize = argsize; dev->status = SNDRV_SEQ_DEVICE_FREE; - /* add this device to the list */ - mutex_lock(&ops->reg_mutex); - list_add_tail(&dev->list, &ops->dev_list); - ops->num_devices++; - mutex_unlock(&ops->reg_mutex); + device_initialize(&dev->dev); + dev->dev.parent = &card->card_dev; + dev->dev.bus = &snd_seq_bus_type; + dev->dev.release = snd_seq_dev_release; + dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device); - if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { - snd_seq_device_free(dev); + /* add this device to the list */ + err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops); + if (err < 0) { + put_device(&dev->dev); return err; } - try_autoload(ops); - unlock_driver(ops); - if (result) *result = dev; @@ -273,82 +264,33 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, EXPORT_SYMBOL(snd_seq_device_new); /* - * free the existing device - */ -static int snd_seq_device_free(struct snd_seq_device *dev) -{ - struct ops_list *ops; - - if (snd_BUG_ON(!dev)) - return -EINVAL; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENXIO; - - /* remove the device from the list */ - mutex_lock(&ops->reg_mutex); - list_del(&dev->list); - ops->num_devices--; - mutex_unlock(&ops->reg_mutex); - - free_device(dev, ops); - if (dev->private_free) - dev->private_free(dev); - kfree(dev); - - unlock_driver(ops); - - return 0; -} - -static int snd_seq_device_dev_free(struct snd_device *device) -{ - struct snd_seq_device *dev = device->device_data; - return snd_seq_device_free(dev); -} - -/* - * register the device + * driver binding - just pass to each driver callback */ -static int snd_seq_device_dev_register(struct snd_device *device) +static int snd_seq_drv_probe(struct device *dev) { - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - /* initialize this device if the corresponding driver was - * already loaded - */ - if (ops->driver & DRIVER_LOADED) - init_device(dev, ops); + struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); + struct snd_seq_device *sdev = to_seq_dev(dev); + int err; - unlock_driver(ops); + err = sdrv->ops.init_device(sdev); + if (err < 0) + return err; + sdev->status = SNDRV_SEQ_DEVICE_REGISTERED; return 0; } -EXPORT_SYMBOL(snd_seq_device_register_driver); -/* - * disconnect the device - */ -static int snd_seq_device_dev_disconnect(struct snd_device *device) +static int snd_seq_drv_remove(struct device *dev) { - struct snd_seq_device *dev = device->device_data; - struct ops_list *ops; - - ops = find_driver(dev->id, 0); - if (ops == NULL) - return -ENOENT; - - free_device(dev, ops); + struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); + struct snd_seq_device *sdev = to_seq_dev(dev); + int err; - unlock_driver(ops); + err = sdrv->ops.free_device(sdev); + if (err < 0) + return err; + sdev->status = SNDRV_SEQ_DEVICE_FREE; return 0; } -EXPORT_SYMBOL(snd_seq_device_unregister_driver); /* * register device driver @@ -358,226 +300,66 @@ EXPORT_SYMBOL(snd_seq_device_unregister_driver); int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize) { - struct ops_list *ops; - struct snd_seq_device *dev; + struct snd_seq_driver *sdrv; + int err; if (id == NULL || entry == NULL || entry->init_device == NULL || entry->free_device == NULL) return -EINVAL; - ops = find_driver(id, 1); - if (ops == NULL) + sdrv = kzalloc(sizeof(*sdrv), GFP_KERNEL); + if (!sdrv) return -ENOMEM; - if (ops->driver & DRIVER_LOADED) { - pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id); - unlock_driver(ops); - return -EBUSY; - } - - mutex_lock(&ops->reg_mutex); - /* copy driver operators */ - ops->ops = *entry; - ops->driver |= DRIVER_LOADED; - ops->argsize = argsize; - /* initialize existing devices if necessary */ - list_for_each_entry(dev, &ops->dev_list, list) { - init_device(dev, ops); - } - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - return 0; + sdrv->driver.name = id; + sdrv->driver.bus = &snd_seq_bus_type; + sdrv->driver.probe = snd_seq_drv_probe; + sdrv->driver.remove = snd_seq_drv_remove; + strlcpy(sdrv->id, id, sizeof(sdrv->id)); + sdrv->argsize = argsize; + sdrv->ops = *entry; + + err = driver_register(&sdrv->driver); + if (err < 0) + kfree(sdrv); + return err; } +EXPORT_SYMBOL(snd_seq_device_register_driver); - -/* - * create driver record +/* callback to find a specific driver; data is a pointer to the id string ptr. + * when the id matches, store the driver pointer in return and break the loop. */ -static struct ops_list * create_driver(char *id) +static int find_drv(struct device_driver *drv, void *data) { - struct ops_list *ops; - - ops = kzalloc(sizeof(*ops), GFP_KERNEL); - if (ops == NULL) - return ops; - - /* set up driver entry */ - strlcpy(ops->id, id, sizeof(ops->id)); - mutex_init(&ops->reg_mutex); - /* - * The ->reg_mutex locking rules are per-driver, so we create - * separate per-driver lock classes: - */ - lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id); - - ops->driver = DRIVER_EMPTY; - INIT_LIST_HEAD(&ops->dev_list); - /* lock this instance */ - ops->used = 1; - - /* register driver entry */ - mutex_lock(&ops_mutex); - list_add_tail(&ops->list, &opslist); - num_ops++; - mutex_unlock(&ops_mutex); - - return ops; -} + struct snd_seq_driver *sdrv = to_seq_drv(drv); + void **ptr = (void **)data; + if (strcmp(sdrv->id, *ptr)) + return 0; /* id don't match, continue the loop */ + *ptr = sdrv; + return 1; /* break the loop */ +} /* * unregister the specified driver */ int snd_seq_device_unregister_driver(char *id) { - struct ops_list *ops; - struct snd_seq_device *dev; + struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; - ops = find_driver(id, 0); - if (ops == NULL) + if (!bus_for_each_drv(&snd_seq_bus_type, NULL, &sdrv, find_drv)) return -ENXIO; - if (! (ops->driver & DRIVER_LOADED) || - (ops->driver & DRIVER_LOCKED)) { - pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n", - id, ops->driver); - unlock_driver(ops); - return -EBUSY; - } - - /* close and release all devices associated with this driver */ - mutex_lock(&ops->reg_mutex); - ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ - list_for_each_entry(dev, &ops->dev_list, list) { - free_device(dev, ops); - } - - ops->driver = 0; - if (ops->num_init_devices > 0) - pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n", - ops->num_init_devices); - mutex_unlock(&ops->reg_mutex); - - unlock_driver(ops); - - /* remove empty driver entries */ - remove_drivers(); - + driver_unregister(&sdrv->driver); + kfree(sdrv); return 0; } - - -/* - * remove empty driver entries - */ -static void remove_drivers(void) -{ - struct list_head *head; - - mutex_lock(&ops_mutex); - head = opslist.next; - while (head != &opslist) { - struct ops_list *ops = list_entry(head, struct ops_list, list); - if (! (ops->driver & DRIVER_LOADED) && - ops->used == 0 && ops->num_devices == 0) { - head = head->next; - list_del(&ops->list); - kfree(ops); - num_ops--; - } else - head = head->next; - } - mutex_unlock(&ops_mutex); -} - -/* - * initialize the device - call init_device operator - */ -static int init_device(struct snd_seq_device *dev, struct ops_list *ops) -{ - if (! (ops->driver & DRIVER_LOADED)) - return 0; /* driver is not loaded yet */ - if (dev->status != SNDRV_SEQ_DEVICE_FREE) - return 0; /* already initialized */ - if (ops->argsize != dev->argsize) { - pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", - dev->name, ops->id, ops->argsize, dev->argsize); - return -EINVAL; - } - if (ops->ops.init_device(dev) >= 0) { - dev->status = SNDRV_SEQ_DEVICE_REGISTERED; - ops->num_init_devices++; - } else { - pr_err("ALSA: seq: init_device failed: %s: %s\n", - dev->name, dev->id); - } - - return 0; -} - -/* - * release the device - call free_device operator - */ -static int free_device(struct snd_seq_device *dev, struct ops_list *ops) -{ - int result; - - if (! (ops->driver & DRIVER_LOADED)) - return 0; /* driver is not loaded yet */ - if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) - return 0; /* not registered */ - if (ops->argsize != dev->argsize) { - pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", - dev->name, ops->id, ops->argsize, dev->argsize); - return -EINVAL; - } - if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { - dev->status = SNDRV_SEQ_DEVICE_FREE; - dev->driver_data = NULL; - ops->num_init_devices--; - } else { - pr_err("ALSA: seq: free_device failed: %s: %s\n", - dev->name, dev->id); - } - - return 0; -} - -/* - * find the matching driver with given id - */ -static struct ops_list * find_driver(char *id, int create_if_empty) -{ - struct ops_list *ops; - - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if (strcmp(ops->id, id) == 0) { - ops->used++; - mutex_unlock(&ops_mutex); - return ops; - } - } - mutex_unlock(&ops_mutex); - if (create_if_empty) - return create_driver(id); - return NULL; -} - -static void unlock_driver(struct ops_list *ops) -{ - mutex_lock(&ops_mutex); - ops->used--; - mutex_unlock(&ops_mutex); -} - +EXPORT_SYMBOL(snd_seq_device_unregister_driver); /* * module part */ -static int __init alsa_seq_device_init(void) +static int __init seq_dev_proc_init(void) { #ifdef CONFIG_PROC_FS info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", @@ -594,17 +376,28 @@ static int __init alsa_seq_device_init(void) return 0; } +static int __init alsa_seq_device_init(void) +{ + int err; + + err = bus_register(&snd_seq_bus_type); + if (err < 0) + return err; + err = seq_dev_proc_init(); + if (err < 0) + bus_unregister(&snd_seq_bus_type); + return err; +} + static void __exit alsa_seq_device_exit(void) { #ifdef CONFIG_MODULES cancel_work_sync(&autoload_work); #endif - remove_drivers(); #ifdef CONFIG_PROC_FS snd_info_free_entry(info_entry); #endif - if (num_ops) - pr_err("ALSA: seq: drivers not released (%d)\n", num_ops); + bus_unregister(&snd_seq_bus_type); } module_init(alsa_seq_device_init) -- GitLab From af03c243a1f014145dae34368fe975b2f08ed964 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 13:40:50 +0100 Subject: [PATCH 0008/1910] ALSA: seq: Clean up device and driver structs Use const string pointer instead of copying the id string to each object. Also drop the status and list fields of snd_seq_device struct that are no longer used. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 18 ++++++------------ sound/core/seq/seq_device.c | 31 ++++++++++--------------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index ea256b825146..b13cd2930d32 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -25,24 +25,16 @@ * registered device information */ -#define ID_LEN 32 - -/* status flag */ -#define SNDRV_SEQ_DEVICE_FREE 0 -#define SNDRV_SEQ_DEVICE_REGISTERED 1 - struct snd_seq_device { /* device info */ struct snd_card *card; /* sound card */ int device; /* device number */ - char id[ID_LEN]; /* driver id */ + const char *id; /* driver id */ char name[80]; /* device name */ int argsize; /* size of the argument */ void *driver_data; /* private data for driver */ - int status; /* flag - read only */ void *private_data; /* private data for the caller */ void (*private_free)(struct snd_seq_device *device); - struct list_head list; /* link to next device */ struct device dev; }; @@ -75,9 +67,11 @@ void snd_seq_device_load_drivers(void); #else #define snd_seq_device_load_drivers() #endif -int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result); -int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize); -int snd_seq_device_unregister_driver(char *id); +int snd_seq_device_new(struct snd_card *card, int device, const char *id, + int argsize, struct snd_seq_device **result); +int snd_seq_device_register_driver(const char *id, + struct snd_seq_dev_ops *entry, int argsize); +int snd_seq_device_unregister_driver(const char *id); #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device)) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index d3320ffe43c2..49daf6e3a387 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL"); struct snd_seq_driver { struct device_driver driver; - char id[ID_LEN]; + const char *id; int argsize; struct snd_seq_dev_ops ops; }; @@ -215,8 +215,8 @@ static void snd_seq_dev_release(struct device *dev) * id = id of driver * result = return pointer (NULL allowed if unnecessary) */ -int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, - struct snd_seq_device **result) +int snd_seq_device_new(struct snd_card *card, int device, const char *id, + int argsize, struct snd_seq_device **result) { struct snd_seq_device *dev; int err; @@ -239,9 +239,8 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, /* set up device info */ dev->card = card; dev->device = device; - strlcpy(dev->id, id, sizeof(dev->id)); + dev->id = id; dev->argsize = argsize; - dev->status = SNDRV_SEQ_DEVICE_FREE; device_initialize(&dev->dev); dev->dev.parent = &card->card_dev; @@ -270,26 +269,16 @@ static int snd_seq_drv_probe(struct device *dev) { struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); struct snd_seq_device *sdev = to_seq_dev(dev); - int err; - err = sdrv->ops.init_device(sdev); - if (err < 0) - return err; - sdev->status = SNDRV_SEQ_DEVICE_REGISTERED; - return 0; + return sdrv->ops.init_device(sdev); } static int snd_seq_drv_remove(struct device *dev) { struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); struct snd_seq_device *sdev = to_seq_dev(dev); - int err; - err = sdrv->ops.free_device(sdev); - if (err < 0) - return err; - sdev->status = SNDRV_SEQ_DEVICE_FREE; - return 0; + return sdrv->ops.free_device(sdev); } /* @@ -297,8 +286,8 @@ static int snd_seq_drv_remove(struct device *dev) * id = driver id * entry = driver operators - duplicated to each instance */ -int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, - int argsize) +int snd_seq_device_register_driver(const char *id, + struct snd_seq_dev_ops *entry, int argsize) { struct snd_seq_driver *sdrv; int err; @@ -315,7 +304,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, sdrv->driver.bus = &snd_seq_bus_type; sdrv->driver.probe = snd_seq_drv_probe; sdrv->driver.remove = snd_seq_drv_remove; - strlcpy(sdrv->id, id, sizeof(sdrv->id)); + sdrv->id = id; sdrv->argsize = argsize; sdrv->ops = *entry; @@ -343,7 +332,7 @@ static int find_drv(struct device_driver *drv, void *data) /* * unregister the specified driver */ -int snd_seq_device_unregister_driver(char *id) +int snd_seq_device_unregister_driver(const char *id) { struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; -- GitLab From 056622053b8ae02978678ac1321b5bd956e7c812 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 13:43:22 +0100 Subject: [PATCH 0009/1910] ALSA: seq: Define driver object in each driver This patch moves the driver object initialization and allocation to each driver's module init/exit code like other normal drivers. The snd_seq_driver struct is now published in seq_device.h, and each driver is responsible to define it with proper driver attributes (name, probe and remove) with snd_seq_driver specific attributes as id and argsize fields. The helper functions snd_seq_driver_register(), snd_seq_driver_unregister() and module_snd_seq_driver() are used for simplifying codes. Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 27 ++++++--- sound/core/seq/oss/seq_oss.c | 20 ++++--- sound/core/seq/oss/seq_oss_synth.c | 6 +- sound/core/seq/oss/seq_oss_synth.h | 4 +- sound/core/seq/seq_device.c | 93 ++++-------------------------- sound/core/seq/seq_midi.c | 28 +++++---- sound/drivers/opl3/opl3_seq.c | 34 +++++------ sound/drivers/opl4/opl4_seq.c | 33 +++++------ sound/isa/sb/emu8000_synth.c | 35 +++++------ sound/pci/emu10k1/emu10k1_synth.c | 35 +++++------ 10 files changed, 124 insertions(+), 191 deletions(-) diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index b13cd2930d32..ddc0d504cf39 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -41,8 +41,10 @@ struct snd_seq_device { #define to_seq_dev(_dev) \ container_of(_dev, struct snd_seq_device, dev) +/* sequencer driver */ + /* driver operators - * init_device: + * probe: * Initialize the device with given parameters. * Typically, * 1. call snd_hwdep_new @@ -50,15 +52,19 @@ struct snd_seq_device { * 3. call snd_hwdep_register * 4. store the instance to dev->driver_data pointer. * - * free_device: + * remove: * Release the private data. * Typically, call snd_device_free(dev->card, dev->driver_data) */ -struct snd_seq_dev_ops { - int (*init_device)(struct snd_seq_device *dev); - int (*free_device)(struct snd_seq_device *dev); +struct snd_seq_driver { + struct device_driver driver; + char *id; + int argsize; }; +#define to_seq_drv(_drv) \ + container_of(_drv, struct snd_seq_driver, driver) + /* * prototypes */ @@ -69,12 +75,17 @@ void snd_seq_device_load_drivers(void); #endif int snd_seq_device_new(struct snd_card *card, int device, const char *id, int argsize, struct snd_seq_device **result); -int snd_seq_device_register_driver(const char *id, - struct snd_seq_dev_ops *entry, int argsize); -int snd_seq_device_unregister_driver(const char *id); #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device)) +int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv, + struct module *mod); +#define snd_seq_driver_register(drv) \ + __snd_seq_driver_register(drv, THIS_MODULE) +void snd_seq_driver_unregister(struct snd_seq_driver *drv); + +#define module_snd_seq_driver(drv) \ + module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister) /* * id strings for generic devices diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 16d42679e43f..ae1814aa767e 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -65,13 +65,19 @@ static unsigned int odev_poll(struct file *file, poll_table * wait); * module interface */ +static struct snd_seq_driver seq_oss_synth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_seq_oss_synth_probe, + .remove = snd_seq_oss_synth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OSS, + .argsize = sizeof(struct snd_seq_oss_reg), +}; + static int __init alsa_seq_oss_init(void) { int rc; - static struct snd_seq_dev_ops ops = { - snd_seq_oss_synth_register, - snd_seq_oss_synth_unregister, - }; snd_seq_autoload_lock(); if ((rc = register_device()) < 0) @@ -86,8 +92,8 @@ static int __init alsa_seq_oss_init(void) goto error; } - if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops, - sizeof(struct snd_seq_oss_reg))) < 0) { + rc = snd_seq_driver_register(&seq_oss_synth_driver); + if (rc < 0) { snd_seq_oss_delete_client(); unregister_proc(); unregister_device(); @@ -104,7 +110,7 @@ static int __init alsa_seq_oss_init(void) static void __exit alsa_seq_oss_exit(void) { - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS); + snd_seq_driver_unregister(&seq_oss_synth_driver); snd_seq_oss_delete_client(); unregister_proc(); unregister_device(); diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 701feb71b700..835edc80f918 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -98,8 +98,9 @@ snd_seq_oss_synth_init(void) * registration of the synth device */ int -snd_seq_oss_synth_register(struct snd_seq_device *dev) +snd_seq_oss_synth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); int i; struct seq_oss_synth *rec; struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -149,8 +150,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev) int -snd_seq_oss_synth_unregister(struct snd_seq_device *dev) +snd_seq_oss_synth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); int index; struct seq_oss_synth *rec = dev->driver_data; unsigned long flags; diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index dbdfcbb80eaa..74ac55f166b6 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -28,8 +28,8 @@ #include void snd_seq_oss_synth_init(void); -int snd_seq_oss_synth_register(struct snd_seq_device *dev); -int snd_seq_oss_synth_unregister(struct snd_seq_device *dev); +int snd_seq_oss_synth_probe(struct device *dev); +int snd_seq_oss_synth_remove(struct device *dev); void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 49daf6e3a387..48b20f009598 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -52,16 +52,6 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_LICENSE("GPL"); -struct snd_seq_driver { - struct device_driver driver; - const char *id; - int argsize; - struct snd_seq_dev_ops ops; -}; - -#define to_seq_drv(_drv) \ - container_of(_drv, struct snd_seq_driver, driver) - /* * bus definition */ @@ -263,86 +253,23 @@ int snd_seq_device_new(struct snd_card *card, int device, const char *id, EXPORT_SYMBOL(snd_seq_device_new); /* - * driver binding - just pass to each driver callback + * driver registration */ -static int snd_seq_drv_probe(struct device *dev) +int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod) { - struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); - struct snd_seq_device *sdev = to_seq_dev(dev); - - return sdrv->ops.init_device(sdev); -} - -static int snd_seq_drv_remove(struct device *dev) -{ - struct snd_seq_driver *sdrv = to_seq_drv(dev->driver); - struct snd_seq_device *sdev = to_seq_dev(dev); - - return sdrv->ops.free_device(sdev); -} - -/* - * register device driver - * id = driver id - * entry = driver operators - duplicated to each instance - */ -int snd_seq_device_register_driver(const char *id, - struct snd_seq_dev_ops *entry, int argsize) -{ - struct snd_seq_driver *sdrv; - int err; - - if (id == NULL || entry == NULL || - entry->init_device == NULL || entry->free_device == NULL) + if (WARN_ON(!drv->driver.name || !drv->id)) return -EINVAL; - - sdrv = kzalloc(sizeof(*sdrv), GFP_KERNEL); - if (!sdrv) - return -ENOMEM; - - sdrv->driver.name = id; - sdrv->driver.bus = &snd_seq_bus_type; - sdrv->driver.probe = snd_seq_drv_probe; - sdrv->driver.remove = snd_seq_drv_remove; - sdrv->id = id; - sdrv->argsize = argsize; - sdrv->ops = *entry; - - err = driver_register(&sdrv->driver); - if (err < 0) - kfree(sdrv); - return err; -} -EXPORT_SYMBOL(snd_seq_device_register_driver); - -/* callback to find a specific driver; data is a pointer to the id string ptr. - * when the id matches, store the driver pointer in return and break the loop. - */ -static int find_drv(struct device_driver *drv, void *data) -{ - struct snd_seq_driver *sdrv = to_seq_drv(drv); - void **ptr = (void **)data; - - if (strcmp(sdrv->id, *ptr)) - return 0; /* id don't match, continue the loop */ - *ptr = sdrv; - return 1; /* break the loop */ + drv->driver.bus = &snd_seq_bus_type; + drv->driver.owner = mod; + return driver_register(&drv->driver); } +EXPORT_SYMBOL_GPL(__snd_seq_driver_register); -/* - * unregister the specified driver - */ -int snd_seq_device_unregister_driver(const char *id) +void snd_seq_driver_unregister(struct snd_seq_driver *drv) { - struct snd_seq_driver *sdrv = (struct snd_seq_driver *)id; - - if (!bus_for_each_drv(&snd_seq_bus_type, NULL, &sdrv, find_drv)) - return -ENXIO; - driver_unregister(&sdrv->driver); - kfree(sdrv); - return 0; + driver_unregister(&drv->driver); } -EXPORT_SYMBOL(snd_seq_device_unregister_driver); +EXPORT_SYMBOL_GPL(snd_seq_driver_unregister); /* * module part diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 68fec776da26..79c73119cedc 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) /* register new midi synth port */ static int -snd_seq_midisynth_register_port(struct snd_seq_device *dev) +snd_seq_midisynth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct seq_midisynth_client *client; struct seq_midisynth *msynth, *ms; struct snd_seq_port_info *port; @@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) /* release midi synth port */ static int -snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) +snd_seq_midisynth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct seq_midisynth_client *client; struct seq_midisynth *msynth; struct snd_card *card = dev->card; @@ -457,23 +459,29 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) return 0; } +static struct snd_seq_driver seq_midisynth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_seq_midisynth_probe, + .remove = snd_seq_midisynth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_MIDISYNTH, + .argsize = 0, +}; static int __init alsa_seq_midi_init(void) { - static struct snd_seq_dev_ops ops = { - snd_seq_midisynth_register_port, - snd_seq_midisynth_unregister_port, - }; - memset(&synths, 0, sizeof(synths)); + int err; + snd_seq_autoload_lock(); - snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0); + err = snd_seq_driver_register(&seq_midisynth_driver); snd_seq_autoload_unlock(); - return 0; + return err; } static void __exit alsa_seq_midi_exit(void) { - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH); + snd_seq_driver_unregister(&seq_midisynth_driver); } module_init(alsa_seq_midi_init) diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index a9f618e06a22..fdae5d7f421f 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) /* ------------------------------ */ -static int snd_opl3_seq_new_device(struct snd_seq_device *dev) +static int snd_opl3_seq_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl3 *opl3; int client, err; char name[32]; @@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) return 0; } -static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) +static int snd_opl3_seq_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl3 *opl3; opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) return 0; } -static int __init alsa_opl3_seq_init(void) -{ - static struct snd_seq_dev_ops ops = - { - snd_opl3_seq_new_device, - snd_opl3_seq_delete_device - }; - - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops, - sizeof(struct snd_opl3 *)); -} - -static void __exit alsa_opl3_seq_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3); -} +static struct snd_seq_driver opl3_seq_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_opl3_seq_probe, + .remove = snd_opl3_seq_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OPL3, + .argsize = sizeof(struct snd_opl3 *), +}; -module_init(alsa_opl3_seq_init) -module_exit(alsa_opl3_seq_exit) +module_snd_seq_driver(opl3_seq_driver); diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c index 99197699c55a..03d6202f4829 100644 --- a/sound/drivers/opl4/opl4_seq.c +++ b/sound/drivers/opl4/opl4_seq.c @@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data) snd_midi_channel_free_set(opl4->chset); } -static int snd_opl4_seq_new_device(struct snd_seq_device *dev) +static int snd_opl4_seq_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl4 *opl4; int client; struct snd_seq_port_callback pcallbacks; @@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev) return 0; } -static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) +static int snd_opl4_seq_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_opl4 *opl4; opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); @@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) return 0; } -static int __init alsa_opl4_synth_init(void) -{ - static struct snd_seq_dev_ops ops = { - snd_opl4_seq_new_device, - snd_opl4_seq_delete_device - }; - - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops, - sizeof(struct snd_opl4 *)); -} - -static void __exit alsa_opl4_synth_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4); -} +static struct snd_seq_driver opl4_seq_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_opl4_seq_probe, + .remove = snd_opl4_seq_remove, + }, + .id = SNDRV_SEQ_DEV_ID_OPL4, + .argsize = sizeof(struct snd_opl4 *), +}; -module_init(alsa_opl4_synth_init) -module_exit(alsa_opl4_synth_exit) +module_snd_seq_driver(opl4_seq_driver); diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 72332dfada9a..4aa719cad331 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -34,8 +34,9 @@ MODULE_LICENSE("GPL"); /* * create a new hardware dependent device for Emu8000 */ -static int snd_emu8000_new_device(struct snd_seq_device *dev) +static int snd_emu8000_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emu8000 *hw; struct snd_emux *emu; @@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev) /* * free all resources */ -static int snd_emu8000_delete_device(struct snd_seq_device *dev) +static int snd_emu8000_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emu8000 *hw; if (dev->driver_data == NULL) @@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) * INIT part */ -static int __init alsa_emu8000_init(void) -{ - - static struct snd_seq_dev_ops ops = { - snd_emu8000_new_device, - snd_emu8000_delete_device, - }; - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops, - sizeof(struct snd_emu8000*)); -} - -static void __exit alsa_emu8000_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000); -} - -module_init(alsa_emu8000_init) -module_exit(alsa_emu8000_exit) +static struct snd_seq_driver emu8000_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_emu8000_probe, + .remove = snd_emu8000_remove, + }, + .id = SNDRV_SEQ_DEV_ID_EMU8000, + .argsize = sizeof(struct snd_emu8000 *), +}; + +module_snd_seq_driver(emu8000_driver); diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 4c41c903a840..5457d5613f6b 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -29,8 +29,9 @@ MODULE_LICENSE("GPL"); /* * create a new hardware dependent device for Emu10k1 */ -static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) +static int snd_emu10k1_synth_probe(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; struct snd_emu10k1_synth_arg *arg; @@ -79,8 +80,9 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) return 0; } -static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) +static int snd_emu10k1_synth_remove(struct device *_dev) { + struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; unsigned long flags; @@ -104,21 +106,14 @@ static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) * INIT part */ -static int __init alsa_emu10k1_synth_init(void) -{ - - static struct snd_seq_dev_ops ops = { - snd_emu10k1_synth_new_device, - snd_emu10k1_synth_delete_device, - }; - return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops, - sizeof(struct snd_emu10k1_synth_arg)); -} - -static void __exit alsa_emu10k1_synth_exit(void) -{ - snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH); -} - -module_init(alsa_emu10k1_synth_init) -module_exit(alsa_emu10k1_synth_exit) +static struct snd_seq_driver emu10k1_synth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_emu10k1_synth_probe, + .remove = snd_emu10k1_synth_remove, + }, + .id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, + .argsize = sizeof(struct snd_emu10k1_synth_arg), +}; + +module_snd_seq_driver(emu10k1_synth_driver); -- GitLab From 54a721abd7953a58e5479065c0cfdd8679d785c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Feb 2015 14:20:24 +0100 Subject: [PATCH 0010/1910] ALSA: seq: Drop snd_seq_autoload_lock() and _unlock() The autoload lock became already superfluous due to the recent rework of autoload code. Let's drop them now. This allows us to simplify a few codes nicely. Signed-off-by: Takashi Iwai --- include/sound/seq_kernel.h | 6 +----- sound/core/seq/oss/seq_oss.c | 2 -- sound/core/seq/seq_device.c | 19 +++++++------------ sound/core/seq/seq_dummy.c | 6 +----- sound/core/seq/seq_midi.c | 18 +----------------- 5 files changed, 10 insertions(+), 41 deletions(-) diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index 18a2ac58b88f..feb58d455560 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h @@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, int snd_seq_event_port_detach(int client, int port); #ifdef CONFIG_MODULES -void snd_seq_autoload_lock(void); -void snd_seq_autoload_unlock(void); void snd_seq_autoload_init(void); -#define snd_seq_autoload_exit() snd_seq_autoload_lock() +void snd_seq_autoload_exit(void); #else -#define snd_seq_autoload_lock() -#define snd_seq_autoload_unlock() #define snd_seq_autoload_init() #define snd_seq_autoload_exit() #endif diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index ae1814aa767e..72873a46afeb 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -79,7 +79,6 @@ static int __init alsa_seq_oss_init(void) { int rc; - snd_seq_autoload_lock(); if ((rc = register_device()) < 0) goto error; if ((rc = register_proc()) < 0) { @@ -104,7 +103,6 @@ static int __init alsa_seq_oss_init(void) snd_seq_oss_synth_init(); error: - snd_seq_autoload_unlock(); return rc; } diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 48b20f009598..355b34269bd1 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -98,19 +98,8 @@ static void snd_seq_device_info(struct snd_info_entry *entry, */ #ifdef CONFIG_MODULES -/* avoid auto-loading during module_init() */ +/* flag to block auto-loading */ static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ -void snd_seq_autoload_lock(void) -{ - atomic_inc(&snd_seq_in_init); -} -EXPORT_SYMBOL(snd_seq_autoload_lock); - -void snd_seq_autoload_unlock(void) -{ - atomic_dec(&snd_seq_in_init); -} -EXPORT_SYMBOL(snd_seq_autoload_unlock); static int request_seq_drv(struct device *dev, void *data) { @@ -147,6 +136,12 @@ void snd_seq_autoload_init(void) } EXPORT_SYMBOL(snd_seq_autoload_init); +void snd_seq_autoload_exit(void) +{ + atomic_inc(&snd_seq_in_init); +} +EXPORT_SYMBOL(snd_seq_autoload_exit); + void snd_seq_device_load_drivers(void) { queue_autoload_drivers(); diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 5d905d90d504..d3a2ec4f0561 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -214,11 +214,7 @@ delete_client(void) static int __init alsa_seq_dummy_init(void) { - int err; - snd_seq_autoload_lock(); - err = register_client(); - snd_seq_autoload_unlock(); - return err; + return register_client(); } static void __exit alsa_seq_dummy_exit(void) diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 79c73119cedc..5dd0ee258359 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -469,20 +469,4 @@ static struct snd_seq_driver seq_midisynth_driver = { .argsize = 0, }; -static int __init alsa_seq_midi_init(void) -{ - int err; - - snd_seq_autoload_lock(); - err = snd_seq_driver_register(&seq_midisynth_driver); - snd_seq_autoload_unlock(); - return err; -} - -static void __exit alsa_seq_midi_exit(void) -{ - snd_seq_driver_unregister(&seq_midisynth_driver); -} - -module_init(alsa_seq_midi_init) -module_exit(alsa_seq_midi_exit) +module_snd_seq_driver(seq_midisynth_driver); -- GitLab From 226e2f1b0bb4a5f724dd119c1eeb8b8e89e87fab Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Feb 2015 16:41:26 +0200 Subject: [PATCH 0011/1910] ASoC: davinci-mcasp: Add support for CBS_CFM mode Support for setups where codec is bitclock slave and frame master. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index de3b155a5011..031c1fb44ae7 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -441,6 +441,18 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); mcasp->bclk_master = 1; break; + case SND_SOC_DAIFMT_CBS_CFM: + /* codec is clock slave and frame master */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE); + + mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); + mcasp->bclk_master = 1; + break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); -- GitLab From 38ebb7034970efe5c7419267e499295e5893b565 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Feb 2015 14:45:33 +0100 Subject: [PATCH 0012/1910] ALSA: Consolidate snd_find_free_minor() A really small cleanup to consolidate snd_find_free_minor() and snd_kernel_minor() so that we can get rid of one more ifdef. Signed-off-by: Takashi Iwai --- sound/core/sound.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/core/sound.c b/sound/core/sound.c index 185cec01ee25..5fc93d00572a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -186,7 +186,7 @@ static const struct file_operations snd_fops = }; #ifdef CONFIG_SND_DYNAMIC_MINORS -static int snd_find_free_minor(int type) +static int snd_find_free_minor(int type, struct snd_card *card, int dev) { int minor; @@ -209,7 +209,7 @@ static int snd_find_free_minor(int type) return -EBUSY; } #else -static int snd_kernel_minor(int type, struct snd_card *card, int dev) +static int snd_find_free_minor(int type, struct snd_card *card, int dev) { int minor; @@ -237,6 +237,8 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) } if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) return -EINVAL; + if (snd_minors[minor]) + return -EBUSY; return minor; } #endif @@ -276,13 +278,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, preg->private_data = private_data; preg->card_ptr = card; mutex_lock(&sound_mutex); -#ifdef CONFIG_SND_DYNAMIC_MINORS - minor = snd_find_free_minor(type); -#else - minor = snd_kernel_minor(type, card, dev); - if (minor >= 0 && snd_minors[minor]) - minor = -EBUSY; -#endif + minor = snd_find_free_minor(type, card, dev); if (minor < 0) { err = minor; goto error; -- GitLab From 5ecc5dc720307d3fb0167e2b14f50e97dd9a2233 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Tue, 17 Feb 2015 00:05:04 +0100 Subject: [PATCH 0013/1910] ALSA: hdspm - DRY cleanup in .open callbacks This commit removes code duplication between snd_hdspm_{capture,playback}_open. No semantic changes intended, this is purely cosmetic. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 100 +++++++++----------------------------- 1 file changed, 24 insertions(+), 76 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index ca67f896d117..51e984170b3d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6043,23 +6043,30 @@ hdspm_hw_constraints_aes32_sample_rates = { .mask = 0 }; -static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) +static int snd_hdspm_open(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); spin_lock_irq(&hdspm->lock); - snd_pcm_set_sync(substream); + runtime->hw = (playback) ? snd_hdspm_playback_subinfo : + snd_hdspm_capture_subinfo; + if (playback) { + if (hdspm->capture_substream == NULL) + hdspm_stop_audio(hdspm); - runtime->hw = snd_hdspm_playback_subinfo; - - if (hdspm->capture_substream == NULL) - hdspm_stop_audio(hdspm); + hdspm->playback_pid = current->pid; + hdspm->playback_substream = substream; + } else { + if (hdspm->playback_substream == NULL) + hdspm_stop_audio(hdspm); - hdspm->playback_pid = current->pid; - hdspm->playback_substream = substream; + hdspm->capture_pid = current->pid; + hdspm->capture_substream = substream; + } spin_unlock_irq(&hdspm->lock); @@ -6094,16 +6101,20 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream) &hdspm_hw_constraints_aes32_sample_rates); } else { snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdspm_hw_rule_rate_out_channels, hdspm, + (playback ? + snd_hdspm_hw_rule_rate_out_channels : + snd_hdspm_hw_rule_rate_in_channels), hdspm, SNDRV_PCM_HW_PARAM_CHANNELS, -1); } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_out_channels, hdspm, + (playback ? snd_hdspm_hw_rule_out_channels : + snd_hdspm_hw_rule_in_channels), hdspm, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_out_channels_rate, hdspm, + (playback ? snd_hdspm_hw_rule_out_channels_rate : + snd_hdspm_hw_rule_in_channels_rate), hdspm, SNDRV_PCM_HW_PARAM_RATE, -1); return 0; @@ -6123,69 +6134,6 @@ static int snd_hdspm_playback_release(struct snd_pcm_substream *substream) return 0; } - -static int snd_hdspm_capture_open(struct snd_pcm_substream *substream) -{ - struct hdspm *hdspm = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - spin_lock_irq(&hdspm->lock); - snd_pcm_set_sync(substream); - runtime->hw = snd_hdspm_capture_subinfo; - - if (hdspm->playback_substream == NULL) - hdspm_stop_audio(hdspm); - - hdspm->capture_pid = current->pid; - hdspm->capture_substream = substream; - - spin_unlock_irq(&hdspm->lock); - - snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); - - switch (hdspm->io_type) { - case AIO: - case RayDAT: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 32, 4096); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - 16384, 16384); - break; - - default: - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - 64, 8192); - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIODS, - 2, 2); - break; - } - - if (AES32 == hdspm->io_type) { - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hdspm_hw_constraints_aes32_sample_rates); - } else { - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdspm_hw_rule_rate_in_channels, hdspm, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - } - - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_in_channels, hdspm, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdspm_hw_rule_in_channels_rate, hdspm, - SNDRV_PCM_HW_PARAM_RATE, -1); - - return 0; -} - static int snd_hdspm_capture_release(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); @@ -6414,7 +6362,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, } static struct snd_pcm_ops snd_hdspm_playback_ops = { - .open = snd_hdspm_playback_open, + .open = snd_hdspm_open, .close = snd_hdspm_playback_release, .ioctl = snd_hdspm_ioctl, .hw_params = snd_hdspm_hw_params, @@ -6426,7 +6374,7 @@ static struct snd_pcm_ops snd_hdspm_playback_ops = { }; static struct snd_pcm_ops snd_hdspm_capture_ops = { - .open = snd_hdspm_capture_open, + .open = snd_hdspm_open, .close = snd_hdspm_capture_release, .ioctl = snd_hdspm_ioctl, .hw_params = snd_hdspm_hw_params, -- GitLab From 8b73b867294364ae3007affdf8cfd28f022b158c Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Tue, 17 Feb 2015 00:05:05 +0100 Subject: [PATCH 0014/1910] ALSA: hdspm - DRY cleanup in .release callback This commit removes code duplication between snd_hdspm_{capture,playback}_release. No semantic changes intended, this is purely cosmetic. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 51e984170b3d..4e1cfb91a8d8 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6120,33 +6120,26 @@ static int snd_hdspm_open(struct snd_pcm_substream *substream) return 0; } -static int snd_hdspm_playback_release(struct snd_pcm_substream *substream) +static int snd_hdspm_release(struct snd_pcm_substream *substream) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); spin_lock_irq(&hdspm->lock); - hdspm->playback_pid = -1; - hdspm->playback_substream = NULL; + if (playback) { + hdspm->playback_pid = -1; + hdspm->playback_substream = NULL; + } else { + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; + } spin_unlock_irq(&hdspm->lock); return 0; } -static int snd_hdspm_capture_release(struct snd_pcm_substream *substream) -{ - struct hdspm *hdspm = snd_pcm_substream_chip(substream); - - spin_lock_irq(&hdspm->lock); - - hdspm->capture_pid = -1; - hdspm->capture_substream = NULL; - - spin_unlock_irq(&hdspm->lock); - return 0; -} - static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file) { /* we have nothing to initialize but the call is required */ @@ -6363,7 +6356,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, static struct snd_pcm_ops snd_hdspm_playback_ops = { .open = snd_hdspm_open, - .close = snd_hdspm_playback_release, + .close = snd_hdspm_release, .ioctl = snd_hdspm_ioctl, .hw_params = snd_hdspm_hw_params, .hw_free = snd_hdspm_hw_free, @@ -6375,7 +6368,7 @@ static struct snd_pcm_ops snd_hdspm_playback_ops = { static struct snd_pcm_ops snd_hdspm_capture_ops = { .open = snd_hdspm_open, - .close = snd_hdspm_capture_release, + .close = snd_hdspm_release, .ioctl = snd_hdspm_ioctl, .hw_params = snd_hdspm_hw_params, .hw_free = snd_hdspm_hw_free, -- GitLab From 0c8d948565490d2a2db9d9a5aec388342c7d38ce Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Tue, 17 Feb 2015 00:05:06 +0100 Subject: [PATCH 0015/1910] ALSA: hdspm - DRY cleanup of snd_pcm_ops This commit removes code duplication between snd_hdspm_{capture,playback}_ops. No semantic changes intended, this is purely cosmetic. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 4e1cfb91a8d8..cb666c73712d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6354,19 +6354,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, return 0; } -static struct snd_pcm_ops snd_hdspm_playback_ops = { - .open = snd_hdspm_open, - .close = snd_hdspm_release, - .ioctl = snd_hdspm_ioctl, - .hw_params = snd_hdspm_hw_params, - .hw_free = snd_hdspm_hw_free, - .prepare = snd_hdspm_prepare, - .trigger = snd_hdspm_trigger, - .pointer = snd_hdspm_hw_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static struct snd_pcm_ops snd_hdspm_capture_ops = { +static struct snd_pcm_ops snd_hdspm_ops = { .open = snd_hdspm_open, .close = snd_hdspm_release, .ioctl = snd_hdspm_ioctl, @@ -6462,9 +6450,9 @@ static int snd_hdspm_create_pcm(struct snd_card *card, strcpy(pcm->name, hdspm->card_name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_hdspm_playback_ops); + &snd_hdspm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_hdspm_capture_ops); + &snd_hdspm_ops); pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; -- GitLab From 76a3aeac2f6c02ecf065fa9baa279dd54bf2d819 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:27 +0100 Subject: [PATCH 0016/1910] hdspm.h: include stdint.h in userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compilation error: sound/hdspm.h:43:2: error: unknown type name ‘uint32_t’ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/hdspm.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h index b357f1a5e29c..5737332d38f2 100644 --- a/include/uapi/sound/hdspm.h +++ b/include/uapi/sound/hdspm.h @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef __KERNEL__ +#include +#else +#include +#endif + /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ #define HDSPM_MAX_CHANNELS 64 -- GitLab From 4bebf7091aa15ec60edf0dcbc654410a87ca21fe Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:38 +0100 Subject: [PATCH 0017/1910] include/uapi/sound/asound.h: include stdlib.h in userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes compiler errors like: error: field ‘trigger_tstamp’ has incomplete type error: invalid application of ‘sizeof’ to incomplete t ype ‘struct timespec’ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1f23cd635957..1fe3f4f3d696 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -25,6 +25,9 @@ #include +#ifndef __KERNEL__ +#include +#endif /* * protocol version -- GitLab From bbf91c1c5bfc00c2961f15657359ee7e87de4269 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:42 +0100 Subject: [PATCH 0018/1910] include/uapi/sound/asequencer.h: include sound/asound.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes userspace compilation error: error: unknown type name ‘snd_seq_client_type_t’ snd_seq_client_type_t type; /* client type */ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 09c8a00ea503..5a5fa4956ebd 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -22,6 +22,7 @@ #ifndef _UAPI__SOUND_ASEQUENCER_H #define _UAPI__SOUND_ASEQUENCER_H +#include /** version of the sequencer */ #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1) -- GitLab From b9956409c281931c74ba8d0a2b61a98076a58602 Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Tue, 17 Feb 2015 00:05:43 +0100 Subject: [PATCH 0019/1910] include/uapi/sound/emu10k1.h: include sound/asound.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes userspace compilation errors like: error: field ‘id’ has incomplete type struct snd_ctl_elem_id id; /* full control ID definition */ Signed-off-by: Mikko Rapeli Signed-off-by: Takashi Iwai --- include/uapi/sound/emu10k1.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index d1bbaf78457a..ec1535bb6aed 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -23,8 +23,7 @@ #define _UAPI__SOUND_EMU10K1_H #include - - +#include /* * ---- FX8010 ---- -- GitLab From ef7449780ebb596b47d5019eb7ba7878c30a3404 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Feb 2015 13:56:29 +0100 Subject: [PATCH 0020/1910] ALSA: hda - Drop hda_bus_template for snd_hda_bus_new() Instead of copying from the given template, let the caller fills the fields after creation. This simplifies the code after all. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 15 +--------- sound/pci/hda/hda_codec.h | 13 +------- sound/pci/hda/hda_controller.c | 54 +++++++++++++++++++--------------- 3 files changed, 32 insertions(+), 50 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2fe86d2e1b09..215bf048c668 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -861,14 +861,12 @@ static int snd_hda_bus_dev_disconnect(struct snd_device *device) /** * snd_hda_bus_new - create a HDA bus * @card: the card entry - * @temp: the template for hda_bus information * @busp: the pointer to store the created bus instance * * Returns 0 if successful, or a negative error code. */ int snd_hda_bus_new(struct snd_card *card, - const struct hda_bus_template *temp, - struct hda_bus **busp) + struct hda_bus **busp) { struct hda_bus *bus; int err; @@ -877,11 +875,6 @@ int snd_hda_bus_new(struct snd_card *card, .dev_free = snd_hda_bus_dev_free, }; - if (snd_BUG_ON(!temp)) - return -EINVAL; - if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response)) - return -EINVAL; - if (busp) *busp = NULL; @@ -892,12 +885,6 @@ int snd_hda_bus_new(struct snd_card *card, } bus->card = card; - bus->private_data = temp->private_data; - bus->pci = temp->pci; - bus->modelname = temp->modelname; - bus->power_save = temp->power_save; - bus->ops = temp->ops; - mutex_init(&bus->cmd_mutex); mutex_init(&bus->prepare_mutex); INIT_LIST_HEAD(&bus->codec_list); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9c8820f21f94..5a6594884069 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -101,15 +101,6 @@ struct hda_bus_ops { #endif }; -/* template to pass to the bus constructor */ -struct hda_bus_template { - void *private_data; - struct pci_dev *pci; - const char *modelname; - int *power_save; - struct hda_bus_ops ops; -}; - /* * codec bus * @@ -119,7 +110,6 @@ struct hda_bus_template { struct hda_bus { struct snd_card *card; - /* copied from template */ void *private_data; struct pci_dev *pci; const char *modelname; @@ -420,8 +410,7 @@ enum { /* * constructors */ -int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, - struct hda_bus **busp); +int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp); int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp); int snd_hda_codec_configure(struct hda_codec *codec); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index dfcb5e929f9f..31ff8b55f386 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1815,39 +1815,45 @@ static int get_jackpoll_interval(struct azx *chip) return j; } +static struct hda_bus_ops bus_ops = { + .command = azx_send_cmd, + .get_response = azx_get_response, + .attach_pcm = azx_attach_pcm_stream, + .bus_reset = azx_bus_reset, +#ifdef CONFIG_PM + .pm_notify = azx_power_notify, +#endif +#ifdef CONFIG_SND_HDA_DSP_LOADER + .load_dsp_prepare = azx_load_dsp_prepare, + .load_dsp_trigger = azx_load_dsp_trigger, + .load_dsp_cleanup = azx_load_dsp_cleanup, +#endif +}; + /* Codec initialization */ int azx_codec_create(struct azx *chip, const char *model, unsigned int max_slots, int *power_save_to) { - struct hda_bus_template bus_temp; + struct hda_bus *bus; int c, codecs, err; - memset(&bus_temp, 0, sizeof(bus_temp)); - bus_temp.private_data = chip; - bus_temp.modelname = model; - bus_temp.pci = chip->pci; - bus_temp.ops.command = azx_send_cmd; - bus_temp.ops.get_response = azx_get_response; - bus_temp.ops.attach_pcm = azx_attach_pcm_stream; - bus_temp.ops.bus_reset = azx_bus_reset; -#ifdef CONFIG_PM - bus_temp.power_save = power_save_to; - bus_temp.ops.pm_notify = azx_power_notify; -#endif -#ifdef CONFIG_SND_HDA_DSP_LOADER - bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare; - bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger; - bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup; -#endif - - err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); + err = snd_hda_bus_new(chip->card, &bus); if (err < 0) return err; + chip->bus = bus; + bus->private_data = chip; + bus->pci = chip->pci; + bus->modelname = model; + bus->ops = bus_ops; +#ifdef CONFIG_PM + bus->power_save = power_save_to; +#endif + if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); - chip->bus->needs_damn_long_delay = 1; + bus->needs_damn_long_delay = 1; } codecs = 0; @@ -1883,15 +1889,15 @@ int azx_codec_create(struct azx *chip, const char *model, */ if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n"); - chip->bus->sync_write = 1; - chip->bus->allow_bus_reset = 1; + bus->sync_write = 1; + bus->allow_bus_reset = 1; } /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(chip->bus, c, &codec); + err = snd_hda_codec_new(bus, c, &codec); if (err < 0) continue; codec->jackpoll_interval = get_jackpoll_interval(chip); -- GitLab From 922c88a8368a61ee93653d4a2888a7f4ce263102 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Feb 2015 14:46:40 +0100 Subject: [PATCH 0021/1910] ALSA: hda - Embed struct hda_bus_unsolicited into struct hda_bus There is no big merit to handle hda_bus_unsolicited object individually, as it's tightly coupled with the hda_bus object itself. Embedding it makes the code simpler in the end. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 39 ++++----------------------------------- sound/pci/hda/hda_codec.h | 13 +++++++++++-- sound/pci/hda/hda_local.h | 17 ----------------- 3 files changed, 15 insertions(+), 54 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 215bf048c668..0734cb35887d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -762,10 +762,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; trace_hda_unsol_event(bus, res, res_ex); - unsol = bus->unsol; - if (!unsol) - return 0; - + unsol = &bus->unsol; wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE; unsol->wp = wp; @@ -784,9 +781,8 @@ EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); */ static void process_unsol_events(struct work_struct *work) { - struct hda_bus_unsolicited *unsol = - container_of(work, struct hda_bus_unsolicited, work); - struct hda_bus *bus = unsol->bus; + struct hda_bus *bus = container_of(work, struct hda_bus, unsol.work); + struct hda_bus_unsolicited *unsol = &bus->unsol; struct hda_codec *codec; unsigned int rp, caddr, res; @@ -804,27 +800,6 @@ static void process_unsol_events(struct work_struct *work) } } -/* - * initialize unsolicited queue - */ -static int init_unsol_queue(struct hda_bus *bus) -{ - struct hda_bus_unsolicited *unsol; - - if (bus->unsol) /* already initialized */ - return 0; - - unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); - if (!unsol) { - dev_err(bus->card->dev, "can't allocate unsolicited queue\n"); - return -ENOMEM; - } - INIT_WORK(&unsol->work, process_unsol_events); - unsol->bus = bus; - bus->unsol = unsol; - return 0; -} - /* * destructor */ @@ -836,7 +811,6 @@ static void snd_hda_bus_free(struct hda_bus *bus) WARN_ON(!list_empty(&bus->codec_list)); if (bus->workq) flush_workqueue(bus->workq); - kfree(bus->unsol); if (bus->ops.private_free) bus->ops.private_free(bus); if (bus->workq) @@ -888,6 +862,7 @@ int snd_hda_bus_new(struct snd_card *card, mutex_init(&bus->cmd_mutex); mutex_init(&bus->prepare_mutex); INIT_LIST_HEAD(&bus->codec_list); + INIT_WORK(&bus->unsol.work, process_unsol_events); snprintf(bus->workq_name, sizeof(bus->workq_name), "hd-audio%d", card->number); @@ -1689,12 +1664,6 @@ int snd_hda_codec_configure(struct hda_codec *codec) return err; } - if (codec->patch_ops.unsol_event) { - err = init_unsol_queue(codec->bus); - if (err < 0) - return err; - } - /* audio codec should override the mixer name */ if (codec->afg || !*codec->bus->card->mixername) snprintf(codec->bus->card->mixername, diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5a6594884069..96421a3b32cd 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -66,7 +66,6 @@ struct hda_beep; struct hda_codec; struct hda_pcm; struct hda_pcm_stream; -struct hda_bus_unsolicited; /* NID type */ typedef u16 hda_nid_t; @@ -101,6 +100,16 @@ struct hda_bus_ops { #endif }; +/* unsolicited event handler */ +#define HDA_UNSOL_QUEUE_SIZE 64 +struct hda_bus_unsolicited { + /* ring buffer */ + u32 queue[HDA_UNSOL_QUEUE_SIZE * 2]; + unsigned int rp, wp; + /* workqueue */ + struct work_struct work; +}; + /* * codec bus * @@ -126,7 +135,7 @@ struct hda_bus { struct mutex prepare_mutex; /* unsolicited event queue */ - struct hda_bus_unsolicited *unsol; + struct hda_bus_unsolicited unsol; char workq_name[16]; struct workqueue_struct *workq; /* common workqueue for codecs */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 62658f2f8c9f..49c08a7278c4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -466,23 +466,6 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, const struct hda_fixup *fixlist); - -/* - * unsolicited event handler - */ - -#define HDA_UNSOL_QUEUE_SIZE 64 - -struct hda_bus_unsolicited { - /* ring buffer */ - u32 queue[HDA_UNSOL_QUEUE_SIZE * 2]; - unsigned int rp, wp; - - /* workqueue */ - struct work_struct work; - struct hda_bus *bus; -}; - /* helper macros to retrieve pin default-config values */ #define get_defcfg_connect(cfg) \ ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -- GitLab From 364aa716f43c991052cbb4fa05e3754bacccb95c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 16:51:17 +0100 Subject: [PATCH 0022/1910] ALSA: hda - Introduce azx_has_pm_runtime() macro For making the debugging of runtime PM easier, introduce azx_has_pm_runtime() and use it in all places checking the runtime pm driver capability. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 4 ++-- sound/pci/hda/hda_intel.c | 12 +++++------- sound/pci/hda/hda_priv.h | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 31ff8b55f386..3589fc2165b0 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1681,7 +1681,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) int i; #ifdef CONFIG_PM - if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME) + if (azx_has_pm_runtime(chip)) if (!pm_runtime_active(chip->card->dev)) return IRQ_NONE; #endif @@ -1784,7 +1784,7 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up) { struct azx *chip = bus->private_data; - if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + if (!azx_has_pm_runtime(chip)) return; if (power_up) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 36d2f20db7a4..589883291f4e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -852,7 +852,7 @@ static int azx_runtime_suspend(struct device *dev) if (chip->disabled || hda->init_failed) return 0; - if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + if (!azx_has_pm_runtime(chip)) return 0; /* enable controller wake up event */ @@ -885,7 +885,7 @@ static int azx_runtime_resume(struct device *dev) if (chip->disabled || hda->init_failed) return 0; - if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + if (!azx_has_pm_runtime(chip)) return 0; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { @@ -928,8 +928,7 @@ static int azx_runtime_idle(struct device *dev) if (chip->disabled || hda->init_failed) return 0; - if (!power_save_controller || - !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + if (!power_save_controller || !azx_has_pm_runtime(chip)) return -EBUSY; return 0; @@ -1071,8 +1070,7 @@ static int azx_free(struct azx *chip) struct hda_intel *hda = container_of(chip, struct hda_intel, chip); int i; - if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) - && chip->running) + if (azx_has_pm_runtime(chip) && chip->running) pm_runtime_get_noresume(&pci->dev); azx_del_card_list(chip); @@ -1938,7 +1936,7 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); - if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo) + if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); out_free: diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index daf458299753..a7b4a25c571c 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -403,4 +403,7 @@ struct azx { #define azx_sd_readb(chip, dev, reg) \ ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) +#define azx_has_pm_runtime(chip) \ + (!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME)) + #endif /* __SOUND_HDA_PRIV_H */ -- GitLab From 89a93fea6182a71cedce9de1d901e4f379322cf3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 18:04:17 +0100 Subject: [PATCH 0023/1910] ALSA: hda - Fold hda_priv.h into hda_controller.h There is no big reason to keep them separately. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 1 - sound/pci/hda/hda_controller.h | 391 ++++++++++++++++++++++++++++++- sound/pci/hda/hda_i915.c | 2 +- sound/pci/hda/hda_intel.c | 1 - sound/pci/hda/hda_intel.h | 2 +- sound/pci/hda/hda_priv.h | 409 --------------------------------- sound/pci/hda/hda_tegra.c | 1 - 7 files changed, 392 insertions(+), 415 deletions(-) delete mode 100644 sound/pci/hda/hda_priv.h diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 3589fc2165b0..6b3254d479e1 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -30,7 +30,6 @@ #include #include #include -#include "hda_priv.h" #include "hda_controller.h" #define CREATE_TRACE_POINTS diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c90d10fd4d8f..bd50b49cdd0d 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -15,10 +15,399 @@ #ifndef __SOUND_HDA_CONTROLLER_H #define __SOUND_HDA_CONTROLLER_H +#include +#include #include +#include #include #include "hda_codec.h" -#include "hda_priv.h" + +/* + * registers + */ +#define AZX_REG_GCAP 0x00 +#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ +#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ +#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ +#define AZX_REG_VMIN 0x02 +#define AZX_REG_VMAJ 0x03 +#define AZX_REG_OUTPAY 0x04 +#define AZX_REG_INPAY 0x06 +#define AZX_REG_GCTL 0x08 +#define AZX_GCTL_RESET (1 << 0) /* controller reset */ +#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ +#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define AZX_REG_WAKEEN 0x0c +#define AZX_REG_STATESTS 0x0e +#define AZX_REG_GSTS 0x10 +#define AZX_GSTS_FSTS (1 << 1) /* flush status */ +#define AZX_REG_INTCTL 0x20 +#define AZX_REG_INTSTS 0x24 +#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ +#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ +#define AZX_REG_SSYNC 0x38 +#define AZX_REG_CORBLBASE 0x40 +#define AZX_REG_CORBUBASE 0x44 +#define AZX_REG_CORBWP 0x48 +#define AZX_REG_CORBRP 0x4a +#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ +#define AZX_REG_CORBCTL 0x4c +#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define AZX_REG_CORBSTS 0x4d +#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define AZX_REG_CORBSIZE 0x4e + +#define AZX_REG_RIRBLBASE 0x50 +#define AZX_REG_RIRBUBASE 0x54 +#define AZX_REG_RIRBWP 0x58 +#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define AZX_REG_RINTCNT 0x5a +#define AZX_REG_RIRBCTL 0x5c +#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define AZX_REG_RIRBSTS 0x5d +#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ +#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define AZX_REG_RIRBSIZE 0x5e + +#define AZX_REG_IC 0x60 +#define AZX_REG_IR 0x64 +#define AZX_REG_IRS 0x68 +#define AZX_IRS_VALID (1<<1) +#define AZX_IRS_BUSY (1<<0) + +#define AZX_REG_DPLBASE 0x70 +#define AZX_REG_DPUBASE 0x74 +#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ + +/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; + +/* stream register offsets from stream base */ +#define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_STS 0x03 +#define AZX_REG_SD_LPIB 0x04 +#define AZX_REG_SD_CBL 0x08 +#define AZX_REG_SD_LVI 0x0c +#define AZX_REG_SD_FIFOW 0x0e +#define AZX_REG_SD_FIFOSIZE 0x10 +#define AZX_REG_SD_FORMAT 0x12 +#define AZX_REG_SD_BDLPL 0x18 +#define AZX_REG_SD_BDLPU 0x1c + +/* PCI space */ +#define AZX_PCIREG_TCSEL 0x44 + +/* + * other constants + */ + +/* max number of fragments - we may use more if allocating more pages for BDL */ +#define BDL_SIZE 4096 +#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) +#define AZX_MAX_FRAG 32 +/* max buffer size - no h/w limit, you can increase as you like */ +#define AZX_MAX_BUF_SIZE (1024*1024*1024) + +/* RIRB int mask: overrun[2], response[0] */ +#define RIRB_INT_RESPONSE 0x01 +#define RIRB_INT_OVERRUN 0x04 +#define RIRB_INT_MASK 0x05 + +/* STATESTS int mask: S3,SD2,SD1,SD0 */ +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 +#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) + +/* SD_CTL bits */ +#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ +#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ +#define SD_CTL_STRIPE (3 << 16) /* stripe control */ +#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ +#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ +#define SD_CTL_STREAM_TAG_MASK (0xf << 20) +#define SD_CTL_STREAM_TAG_SHIFT 20 + +/* SD_CTL and SD_STS */ +#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ +#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SD_INT_COMPLETE 0x04 /* completion interrupt */ +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) + +/* SD_STS */ +#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ + +/* INTCTL and INTSTS */ +#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ + +/* below are so far hardcoded - should read registers in future */ +#define AZX_MAX_CORB_ENTRIES 256 +#define AZX_MAX_RIRB_ENTRIES 256 + +/* driver quirks (capabilities) */ +/* bits 0-7 are used for indicating driver type */ +#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ +#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ +#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ +#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ +#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ +#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ +#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ +#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ +#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ +#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ +#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */ +/* 22 unused */ +#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ +#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ +#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ +#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ +#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ +#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ +#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ + +enum { + AZX_SNOOP_TYPE_NONE, + AZX_SNOOP_TYPE_SCH, + AZX_SNOOP_TYPE_ATI, + AZX_SNOOP_TYPE_NVIDIA, +}; + +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + +struct azx_dev { + struct snd_dma_buffer bdl; /* BDL buffer */ + u32 *posbuf; /* position buffer pointer */ + + unsigned int bufsize; /* size of the play buffer in bytes */ + unsigned int period_bytes; /* size of the period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ + unsigned long start_wallclk; /* start + minimum wallclk */ + unsigned long period_wallclk; /* wallclk for period */ + + void __iomem *sd_addr; /* stream descriptor pointer */ + + u32 sd_int_sta_mask; /* stream int status mask */ + + /* pcm support */ + struct snd_pcm_substream *substream; /* assigned substream, + * set in PCM open + */ + unsigned int format_val; /* format value to be set in the + * controller and the codec + */ + unsigned char stream_tag; /* assigned stream */ + unsigned char index; /* stream index */ + int assigned_key; /* last device# key assigned to */ + + unsigned int opened:1; + unsigned int running:1; + unsigned int irq_pending:1; + unsigned int prepared:1; + unsigned int locked:1; + /* + * For VIA: + * A flag to ensure DMA position is 0 + * when link position is not greater than FIFO size + */ + unsigned int insufficient:1; + unsigned int wc_marked:1; + unsigned int no_period_wakeup:1; + + struct timecounter azx_tc; + struct cyclecounter azx_cc; + + int delay_negative_threshold; + +#ifdef CONFIG_SND_HDA_DSP_LOADER + /* Allows dsp load to have sole access to the playback stream. */ + struct mutex dsp_mutex; +#endif +}; + +/* CORB/RIRB */ +struct azx_rb { + u32 *buf; /* CORB/RIRB buffer + * Each CORB entry is 4byte, RIRB is 8byte + */ + dma_addr_t addr; /* physical address of CORB/RIRB buffer */ + /* for RIRB */ + unsigned short rp, wp; /* read/write pointers */ + int cmds[AZX_MAX_CODECS]; /* number of pending requests */ + u32 res[AZX_MAX_CODECS]; /* last read value */ +}; + +struct azx; + +/* Functions to read/write to hda registers. */ +struct hda_controller_ops { + /* Register Access */ + void (*reg_writel)(u32 value, u32 __iomem *addr); + u32 (*reg_readl)(u32 __iomem *addr); + void (*reg_writew)(u16 value, u16 __iomem *addr); + u16 (*reg_readw)(u16 __iomem *addr); + void (*reg_writeb)(u8 value, u8 __iomem *addr); + u8 (*reg_readb)(u8 __iomem *addr); + /* Disable msi if supported, PCI only */ + int (*disable_msi_reset_irq)(struct azx *); + /* Allocation ops */ + int (*dma_alloc_pages)(struct azx *chip, + int type, + size_t size, + struct snd_dma_buffer *buf); + void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf); + int (*substream_alloc_pages)(struct azx *chip, + struct snd_pcm_substream *substream, + size_t size); + int (*substream_free_pages)(struct azx *chip, + struct snd_pcm_substream *substream); + void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream, + struct vm_area_struct *area); + /* Check if current position is acceptable */ + int (*position_check)(struct azx *chip, struct azx_dev *azx_dev); +}; + +struct azx_pcm { + struct azx *chip; + struct snd_pcm *pcm; + struct hda_codec *codec; + struct hda_pcm_stream *hinfo[2]; + struct list_head list; +}; + +typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); +typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); + +struct azx { + struct snd_card *card; + struct pci_dev *pci; + int dev_index; + + /* chip type specific */ + int driver_type; + unsigned int driver_caps; + int playback_streams; + int playback_index_offset; + int capture_streams; + int capture_index_offset; + int num_streams; + const int *jackpoll_ms; /* per-card jack poll interval */ + + /* Register interaction. */ + const struct hda_controller_ops *ops; + + /* position adjustment callbacks */ + azx_get_pos_callback_t get_position[2]; + azx_get_delay_callback_t get_delay[2]; + + /* pci resources */ + unsigned long addr; + void __iomem *remap_addr; + int irq; + + /* locks */ + spinlock_t reg_lock; + struct mutex open_mutex; /* Prevents concurrent open/close operations */ + + /* streams (x num_streams) */ + struct azx_dev *azx_dev; + + /* PCM */ + struct list_head pcm_list; /* azx_pcm list */ + + /* HD codec */ + unsigned short codec_mask; + int codec_probe_mask; /* copied from probe_mask option */ + struct hda_bus *bus; + unsigned int beep_mode; + + /* CORB/RIRB */ + struct azx_rb corb; + struct azx_rb rirb; + + /* CORB/RIRB and position buffers */ + struct snd_dma_buffer rb; + struct snd_dma_buffer posbuf; + +#ifdef CONFIG_SND_HDA_PATCH_LOADER + const struct firmware *fw; +#endif + + /* flags */ + const int *bdl_pos_adj; + int poll_count; + unsigned int running:1; + unsigned int initialized:1; + unsigned int single_cmd:1; + unsigned int polling_mode:1; + unsigned int msi:1; + unsigned int probing:1; /* codec probing phase */ + unsigned int snoop:1; + unsigned int align_buffer_size:1; + unsigned int region_requested:1; + unsigned int disabled:1; /* disabled by VGA-switcher */ + + /* for debugging */ + unsigned int last_cmd[AZX_MAX_CODECS]; + + /* reboot notifier (for mysterious hangup problem at power-down) */ + struct notifier_block reboot_notifier; + +#ifdef CONFIG_SND_HDA_DSP_LOADER + struct azx_dev saved_azx_dev; +#endif +}; + +#ifdef CONFIG_X86 +#define azx_snoop(chip) ((chip)->snoop) +#else +#define azx_snoop(chip) true +#endif + +/* + * macros for easy use + */ + +#define azx_writel(chip, reg, value) \ + ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) +#define azx_readl(chip, reg) \ + ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) +#define azx_writew(chip, reg, value) \ + ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) +#define azx_readw(chip, reg) \ + ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) +#define azx_writeb(chip, reg, value) \ + ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) +#define azx_readb(chip, reg) \ + ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) + +#define azx_sd_writel(chip, dev, reg, value) \ + ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) +#define azx_sd_readl(chip, dev, reg) \ + ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) +#define azx_sd_writew(chip, dev, reg, value) \ + ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) +#define azx_sd_readw(chip, dev, reg) \ + ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) +#define azx_sd_writeb(chip, dev, reg, value) \ + ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) +#define azx_sd_readb(chip, dev, reg) \ + ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) + +#define azx_has_pm_runtime(chip) \ + (!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME)) /* PCM setup */ static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream) diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 714894527e06..52a85d87c23c 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_priv.h" +#include "hda_controller.h" #include "hda_intel.h" /* Intel HSW/BDW display HDA controller Extended Mode registers. diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 589883291f4e..ced44a75f8ea 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -62,7 +62,6 @@ #include #include "hda_codec.h" #include "hda_controller.h" -#include "hda_priv.h" #include "hda_intel.h" /* position fix mode */ diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 348611835476..d5231f7216a7 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -17,7 +17,7 @@ #define __SOUND_HDA_INTEL_H #include -#include "hda_priv.h" +#include "hda_controller.h" struct hda_intel { struct azx chip; diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h deleted file mode 100644 index a7b4a25c571c..000000000000 --- a/sound/pci/hda/hda_priv.h +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Common defines for the alsa driver code base for HD Audio. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __SOUND_HDA_PRIV_H -#define __SOUND_HDA_PRIV_H - -#include -#include -#include - -/* - * registers - */ -#define AZX_REG_GCAP 0x00 -#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */ -#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define AZX_GCAP_ISS (15 << 8) /* # of input streams */ -#define AZX_GCAP_OSS (15 << 12) /* # of output streams */ -#define AZX_REG_VMIN 0x02 -#define AZX_REG_VMAJ 0x03 -#define AZX_REG_OUTPAY 0x04 -#define AZX_REG_INPAY 0x06 -#define AZX_REG_GCTL 0x08 -#define AZX_GCTL_RESET (1 << 0) /* controller reset */ -#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */ -#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define AZX_REG_WAKEEN 0x0c -#define AZX_REG_STATESTS 0x0e -#define AZX_REG_GSTS 0x10 -#define AZX_GSTS_FSTS (1 << 1) /* flush status */ -#define AZX_REG_INTCTL 0x20 -#define AZX_REG_INTSTS 0x24 -#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */ -#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define AZX_REG_SSYNC 0x38 -#define AZX_REG_CORBLBASE 0x40 -#define AZX_REG_CORBUBASE 0x44 -#define AZX_REG_CORBWP 0x48 -#define AZX_REG_CORBRP 0x4a -#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */ -#define AZX_REG_CORBCTL 0x4c -#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define AZX_REG_CORBSTS 0x4d -#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define AZX_REG_CORBSIZE 0x4e - -#define AZX_REG_RIRBLBASE 0x50 -#define AZX_REG_RIRBUBASE 0x54 -#define AZX_REG_RIRBWP 0x58 -#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define AZX_REG_RINTCNT 0x5a -#define AZX_REG_RIRBCTL 0x5c -#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define AZX_REG_RIRBSTS 0x5d -#define AZX_RBSTS_IRQ (1 << 0) /* response irq */ -#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define AZX_REG_RIRBSIZE 0x5e - -#define AZX_REG_IC 0x60 -#define AZX_REG_IR 0x64 -#define AZX_REG_IRS 0x68 -#define AZX_IRS_VALID (1<<1) -#define AZX_IRS_BUSY (1<<0) - -#define AZX_REG_DPLBASE 0x70 -#define AZX_REG_DPUBASE 0x74 -#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */ - -/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ -enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; - -/* stream register offsets from stream base */ -#define AZX_REG_SD_CTL 0x00 -#define AZX_REG_SD_STS 0x03 -#define AZX_REG_SD_LPIB 0x04 -#define AZX_REG_SD_CBL 0x08 -#define AZX_REG_SD_LVI 0x0c -#define AZX_REG_SD_FIFOW 0x0e -#define AZX_REG_SD_FIFOSIZE 0x10 -#define AZX_REG_SD_FORMAT 0x12 -#define AZX_REG_SD_BDLPL 0x18 -#define AZX_REG_SD_BDLPU 0x1c - -/* PCI space */ -#define AZX_PCIREG_TCSEL 0x44 - -/* - * other constants - */ - -/* max number of fragments - we may use more if allocating more pages for BDL */ -#define BDL_SIZE 4096 -#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -#define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) - -/* RIRB int mask: overrun[2], response[0] */ -#define RIRB_INT_RESPONSE 0x01 -#define RIRB_INT_OVERRUN 0x04 -#define RIRB_INT_MASK 0x05 - -/* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 8 -#define AZX_DEFAULT_CODECS 4 -#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) - -/* SD_CTL bits */ -#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ -#define SD_CTL_STRIPE (3 << 16) /* stripe control */ -#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ -#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ -#define SD_CTL_STREAM_TAG_MASK (0xf << 20) -#define SD_CTL_STREAM_TAG_SHIFT 20 - -/* SD_CTL and SD_STS */ -#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ -#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ - SD_INT_COMPLETE) - -/* SD_STS */ -#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ - -/* INTCTL and INTSTS */ -#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ - -/* below are so far hardcoded - should read registers in future */ -#define AZX_MAX_CORB_ENTRIES 256 -#define AZX_MAX_RIRB_ENTRIES 256 - -/* driver quirks (capabilities) */ -/* bits 0-7 are used for indicating driver type */ -#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ -#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ -#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ -#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ -#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ -#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ -#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ -#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ -#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ -#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ -#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ -#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ -#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */ -/* 22 unused */ -#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ -#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ -#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ -#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ -#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ -#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ - -enum { - AZX_SNOOP_TYPE_NONE , - AZX_SNOOP_TYPE_SCH, - AZX_SNOOP_TYPE_ATI, - AZX_SNOOP_TYPE_NVIDIA, -}; - -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - -struct azx_dev { - struct snd_dma_buffer bdl; /* BDL buffer */ - u32 *posbuf; /* position buffer pointer */ - - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int period_bytes; /* size of the period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ - unsigned long start_wallclk; /* start + minimum wallclk */ - unsigned long period_wallclk; /* wallclk for period */ - - void __iomem *sd_addr; /* stream descriptor pointer */ - - u32 sd_int_sta_mask; /* stream int status mask */ - - /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, - * set in PCM open - */ - unsigned int format_val; /* format value to be set in the - * controller and the codec - */ - unsigned char stream_tag; /* assigned stream */ - unsigned char index; /* stream index */ - int assigned_key; /* last device# key assigned to */ - - unsigned int opened:1; - unsigned int running:1; - unsigned int irq_pending:1; - unsigned int prepared:1; - unsigned int locked:1; - /* - * For VIA: - * A flag to ensure DMA position is 0 - * when link position is not greater than FIFO size - */ - unsigned int insufficient:1; - unsigned int wc_marked:1; - unsigned int no_period_wakeup:1; - - struct timecounter azx_tc; - struct cyclecounter azx_cc; - - int delay_negative_threshold; - -#ifdef CONFIG_SND_HDA_DSP_LOADER - /* Allows dsp load to have sole access to the playback stream. */ - struct mutex dsp_mutex; -#endif -}; - -/* CORB/RIRB */ -struct azx_rb { - u32 *buf; /* CORB/RIRB buffer - * Each CORB entry is 4byte, RIRB is 8byte - */ - dma_addr_t addr; /* physical address of CORB/RIRB buffer */ - /* for RIRB */ - unsigned short rp, wp; /* read/write pointers */ - int cmds[AZX_MAX_CODECS]; /* number of pending requests */ - u32 res[AZX_MAX_CODECS]; /* last read value */ -}; - -struct azx; - -/* Functions to read/write to hda registers. */ -struct hda_controller_ops { - /* Register Access */ - void (*reg_writel)(u32 value, u32 __iomem *addr); - u32 (*reg_readl)(u32 __iomem *addr); - void (*reg_writew)(u16 value, u16 __iomem *addr); - u16 (*reg_readw)(u16 __iomem *addr); - void (*reg_writeb)(u8 value, u8 __iomem *addr); - u8 (*reg_readb)(u8 __iomem *addr); - /* Disable msi if supported, PCI only */ - int (*disable_msi_reset_irq)(struct azx *); - /* Allocation ops */ - int (*dma_alloc_pages)(struct azx *chip, - int type, - size_t size, - struct snd_dma_buffer *buf); - void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf); - int (*substream_alloc_pages)(struct azx *chip, - struct snd_pcm_substream *substream, - size_t size); - int (*substream_free_pages)(struct azx *chip, - struct snd_pcm_substream *substream); - void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream, - struct vm_area_struct *area); - /* Check if current position is acceptable */ - int (*position_check)(struct azx *chip, struct azx_dev *azx_dev); -}; - -struct azx_pcm { - struct azx *chip; - struct snd_pcm *pcm; - struct hda_codec *codec; - struct hda_pcm_stream *hinfo[2]; - struct list_head list; -}; - -typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *); -typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos); - -struct azx { - struct snd_card *card; - struct pci_dev *pci; - int dev_index; - - /* chip type specific */ - int driver_type; - unsigned int driver_caps; - int playback_streams; - int playback_index_offset; - int capture_streams; - int capture_index_offset; - int num_streams; - const int *jackpoll_ms; /* per-card jack poll interval */ - - /* Register interaction. */ - const struct hda_controller_ops *ops; - - /* position adjustment callbacks */ - azx_get_pos_callback_t get_position[2]; - azx_get_delay_callback_t get_delay[2]; - - /* pci resources */ - unsigned long addr; - void __iomem *remap_addr; - int irq; - - /* locks */ - spinlock_t reg_lock; - struct mutex open_mutex; /* Prevents concurrent open/close operations */ - - /* streams (x num_streams) */ - struct azx_dev *azx_dev; - - /* PCM */ - struct list_head pcm_list; /* azx_pcm list */ - - /* HD codec */ - unsigned short codec_mask; - int codec_probe_mask; /* copied from probe_mask option */ - struct hda_bus *bus; - unsigned int beep_mode; - - /* CORB/RIRB */ - struct azx_rb corb; - struct azx_rb rirb; - - /* CORB/RIRB and position buffers */ - struct snd_dma_buffer rb; - struct snd_dma_buffer posbuf; - -#ifdef CONFIG_SND_HDA_PATCH_LOADER - const struct firmware *fw; -#endif - - /* flags */ - const int *bdl_pos_adj; - int poll_count; - unsigned int running:1; - unsigned int initialized:1; - unsigned int single_cmd:1; - unsigned int polling_mode:1; - unsigned int msi:1; - unsigned int probing:1; /* codec probing phase */ - unsigned int snoop:1; - unsigned int align_buffer_size:1; - unsigned int region_requested:1; - unsigned int disabled:1; /* disabled by VGA-switcher */ - - /* for debugging */ - unsigned int last_cmd[AZX_MAX_CODECS]; - - /* reboot notifier (for mysterious hangup problem at power-down) */ - struct notifier_block reboot_notifier; - -#ifdef CONFIG_SND_HDA_DSP_LOADER - struct azx_dev saved_azx_dev; -#endif -}; - -#ifdef CONFIG_X86 -#define azx_snoop(chip) ((chip)->snoop) -#else -#define azx_snoop(chip) true -#endif - -/* - * macros for easy use - */ - -#define azx_writel(chip, reg, value) \ - ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg)) -#define azx_readl(chip, reg) \ - ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg)) -#define azx_writew(chip, reg, value) \ - ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg)) -#define azx_readw(chip, reg) \ - ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg)) -#define azx_writeb(chip, reg, value) \ - ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg)) -#define azx_readb(chip, reg) \ - ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg)) - -#define azx_sd_writel(chip, dev, reg, value) \ - ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readl(chip, dev, reg) \ - ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_writew(chip, dev, reg, value) \ - ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readw(chip, dev, reg) \ - ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_writeb(chip, dev, reg, value) \ - ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg)) -#define azx_sd_readb(chip, dev, reg) \ - ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg)) - -#define azx_has_pm_runtime(chip) \ - (!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME)) - -#endif /* __SOUND_HDA_PRIV_H */ diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 375e94f4cf52..7d0d04480f48 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -37,7 +37,6 @@ #include "hda_codec.h" #include "hda_controller.h" -#include "hda_priv.h" /* Defines for Nvidia Tegra HDA support */ #define HDA_BAR0 0x8000 -- GitLab From b8f28d53641f13902790904ab15028ff8ecd0882 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 18:06:45 +0100 Subject: [PATCH 0024/1910] ALSA: hda - Drop azx_mixer_create() It's just an indirection, so let the caller directly calling snd_hda_build_controls(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 7 ------- sound/pci/hda/hda_controller.h | 1 - sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 6b3254d479e1..6fab39133051 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1923,13 +1923,6 @@ int azx_codec_configure(struct azx *chip) } EXPORT_SYMBOL_GPL(azx_codec_configure); -/* mixer creation - all stuff is implemented in hda module */ -int azx_mixer_create(struct azx *chip) -{ - return snd_hda_build_controls(chip->bus); -} -EXPORT_SYMBOL_GPL(azx_mixer_create); - static bool is_input_stream(struct azx *chip, unsigned char index) { diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index bd50b49cdd0d..79808e1a79ac 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -436,7 +436,6 @@ int azx_codec_create(struct azx *chip, const char *model, unsigned int max_slots, int *power_save_to); int azx_codec_configure(struct azx *chip); -int azx_mixer_create(struct azx *chip); int azx_init_stream(struct azx *chip); void azx_notifier_register(struct azx *chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ced44a75f8ea..b0a05691abe7 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1923,7 +1923,7 @@ static int azx_probe_continue(struct azx *chip) goto out_free; /* create mixer controls */ - err = azx_mixer_create(chip); + err = snd_hda_build_controls(chip->bus); if (err < 0) goto out_free; diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 7d0d04480f48..f305c2a99206 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -516,7 +516,7 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; /* create mixer controls */ - err = azx_mixer_create(chip); + err = snd_hda_build_controls(chip->bus); if (err < 0) goto out_free; -- GitLab From 96d2bd6e3cdf57926f80605d6e28051bb6b24eb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 18:12:22 +0100 Subject: [PATCH 0025/1910] ALSA: hda - Split azx_codec_create() to two phases azx_create_codec() function does actually two things: create a bus and probe codecs. For the future work, split this to two logical functions, azx_bus_create() and azx_probe_codecs(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 40 ++++++++++++++++++++-------------- sound/pci/hda/hda_controller.h | 5 ++--- sound/pci/hda/hda_intel.c | 8 ++++--- sound/pci/hda/hda_tegra.c | 6 ++++- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 6fab39133051..2a674525e56f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1829,13 +1829,11 @@ static struct hda_bus_ops bus_ops = { #endif }; -/* Codec initialization */ -int azx_codec_create(struct azx *chip, const char *model, - unsigned int max_slots, - int *power_save_to) +/* HD-audio bus initialization */ +int azx_bus_create(struct azx *chip, const char *model, int *power_save_to) { struct hda_bus *bus; - int c, codecs, err; + int err; err = snd_hda_bus_new(chip->card, &bus); if (err < 0) @@ -1855,6 +1853,26 @@ int azx_codec_create(struct azx *chip, const char *model, bus->needs_damn_long_delay = 1; } + /* AMD chipsets often cause the communication stalls upon certain + * sequence like the pin-detection. It seems that forcing the synced + * access works around the stall. Grrr... + */ + if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { + dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n"); + bus->sync_write = 1; + bus->allow_bus_reset = 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(azx_bus_create); + +/* Probe codecs */ +int azx_probe_codecs(struct azx *chip, unsigned int max_slots) +{ + struct hda_bus *bus = chip->bus; + int c, codecs, err; + codecs = 0; if (!max_slots) max_slots = AZX_DEFAULT_CODECS; @@ -1882,16 +1900,6 @@ int azx_codec_create(struct azx *chip, const char *model, } } - /* AMD chipsets often cause the communication stalls upon certain - * sequence like the pin-detection. It seems that forcing the synced - * access works around the stall. Grrr... - */ - if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { - dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n"); - bus->sync_write = 1; - bus->allow_bus_reset = 1; - } - /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { @@ -1910,7 +1918,7 @@ int azx_codec_create(struct azx *chip, const char *model, } return 0; } -EXPORT_SYMBOL_GPL(azx_codec_create); +EXPORT_SYMBOL_GPL(azx_probe_codecs); /* configure each codec instance */ int azx_codec_configure(struct azx *chip) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 79808e1a79ac..0d09aa6b49ac 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -432,9 +432,8 @@ void azx_enter_link_reset(struct azx *chip); irqreturn_t azx_interrupt(int irq, void *dev_id); /* Codec interface */ -int azx_codec_create(struct azx *chip, const char *model, - unsigned int max_slots, - int *power_save_to); +int azx_bus_create(struct azx *chip, const char *model, int *power_save_to); +int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); int azx_init_stream(struct azx *chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b0a05691abe7..5e00cc4a722f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1893,12 +1893,14 @@ static int azx_probe_continue(struct azx *chip) #endif /* create codec instances */ - err = azx_codec_create(chip, model[dev], - azx_max_codecs[chip->driver_type], - power_save_addr); + err = azx_bus_create(chip, model[dev], power_save_addr); + if (err < 0) + goto out_free; + err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]); if (err < 0) goto out_free; + #ifdef CONFIG_SND_HDA_PATCH_LOADER if (chip->fw) { err = snd_hda_load_patch(chip->bus, chip->fw->size, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index f305c2a99206..1bd7a9e04046 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -502,7 +502,11 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; /* create codec instances */ - err = azx_codec_create(chip, NULL, 0, &power_save); + err = azx_bus_create(chip, NULL, &power_save); + if (err < 0) + goto out_free; + + err = azx_probe_codecs(chip, 0); if (err < 0) goto out_free; -- GitLab From 781c7b9615dc1441d6743124086eb3da14bf46e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 10:26:25 +0100 Subject: [PATCH 0026/1910] ALSA: hda - Avoid unnecessary power-up at mixer amp changes When the mixer amp is touched by control elements, we don't have to power up always; if the codec was suspended at the time, we can just update the amp cache and it's reflected to the hardware upon resume. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0734cb35887d..5e755eb6f19a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2148,11 +2148,10 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val, - bool init_only) + bool init_only, bool cache_only) { struct hda_amp_info *info; unsigned int caps; - unsigned int cache_only; if (snd_BUG_ON(mask & ~0xff)) mask &= 0xff; @@ -2170,7 +2169,7 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; } info->vol[ch] = val; - cache_only = info->head.dirty = codec->cached_write; + info->head.dirty |= cache_only; caps = info->amp_caps; mutex_unlock(&codec->hash_mutex); if (!cache_only) @@ -2194,7 +2193,8 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val) { - return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false); + return codec_amp_update(codec, nid, ch, direction, idx, mask, val, + false, codec->cached_write); } EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); @@ -2241,7 +2241,8 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, int mask, int val) { - return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true); + return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true, + codec->cached_write); } EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); @@ -2383,8 +2384,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, maxval = get_amp_max_value(codec, nid, dir, 0); if (val > maxval) val = maxval; - return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, - HDA_AMP_VOLMASK, val); + return codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val, + false, !hda_codec_is_power_on(codec)); } /** @@ -2434,14 +2435,12 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; - snd_hda_power_up(codec); if (chs & 1) { change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); valp++; } if (chs & 2) change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); - snd_hda_power_down(codec); return change; } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); @@ -3109,19 +3108,19 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; - snd_hda_power_up(codec); if (chs & 1) { - change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - HDA_AMP_MUTE, - *valp ? 0 : HDA_AMP_MUTE); + change = codec_amp_update(codec, nid, 0, dir, idx, + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE, false, + !hda_codec_is_power_on(codec)); valp++; } if (chs & 2) - change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - HDA_AMP_MUTE, - *valp ? 0 : HDA_AMP_MUTE); + change |= codec_amp_update(codec, nid, 1, dir, idx, + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE, false, + !hda_codec_is_power_on(codec)); hda_call_check_power_status(codec, nid); - snd_hda_power_down(codec); return change; } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); -- GitLab From 229d043096ea8e58829d37d35767afeac15997f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:03 -0600 Subject: [PATCH 0027/1910] ALSA: core: selection of audio_tstamp type and accuracy reports Audio timestamps can be extracted from sample counters, wall clocks, PHC clocks (Ethernet AVB), on-demand synchronized snapshots. This patch provides the ability to report timestamping capabilities, select timestamp types and retrieve timestamp accuracy, if supported. Details can be found in Documentations/sound/alsa/timestamping.txt This functionality is introduced by reclaiming the reserved_aligned field introduced by commit9c7066aef4a5eb8e4063de28f06c508bf6f2963a in snd_pcm_status to provide userspace with selection/query capabilities. Additional driver_tstamp and audio_tstamp_accuracy fields are also added. snd_pcm_mmap_status remains a read-only structure with only the audio timestamp value accessible from user space. The selection of audio timestamp type is done through snd_pcm_status only This commit does not impact ABI and does not impact the default behavior. By default audio timestamp is aligned with hw_pointer and reports the DMA position. Backwards compatibility is handled by using the HDAudio wall clock for playback and the hw_ptr for all other cases. For timestamp selection a new STATUS_EXT ioctl is introduced with read/write parameters. Alsa-lib will be modified to make use of STATUS_EXT. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/timestamping.txt | 200 ++++++++++++++++++++++ include/sound/pcm.h | 60 +++++++ include/uapi/sound/asound.h | 34 +++- 3 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 Documentation/sound/alsa/timestamping.txt diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt new file mode 100644 index 000000000000..0b191a23f534 --- /dev/null +++ b/Documentation/sound/alsa/timestamping.txt @@ -0,0 +1,200 @@ +The ALSA API can provide two different system timestamps: + +- Trigger_tstamp is the system time snapshot taken when the .trigger +callback is invoked. This snapshot is taken by the ALSA core in the +general case, but specific hardware may have synchronization +capabilities or conversely may only be able to provide a correct +estimate with a delay. In the latter two cases, the low-level driver +is responsible for updating the trigger_tstamp at the most appropriate +and precise moment. Applications should not rely solely on the first +trigger_tstamp but update their internal calculations if the driver +provides a refined estimate with a delay. + +- tstamp is the current system timestamp updated during the last +event or application query. +The difference (tstamp - trigger_tstamp) defines the elapsed time. + +The ALSA API provides reports two basic pieces of information, avail +and delay, which combined with the trigger and current system +timestamps allow for applications to keep track of the 'fullness' of +the ring buffer and the amount of queued samples. + +The use of these different pointers and time information depends on +the application needs: + +- 'avail' reports how much can be written in the ring buffer +- 'delay' reports the time it will take to hear a new sample after all +queued samples have been played out. + +When timestamps are enabled, the avail/delay information is reported +along with a snapshot of system time. Applications can select from +CLOCK_REALTIME (NTP corrections including going backwards), +CLOCK_MONOTONIC (NTP corrections but never going backwards), +CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode +dynamically with sw_params + + +The ALSA API also provide an audio_tstamp which reflects the passage +of time as measured by different components of audio hardware. In +ascii-art, this could be represented as follows (for the playback +case): + + +--------------------------------------------------------------> time + ^ ^ ^ ^ ^ + | | | | | + analog link dma app FullBuffer + time time time time time + | | | | | + |< codec delay >|<--hw delay-->||<---avail->| + |<----------------- delay---------------------->| | + |<----ring buffer length---->| + +The analog time is taken at the last stage of the playback, as close +as possible to the actual transducer + +The link time is taken at the output of the SOC/chipset as the samples +are pushed on a link. The link time can be directly measured if +supported in hardware by sample counters or wallclocks (e.g. with +HDAudio 24MHz or PTP clock for networked solutions) or indirectly +estimated (e.g. with the frame counter in USB). + +The DMA time is measured using counters - typically the least reliable +of all measurements due to the bursty natured of DMA transfers. + +The app time corresponds to the time tracked by an application after +writing in the ring buffer. + +The application can query what the hardware supports, define which +audio time it wants reported by selecting the relevant settings in +audio_tstamp_config fields, get an estimate of the timestamp +accuracy. It can also request the delay-to-analog be included in the +measurement. Direct access to the link time is very interesting on +platforms that provide an embedded DSP; measuring directly the link +time with dedicated hardware, possibly synchronized with system time, +removes the need to keep track of internal DSP processing times and +latency. + +In case the application requests an audio tstamp that is not supported +in hardware/low-level driver, the type is overridden as DEFAULT and the +timestamp will report the DMA time based on the hw_pointer value. + +For backwards compatibility with previous implementations that did not +provide timestamp selection, with a zero-valued COMPAT timestamp type +the results will default to the HDAudio wall clock for playback +streams and to the DMA time (hw_ptr) in all other cases. + +The audio timestamp accuracy can be returned to user-space, so that +appropriate decisions are made: + +- for dma time (default), the granularity of the transfers can be + inferred from the steps between updates and in turn provide + information on how much the application pointer can be rewound + safely. + +- the link time can be used to track long-term drifts between audio + and system time using the (tstamp-trigger_tstamp)/audio_tstamp + ratio, the precision helps define how much smoothing/low-pass + filtering is required. The link time can be either reset on startup + or reported as is (the latter being useful to compare progress of + different streams - but may require the wallclock to be always + running and not wrap-around during idle periods). If supported in + hardware, the absolute link time could also be used to define a + precise start time (patches WIP) + +- including the delay in the audio timestamp may + counter-intuitively not increase the precision of timestamps, e.g. if a + codec includes variable-latency DSP processing or a chain of + hardware components the delay is typically not known with precision. + +The accuracy is reported in nanosecond units (using an unsigned 32-bit +word), which gives a max precision of 4.29s, more than enough for +audio applications... + +Due to the varied nature of timestamping needs, even for a single +application, the audio_tstamp_config can be changed dynamically. In +the STATUS ioctl, the parameters are read-only and do not allow for +any application selection. To work around this limitation without +impacting legacy applications, a new STATUS_EXT ioctl is introduced +with read/write parameters. ALSA-lib will be modified to make use of +STATUS_EXT and effectively deprecate STATUS. + +The ALSA API only allows for a single audio timestamp to be reported +at a time. This is a conscious design decision, reading the audio +timestamps from hardware registers or from IPC takes time, the more +timestamps are read the more imprecise the combined measurements +are. To avoid any interpretation issues, a single (system, audio) +timestamp is reported. Applications that need different timestamps +will be required to issue multiple queries and perform an +interpolation of the results + +In some hardware-specific configuration, the system timestamp is +latched by a low-level audio subsytem, and the information provided +back to the driver. Due to potential delays in the communication with +the hardware, there is a risk of misalignment with the avail and delay +information. To make sure applications are not confused, a +driver_timestamp field is added in the snd_pcm_status structure; this +timestamp shows when the information is put together by the driver +before returning from the STATUS and STATUS_EXT ioctl. in most cases +this driver_timestamp will be identical to the regular system tstamp. + +Examples of typestamping with HDaudio: + +1. DMA timestamp, no compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 +playback: systime: 341121338 nsec, audio time 342000000 nsec, systime delta -878662 +playback: systime: 426236663 nsec, audio time 427187500 nsec, systime delta -950837 +playback: systime: 597080580 nsec, audio time 598000000 nsec, systime delta -919420 +playback: systime: 682059782 nsec, audio time 683020833 nsec, systime delta -961051 +playback: systime: 852896415 nsec, audio time 853854166 nsec, systime delta -957751 +playback: systime: 937903344 nsec, audio time 938854166 nsec, systime delta -950822 + +2. DMA timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=1 -d +playback: systime: 341053347 nsec, audio time 341062500 nsec, systime delta -9153 +playback: systime: 426072447 nsec, audio time 426062500 nsec, systime delta 9947 +playback: systime: 596899518 nsec, audio time 596895833 nsec, systime delta 3685 +playback: systime: 681915317 nsec, audio time 681916666 nsec, systime delta -1349 +playback: systime: 852741306 nsec, audio time 852750000 nsec, systime delta -8694 + +3. link timestamp, compensation for DMA+analog delay +$ ./audio_time -p --ts_type=2 -d +playback: systime: 341060004 nsec, audio time 341062791 nsec, systime delta -2787 +playback: systime: 426242074 nsec, audio time 426244875 nsec, systime delta -2801 +playback: systime: 597080992 nsec, audio time 597084583 nsec, systime delta -3591 +playback: systime: 682084512 nsec, audio time 682088291 nsec, systime delta -3779 +playback: systime: 852936229 nsec, audio time 852940916 nsec, systime delta -4687 +playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -5146 + +Example 1 shows that the timestamp at the DMA level is close to 1ms +ahead of the actual playback time (as a side time this sort of +measurement can help define rewind safeguards). Compensating for the +DMA-link delay in example 2 helps remove the hardware buffering abut +the information is still very jittery, with up to one sample of +error. In example 3 where the timestamps are measured with the link +wallclock, the timestamps show a monotonic behavior and a lower +dispersion. + +Example 3 and 4 are with USB audio class. Example 3 shows a high +offset between audio time and system time due to buffering. Example 4 +shows how compensating for the delay exposes a 1ms accuracy (due to +the use of the frame counter by the driver) + +Example 3: DMA timestamp, no compensation for delay, delta of ~5ms +$ ./audio_time -p -Dhw:1 -t1 +playback: systime: 120174019 nsec, audio time 125000000 nsec, systime delta -4825981 +playback: systime: 245041136 nsec, audio time 250000000 nsec, systime delta -4958864 +playback: systime: 370106088 nsec, audio time 375000000 nsec, systime delta -4893912 +playback: systime: 495040065 nsec, audio time 500000000 nsec, systime delta -4959935 +playback: systime: 620038179 nsec, audio time 625000000 nsec, systime delta -4961821 +playback: systime: 745087741 nsec, audio time 750000000 nsec, systime delta -4912259 +playback: systime: 870037336 nsec, audio time 875000000 nsec, systime delta -4962664 + +Example 4: DMA timestamp, compensation for delay, delay of ~1ms +$ ./audio_time -p -Dhw:1 -t1 -d +playback: systime: 120190520 nsec, audio time 120000000 nsec, systime delta 190520 +playback: systime: 245036740 nsec, audio time 244000000 nsec, systime delta 1036740 +playback: systime: 370034081 nsec, audio time 369000000 nsec, systime delta 1034081 +playback: systime: 495159907 nsec, audio time 494000000 nsec, systime delta 1159907 +playback: systime: 620098824 nsec, audio time 619000000 nsec, systime delta 1098824 +playback: systime: 745031847 nsec, audio time 744000000 nsec, systime delta 1031847 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c0ddb7e69c28..60f0e48f7905 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -60,6 +60,9 @@ struct snd_pcm_hardware { struct snd_pcm_substream; +struct snd_pcm_audio_tstamp_config; /* definitions further down */ +struct snd_pcm_audio_tstamp_report; + struct snd_pcm_ops { int (*open)(struct snd_pcm_substream *substream); int (*close)(struct snd_pcm_substream *substream); @@ -281,6 +284,58 @@ struct snd_pcm_hw_constraint_ranges { struct snd_pcm_hwptr_log; +/* + * userspace-provided audio timestamp config to kernel, + * structure is for internal use only and filled with dedicated unpack routine + */ +struct snd_pcm_audio_tstamp_config { + /* 5 of max 16 bits used */ + u32 type_requested:4; + u32 report_delay:1; /* add total delay to A/D or D/A */ +}; + +static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data, + struct snd_pcm_audio_tstamp_config *config) +{ + config->type_requested = data & 0xF; + config->report_delay = (data >> 4) & 1; +} + +/* + * kernel-provided audio timestamp report to user-space + * structure is for internal use only and read by dedicated pack routine + */ +struct snd_pcm_audio_tstamp_report { + /* 6 of max 16 bits used for bit-fields */ + + /* for backwards compatibility */ + u32 valid:1; + + /* actual type if hardware could not support requested timestamp */ + u32 actual_type:4; + + /* accuracy represented in ns units */ + u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */ + u32 accuracy; /* up to 4.29s, will be packed in separate field */ +}; + +static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy, + const struct snd_pcm_audio_tstamp_report *report) +{ + u32 tmp; + + tmp = report->accuracy_report; + tmp <<= 4; + tmp |= report->actual_type; + tmp <<= 1; + tmp |= report->valid; + + *data &= 0xffff; /* zero-clear MSBs */ + *data |= (tmp << 16); + *accuracy = report->accuracy; +} + + struct snd_pcm_runtime { /* -- Status -- */ struct snd_pcm_substream *trigger_master; @@ -361,6 +416,11 @@ struct snd_pcm_runtime { struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */ + /* -- audio timestamp config -- */ + struct snd_pcm_audio_tstamp_config audio_tstamp_config; + struct snd_pcm_audio_tstamp_report audio_tstamp_report; + struct timespec driver_tstamp; + #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 0e88e7a0f0eb..acef4e4d2735 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -267,10 +267,17 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ -#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* (Deprecated)has audio wall clock for audio/system time sync */ +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 /* report hardware link audio time, reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 /* report absolute hardware link audio time, not reset on startup */ +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 /* report estimated link audio time */ +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 /* report synchronized audio/system time */ + #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ + + typedef int __bitwise snd_pcm_state_t; #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ #define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ @@ -408,6 +415,22 @@ struct snd_pcm_channel_info { unsigned int step; /* samples distance in bits */ }; +enum { + /* + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + + /* timestamp definitions */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /* DMA time, reported as per hw_ptr */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /* link time reported by sample or wallclock counter, reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /* link time reported by sample or wallclock counter, not reset on startup */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /* link time estimated indirectly */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */ + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; + struct snd_pcm_status { snd_pcm_state_t state; /* stream state */ struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ @@ -419,9 +442,11 @@ struct snd_pcm_status { snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ snd_pcm_state_t suspended_state; /* suspended stream state */ - __u32 reserved_alignment; /* must be filled with zero */ - struct timespec audio_tstamp; /* from sample counter or wall clock */ - unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ }; struct snd_pcm_mmap_status { @@ -534,6 +559,7 @@ enum { #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) #define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) #define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) -- GitLab From 38ca2a4d58bbc45973ee5cd14e4b803ee5ad69f0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:04 -0600 Subject: [PATCH 0028/1910] ALSA: core: pass audio tstamp config from userspace Let userspace select audio timestamp config when the STATUS_EXT ioctl is used, ignore and zero all other fields No change for the existing STATUS ioctl, parameters are treated as read-only. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b03a638b420c..72323a8c35c8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -753,12 +753,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream, } static int snd_pcm_status_user(struct snd_pcm_substream *substream, - struct snd_pcm_status __user * _status) + struct snd_pcm_status __user * _status, + bool ext) { struct snd_pcm_status status; int res; - + memset(&status, 0, sizeof(status)); + /* + * with extension, parameters are read/write, + * get audio_tstamp_data from user, + * ignore rest of status structure + */ + if (ext && get_user(status.audio_tstamp_data, + (u32 __user *)(&_status->audio_tstamp_data))) + return -EFAULT; res = snd_pcm_status(substream, &status); if (res < 0) return res; @@ -2723,7 +2732,9 @@ static int snd_pcm_common_ioctl1(struct file *file, case SNDRV_PCM_IOCTL_SW_PARAMS: return snd_pcm_sw_params_user(substream, arg); case SNDRV_PCM_IOCTL_STATUS: - return snd_pcm_status_user(substream, arg); + return snd_pcm_status_user(substream, arg, false); + case SNDRV_PCM_IOCTL_STATUS_EXT: + return snd_pcm_status_user(substream, arg, true); case SNDRV_PCM_IOCTL_CHANNEL_INFO: return snd_pcm_channel_info_user(substream, arg); case SNDRV_PCM_IOCTL_PREPARE: -- GitLab From 5442a73a009231598fb5ea065c4e3f9daa30d8cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:05 -0600 Subject: [PATCH 0029/1910] ALSA: core: pass audio tstamp config from userspace in compat mode Let userspace select audio timestamp config, ignore and zero all other fields Use audio_tstamp_data to retrieve config and pass report back to user space Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/core/pcm_compat.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2d957ba63557..b48b434444ed 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -194,18 +194,30 @@ struct snd_pcm_status32 { u32 avail_max; u32 overrange; s32 suspended_state; - u32 reserved_alignment; + u32 audio_tstamp_data; struct compat_timespec audio_tstamp; - unsigned char reserved[56-sizeof(struct compat_timespec)]; + struct compat_timespec driver_tstamp; + u32 audio_tstamp_accuracy; + unsigned char reserved[52-2*sizeof(struct compat_timespec)]; } __attribute__((packed)); static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, - struct snd_pcm_status32 __user *src) + struct snd_pcm_status32 __user *src, + bool ext) { struct snd_pcm_status status; int err; + memset(&status, 0, sizeof(status)); + /* + * with extension, parameters are read/write, + * get audio_tstamp_data from user, + * ignore rest of status structure + */ + if (ext && get_user(status.audio_tstamp_data, + (u32 __user *)(&src->audio_tstamp_data))) + return -EFAULT; err = snd_pcm_status(substream, &status); if (err < 0) return err; @@ -222,7 +234,10 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, put_user(status.avail_max, &src->avail_max) || put_user(status.overrange, &src->overrange) || put_user(status.suspended_state, &src->suspended_state) || - compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp)) + put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || + compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) || + compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) || + put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) return -EFAULT; return err; @@ -457,6 +472,7 @@ enum { SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32), SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32), SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32), + SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32), SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32), SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), @@ -517,7 +533,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_SW_PARAMS32: return snd_pcm_ioctl_sw_params_compat(substream, argp); case SNDRV_PCM_IOCTL_STATUS32: - return snd_pcm_status_user_compat(substream, argp); + return snd_pcm_status_user_compat(substream, argp, false); + case SNDRV_PCM_IOCTL_STATUS_EXT32: + return snd_pcm_status_user_compat(substream, argp, true); case SNDRV_PCM_IOCTL_SYNC_PTR32: return snd_pcm_ioctl_sync_ptr_compat(substream, argp); case SNDRV_PCM_IOCTL_CHANNEL_INFO32: -- GitLab From 3179f62001880e588e229db3006a59ad87b7792a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:06 -0600 Subject: [PATCH 0030/1910] ALSA: core: add .get_time_info Introduce more generic .get_time_info to retrieve system timestamp and audio timestamp in single routine. Backwards compatibility is preserved with same functionality as with .wall_clock method (to be removed in following commits to avoid breaking git bisect) Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 4 ++ sound/core/pcm_lib.c | 88 +++++++++++++++++++++++++++-------------- sound/core/pcm_native.c | 24 +++++++++++ 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 60f0e48f7905..04f2d492ae57 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -76,6 +76,10 @@ struct snd_pcm_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); int (*wall_clock)(struct snd_pcm_substream *substream, struct timespec *audio_ts); + int (*get_time_info)(struct snd_pcm_substream *substream, + struct timespec *system_ts, struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report); int (*copy)(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void __user *buf, snd_pcm_uframes_t count); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ffd656012ab8..ac6b33f3779c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return 0; } +static void update_audio_tstamp(struct snd_pcm_substream *substream, + struct timespec *curr_tstamp, + struct timespec *audio_tstamp) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + u64 audio_frames, audio_nsecs; + struct timespec driver_tstamp; + + if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) + return; + + if (!(substream->ops->get_time_info) || + (runtime->audio_tstamp_report.actual_type == + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { + + /* + * provide audio timestamp derived from pointer position + * add delay only if requested + */ + + audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr; + + if (runtime->audio_tstamp_config.report_delay) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + audio_frames -= runtime->delay; + else + audio_frames += runtime->delay; + } + audio_nsecs = div_u64(audio_frames * 1000000000LL, + runtime->rate); + *audio_tstamp = ns_to_timespec(audio_nsecs); + } + runtime->status->audio_tstamp = *audio_tstamp; + runtime->status->tstamp = *curr_tstamp; + + /* + * re-take a driver timestamp to let apps detect if the reference tstamp + * read by low-level hardware was provided with a delay + */ + snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); + runtime->driver_tstamp = driver_tstamp; +} + static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, unsigned int in_interrupt) { @@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, pos = substream->ops->pointer(substream); curr_jiffies = jiffies; if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { - snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); - - if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) && - (substream->ops->wall_clock)) - substream->ops->wall_clock(substream, &audio_tstamp); + if ((substream->ops->get_time_info) && + (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { + substream->ops->get_time_info(substream, &curr_tstamp, + &audio_tstamp, + &runtime->audio_tstamp_config, + &runtime->audio_tstamp_report); + + /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ + if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) + snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); + } else + snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); } if (pos == SNDRV_PCM_POS_XRUN) { @@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } no_delta_check: - if (runtime->status->hw_ptr == new_hw_ptr) + if (runtime->status->hw_ptr == new_hw_ptr) { + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); return 0; + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) @@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, snd_BUG_ON(crossed_boundary != 1); runtime->hw_ptr_wrap += runtime->boundary; } - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { - runtime->status->tstamp = curr_tstamp; - if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) { - /* - * no wall clock available, provide audio timestamp - * derived from pointer position+delay - */ - u64 audio_frames, audio_nsecs; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - audio_frames = runtime->hw_ptr_wrap - + runtime->status->hw_ptr - - runtime->delay; - else - audio_frames = runtime->hw_ptr_wrap - + runtime->status->hw_ptr - + runtime->delay; - audio_nsecs = div_u64(audio_frames * 1000000000LL, - runtime->rate); - audio_tstamp = ns_to_timespec(audio_nsecs); - } - runtime->status->audio_tstamp = audio_tstamp; - } + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); return snd_pcm_update_state(substream, runtime); } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 72323a8c35c8..9c2c6f801fed 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); + + snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, + &runtime->audio_tstamp_config); + + /* backwards compatible behavior */ + if (runtime->audio_tstamp_config.type_requested == + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) { + if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) + runtime->audio_tstamp_config.type_requested = + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; + else + runtime->audio_tstamp_config.type_requested = + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; + runtime->audio_tstamp_report.valid = 0; + } else + runtime->audio_tstamp_report.valid = 1; + status->state = runtime->status->state; status->suspended_state = runtime->status->suspended_state; if (status->state == SNDRV_PCM_STATE_OPEN) @@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, snd_pcm_update_hw_ptr(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { status->tstamp = runtime->status->tstamp; + status->driver_tstamp = runtime->driver_tstamp; status->audio_tstamp = runtime->status->audio_tstamp; + if (runtime->audio_tstamp_report.valid == 1) + /* backwards compatibility, no report provided in COMPAT mode */ + snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, + &status->audio_tstamp_accuracy, + &runtime->audio_tstamp_report); + goto _tstamp_end; } } else { -- GitLab From 9e94df3a624b1b485f2c2ac5ab94032da01e45b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:07 -0600 Subject: [PATCH 0031/1910] ALSA: hda: replace .wallclock by .get_time_info No real functional change, only take wall clock and system time in same routine and add accuracy report. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 40 ++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index dfcb5e929f9f..7806f1d297cb 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -732,17 +732,32 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) azx_get_position(chip, azx_dev)); } -static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, - struct timespec *ts) +static int azx_get_time_info(struct snd_pcm_substream *substream, + struct timespec *system_ts, struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report) { struct azx_dev *azx_dev = get_azx_dev(substream); u64 nsec; - nsec = timecounter_read(&azx_dev->azx_tc); - nsec = div_u64(nsec, 3); /* can be optimized */ - nsec = azx_adjust_codec_delay(substream, nsec); + if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && + (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { - *ts = ns_to_timespec(nsec); + snd_pcm_gettime(substream->runtime, system_ts); + + nsec = timecounter_read(&azx_dev->azx_tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + if (audio_tstamp_config->report_delay) + nsec = azx_adjust_codec_delay(substream, nsec); + + *audio_ts = ns_to_timespec(nsec); + + audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; + audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ + audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */ + + } else + audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; return 0; } @@ -756,7 +771,8 @@ static struct snd_pcm_hardware azx_pcm_hw = { /* SNDRV_PCM_INFO_RESUME |*/ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START | - SNDRV_PCM_INFO_HAS_WALL_CLOCK | + SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ + SNDRV_PCM_INFO_HAS_LINK_ATIME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -842,10 +858,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) return -EINVAL; } - /* disable WALLCLOCK timestamps for capture streams + /* disable LINK_ATIME timestamps for capture streams until we figure out how to handle digital inputs */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; + } spin_lock_irqsave(&chip->reg_lock, flags); azx_dev->substream = substream; @@ -877,7 +895,7 @@ static struct snd_pcm_ops azx_pcm_ops = { .prepare = azx_pcm_prepare, .trigger = azx_pcm_trigger, .pointer = azx_pcm_pointer, - .wall_clock = azx_get_wallclock_tstamp, + .get_time_info = azx_get_time_info, .mmap = azx_pcm_mmap, .page = snd_pcm_sgbuf_ops_page, }; -- GitLab From 2d52a5abd5be35340296a251092c8a594679df54 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:08 -0600 Subject: [PATCH 0032/1910] ALSA: core: remove .wall_clock can be removed without breaking git-bisect now Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 04f2d492ae57..0cb7f3f5df7b 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -74,8 +74,6 @@ struct snd_pcm_ops { int (*prepare)(struct snd_pcm_substream *substream); int (*trigger)(struct snd_pcm_substream *substream, int cmd); snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); - int (*wall_clock)(struct snd_pcm_substream *substream, - struct timespec *audio_ts); int (*get_time_info)(struct snd_pcm_substream *substream, struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, -- GitLab From c72638bdaabe9ea4b09003b9db7e1754f472fbed Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Feb 2015 15:14:09 -0600 Subject: [PATCH 0033/1910] ALSA: bump PCM protocol to 2.0.13 Bump PCM protocol to enable use of STATUS_EXT ioctls, older apps will still use STATUS and audio timestamp configuration is not supported (backwards compatible behavior). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index acef4e4d2735..3d46e9a0cd2e 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -140,7 +140,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 12) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; -- GitLab From ad876c862278be59147d4004f1a7c4d492e4ec96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 16:26:00 +0100 Subject: [PATCH 0034/1910] ALSA: pcm: Minor refactoring in snd_pcm_attach_substream() No functional changes at all. Acked-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 0345e53a340c..d63d262c571e 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -919,6 +919,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, if (snd_BUG_ON(!pcm || !rsubstream)) return -ENXIO; + if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK && + stream != SNDRV_PCM_STREAM_CAPTURE)) + return -EINVAL; *rsubstream = NULL; pstr = &pcm->streams[stream]; if (pstr->substream == NULL || pstr->substream_count == 0) @@ -927,25 +930,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); - switch (stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { - for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { - if (SUBSTREAM_BUSY(substream)) - return -EAGAIN; - } - } - break; - case SNDRV_PCM_STREAM_CAPTURE: - if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { - for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { - if (SUBSTREAM_BUSY(substream)) - return -EAGAIN; - } + if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { + int opposite = !stream; + + for (substream = pcm->streams[opposite].substream; substream; + substream = substream->next) { + if (SUBSTREAM_BUSY(substream)) + return -EAGAIN; } - break; - default: - return -EINVAL; } if (file->f_flags & O_APPEND) { @@ -968,15 +960,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, return 0; } - if (prefer_subdevice >= 0) { - for (substream = pstr->substream; substream; substream = substream->next) - if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) - goto __ok; - } - for (substream = pstr->substream; substream; substream = substream->next) - if (!SUBSTREAM_BUSY(substream)) + for (substream = pstr->substream; substream; substream = substream->next) { + if (!SUBSTREAM_BUSY(substream) && + (prefer_subdevice == -1 || + substream->number == prefer_subdevice)) break; - __ok: + } if (substream == NULL) return -EAGAIN; -- GitLab From b95bd3a454cf9e9e111b6b87c02550368fe6e802 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 16:49:04 +0100 Subject: [PATCH 0035/1910] ALSA: pcm: Don't add internal PCMs to PCM device list An internal PCM object shouldn't be added to the PCM device list, as it's never accessed directly from the user-space, and it has no proc or any similar accesses. Currently, it's excluded in snd_pcm_get() and snd_pcm_next(), but it's easier not to add such an object to the list. Actually, the whole snd_pcm_dev_register() can be skipped for an internal PCM. So this patch changes the code there, but also addresses the uninitialized list_head access. Acked-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d63d262c571e..d440629e08e2 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device) struct snd_pcm *pcm; list_for_each_entry(pcm, &snd_pcm_devices, list) { - if (pcm->internal) - continue; if (pcm->card == card && pcm->device == device) return pcm; } @@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device) struct snd_pcm *pcm; list_for_each_entry(pcm, &snd_pcm_devices, list) { - if (pcm->internal) - continue; if (pcm->card == card && pcm->device > device) return pcm->device; else if (pcm->card->number > card->number) @@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm) { struct snd_pcm *pcm; + if (newpcm->internal) + return 0; + list_for_each_entry(pcm, &snd_pcm_devices, list) { if (pcm->card == newpcm->card && pcm->device == newpcm->device) return -EBUSY; @@ -782,6 +781,9 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, pcm->card = card; pcm->device = device; pcm->internal = internal; + mutex_init(&pcm->open_mutex); + init_waitqueue_head(&pcm->open_wait); + INIT_LIST_HEAD(&pcm->list); if (id) strlcpy(pcm->id, id, sizeof(pcm->id)); if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { @@ -792,8 +794,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, snd_pcm_free(pcm); return err; } - mutex_init(&pcm->open_mutex); - init_waitqueue_head(&pcm->open_wait); if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { snd_pcm_free(pcm); return err; @@ -1075,15 +1075,16 @@ static int snd_pcm_dev_register(struct snd_device *device) if (snd_BUG_ON(!device || !device->device_data)) return -ENXIO; pcm = device->device_data; + if (pcm->internal) + return 0; + mutex_lock(®ister_mutex); err = snd_pcm_add(pcm); - if (err) { - mutex_unlock(®ister_mutex); - return err; - } + if (err) + goto unlock; for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; - if (pcm->streams[cidx].substream == NULL || pcm->internal) + if (pcm->streams[cidx].substream == NULL) continue; switch (cidx) { case SNDRV_PCM_STREAM_PLAYBACK: @@ -1098,9 +1099,8 @@ static int snd_pcm_dev_register(struct snd_device *device) &snd_pcm_f_ops[cidx], pcm, &pcm->streams[cidx].dev); if (err < 0) { - list_del(&pcm->list); - mutex_unlock(®ister_mutex); - return err; + list_del_init(&pcm->list); + goto unlock; } for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) @@ -1110,8 +1110,9 @@ static int snd_pcm_dev_register(struct snd_device *device) list_for_each_entry(notify, &snd_pcm_notify_list, list) notify->n_register(pcm); + unlock: mutex_unlock(®ister_mutex); - return 0; + return err; } static int snd_pcm_dev_disconnect(struct snd_device *device) -- GitLab From 646e1dd8f9f47c57560ce81c02fdd57ff0929bc6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 17:04:08 +0100 Subject: [PATCH 0036/1910] ALSA: pcm: Don't notify internal PCMs Notifier shouldn't listen to the changes of internal PCMs. Acked-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d440629e08e2..542dbc6f54e8 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -888,8 +888,9 @@ static int snd_pcm_free(struct snd_pcm *pcm) if (!pcm) return 0; - list_for_each_entry(notify, &snd_pcm_notify_list, list) { - notify->n_unregister(pcm); + if (!pcm->internal) { + list_for_each_entry(notify, &snd_pcm_notify_list, list) + notify->n_unregister(pcm); } if (pcm->private_free) pcm->private_free(pcm); @@ -1129,7 +1130,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) mutex_lock(&pcm->open_mutex); wake_up(&pcm->open_wait); list_del_init(&pcm->list); - for (cidx = 0; cidx < 2; cidx++) + for (cidx = 0; cidx < 2; cidx++) { for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { snd_pcm_stream_lock_irq(substream); if (substream->runtime) { @@ -1139,8 +1140,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) } snd_pcm_stream_unlock_irq(substream); } - list_for_each_entry(notify, &snd_pcm_notify_list, list) { - notify->n_disconnect(pcm); + } + if (!pcm->internal) { + list_for_each_entry(notify, &snd_pcm_notify_list, list) + notify->n_disconnect(pcm); } for (cidx = 0; cidx < 2; cidx++) { snd_unregister_device(&pcm->streams[cidx].dev); -- GitLab From b20221385c40155f13068be75b865170a1ad5d1e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 17:05:27 +0100 Subject: [PATCH 0037/1910] ALSA: pcm: Don't ignore internal PCMs in snd_pcm_dev_disconnect() Some codes in snd_pcm_dev_disconnect() are still valid even for internal PCMs, but they are skipped because of the check of list_empty(&pcm->list) at the beginning. Remove this check and put pcm->internal checks appropriately for internal PCM object to process through this function. Acked-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 542dbc6f54e8..e9b87465c73d 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1124,9 +1124,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) int cidx; mutex_lock(®ister_mutex); - if (list_empty(&pcm->list)) - goto unlock; - mutex_lock(&pcm->open_mutex); wake_up(&pcm->open_wait); list_del_init(&pcm->list); @@ -1146,14 +1143,14 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) notify->n_disconnect(pcm); } for (cidx = 0; cidx < 2; cidx++) { - snd_unregister_device(&pcm->streams[cidx].dev); + if (!pcm->internal) + snd_unregister_device(&pcm->streams[cidx].dev); if (pcm->streams[cidx].chmap_kctl) { snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); pcm->streams[cidx].chmap_kctl = NULL; } } mutex_unlock(&pcm->open_mutex); - unlock: mutex_unlock(®ister_mutex); return 0; } -- GitLab From 7371bd1f4aeb4e1c44b8c1ba8e36ebba4250b59c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 17 Feb 2015 13:59:26 +0800 Subject: [PATCH 0038/1910] ASoC: rt5670: Add disabled item in dmic pin enum Currently, we will configure dmic related pin definition if pdata.dmic_en is true. However, there is no disable option in the enum. So, any dmic is used, all 3 dmic related pins will be configured. It may cause unexpected pin definition. This patch adds a disable item for each dmic enum and take it as default. So the driver will not set the pin configuration if we don't set dmicx_data_pin in platform data. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index d11b9c207e26..84857bdaa78b 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1967,17 +1967,20 @@ enum { }; enum { + RT5670_DMIC1_DISABLED, RT5670_DMIC_DATA_GPIO6, RT5670_DMIC_DATA_IN2P, RT5670_DMIC_DATA_GPIO7, }; enum { + RT5670_DMIC2_DISABLED, RT5670_DMIC_DATA_GPIO8, RT5670_DMIC_DATA_IN3N, }; enum { + RT5670_DMIC3_DISABLED, RT5670_DMIC_DATA_GPIO9, RT5670_DMIC_DATA_GPIO10, RT5670_DMIC_DATA_GPIO5, -- GitLab From 65d17a9ce9f24a3aaf7d614251fdcc1b2121765f Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Mon, 16 Feb 2015 15:25:48 +0000 Subject: [PATCH 0039/1910] ASoC: wm_adsp: Ensure DSP controls are always persistent Currently DSP controls are persistent (across DSP On/Off) only if they were set whilst the DSP is off. This change makes the controls persistent irrespective of when they are set. Signed-off-by: Nikesh Oswal Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 720d6e852986..14414ea23b55 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -420,10 +420,9 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol, memcpy(ctl->cache, p, ctl->len); - if (!ctl->enabled) { - ctl->set = 1; + ctl->set = 1; + if (!ctl->enabled) return 0; - } return wm_coeff_write_control(kcontrol, p, ctl->len); } -- GitLab From be951017453cba2f3eb789413f697b8f14393eec Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 16 Feb 2015 15:25:49 +0000 Subject: [PATCH 0040/1910] ASoC: wm_adsp: Improve round to next 4-byte boundary Whilst the existing code does correctly round to the next 4-byte boundary it does so rather inefficiently. This patch changes the rounding to be simpler and more efficient. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 14414ea23b55..e625cedb0fa9 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1184,7 +1184,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) int ret, pos, blocks, type, offset, reg; char *file; struct wm_adsp_buf *buf; - int tmp; file = kzalloc(PAGE_SIZE, GFP_KERNEL); if (file == NULL) @@ -1334,12 +1333,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) } } - tmp = le32_to_cpu(blk->len) % 4; - if (tmp) - pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk); - else - pos += le32_to_cpu(blk->len) + sizeof(*blk); - + pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; blocks++; } -- GitLab From 7ff5eabce4231d199dadc14c23f14a6619f926c0 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 17 Feb 2015 00:53:12 -0800 Subject: [PATCH 0041/1910] ASoC: max98357a: Remove use of DRV_NAME Remove use of DRV_NAME define. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index e9e6efbc21dd..4ee23fbc4e12 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -26,8 +26,6 @@ #include #include -#define DRV_NAME "max98357a" - static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -87,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = { }; static struct snd_soc_dai_driver max98357a_dai_driver = { - .name = DRV_NAME, + .name = "max98357a", .playback = { - .stream_name = DRV_NAME "-playback", + .stream_name = "max98357a-playback", .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32, @@ -127,7 +125,7 @@ static int max98357a_platform_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id max98357a_device_id[] = { - { .compatible = "maxim," DRV_NAME, }, + { .compatible = "maxim,max98357a" }, {} }; MODULE_DEVICE_TABLE(of, max98357a_device_id); @@ -135,7 +133,7 @@ MODULE_DEVICE_TABLE(of, max98357a_device_id); static struct platform_driver max98357a_platform_driver = { .driver = { - .name = DRV_NAME, + .name = "max98357a", .of_match_table = of_match_ptr(max98357a_device_id), }, .probe = max98357a_platform_probe, @@ -145,4 +143,3 @@ module_platform_driver(max98357a_platform_driver); MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); -- GitLab From 327ef4f02582d01f7eedb291794106823b44a0cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Feb 2015 17:15:04 +0100 Subject: [PATCH 0042/1910] ALSA: hda - Decouple PCM and hwdep devices from codec object This is a preliminary patch for the hda_bus implementation, removing the parent device setup to codec device. Since the bus and the class devices can't be crossed over, leave the sound devices to the default parent device as is. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 1 - sound/pci/hda/hda_controller.c | 3 --- sound/pci/hda/hda_hwdep.c | 3 --- 3 files changed, 7 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 1e7de08e77cb..d6be4e852c4d 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -168,7 +168,6 @@ static int snd_hda_do_attach(struct hda_beep *beep) input_dev->evbit[0] = BIT_MASK(EV_SND); input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = snd_hda_beep_event; - input_dev->dev.parent = &codec->dev; input_set_drvdata(input_dev, beep); beep->dev = input_dev; diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index ebb7a644bd86..4c7a6f9bfcde 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -958,9 +958,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, chip->card->dev, size, MAX_PREALLOC_SIZE); - /* link to codec */ - for (s = 0; s < 2; s++) - pcm->streams[s].dev.parent = &codec->dev; return 0; } diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 11b5a42b4ec8..125f3420fa6a 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -116,9 +116,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif - /* link to codec */ - hwdep->dev.parent = &codec->dev; - /* for sysfs */ hwdep->dev.groups = snd_hda_dev_attr_groups; dev_set_drvdata(&hwdep->dev, codec); -- GitLab From d8a766a16ed90c4b3bd7afa6e1417f8d715db507 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Feb 2015 15:25:37 +0100 Subject: [PATCH 0043/1910] ALSA: hda - Bind codecs via standard bus Now we create the standard HD-audio bus (/sys/bus/hdaudio), and bind the codec driver with the codec device over there. This is the first step of the whole transition so that the changes to each codec driver are kept as minimal as possible. Each codec driver needs to register hda_codec_driver struct containing the currently existing preset via the new helper macro module_hda_codec_driver(). The old hda_codec_preset_list is replaced with this infrastructure. The generic parsers (for HDMI and other) are also included in the preset with the special IDs to bind uniquely. In HD-audio core side, the device binding code is split to hda_bind.c. It provides the snd_hda_bus_type implementation to match the codec driver with the given codec vendor ID. It also manages the module auto-loading by itself like before: when the matching isn't found, it tries to probe the corresponding codec modules, and finally falls back to the generic drivers. (The special ID mentioned above is set at this stage.) The only visible change to outside is that the hdaudio sysfs entry now appears in /sys/bus/devices, not as a sound class device. More works to move the suspend/resume and remove ops will be (hopefully) done in later patches. Signed-off-by: Takashi Iwai --- sound/pci/hda/Makefile | 2 +- sound/pci/hda/hda_bind.c | 320 +++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.c | 307 ++----------------------------- sound/pci/hda/hda_codec.h | 27 ++- sound/pci/hda/hda_generic.c | 18 +- sound/pci/hda/hda_local.h | 18 +- sound/pci/hda/patch_analog.c | 16 +- sound/pci/hda/patch_ca0110.c | 16 +- sound/pci/hda/patch_ca0132.c | 16 +- sound/pci/hda/patch_cirrus.c | 16 +- sound/pci/hda/patch_cmedia.c | 16 +- sound/pci/hda/patch_conexant.c | 16 +- sound/pci/hda/patch_hdmi.c | 27 +-- sound/pci/hda/patch_realtek.c | 16 +- sound/pci/hda/patch_si3054.c | 16 +- sound/pci/hda/patch_sigmatel.c | 16 +- sound/pci/hda/patch_via.c | 16 +- 17 files changed, 401 insertions(+), 478 deletions(-) create mode 100644 sound/pci/hda/hda_bind.c diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 194f30935e77..96caaebfc19d 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -4,7 +4,7 @@ snd-hda-tegra-objs := hda_tegra.o # for haswell power well snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o -snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o +snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c new file mode 100644 index 000000000000..adf6b475dee1 --- /dev/null +++ b/sound/pci/hda/hda_bind.c @@ -0,0 +1,320 @@ +/* + * HD-audio codec driver binding + * Copyright (c) Takashi Iwai + */ + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +/* codec vendor labels */ +struct hda_vendor_id { + unsigned int id; + const char *name; +}; + +static struct hda_vendor_id hda_vendor_ids[] = { + { 0x1002, "ATI" }, + { 0x1013, "Cirrus Logic" }, + { 0x1057, "Motorola" }, + { 0x1095, "Silicon Image" }, + { 0x10de, "Nvidia" }, + { 0x10ec, "Realtek" }, + { 0x1102, "Creative" }, + { 0x1106, "VIA" }, + { 0x111d, "IDT" }, + { 0x11c1, "LSI" }, + { 0x11d4, "Analog Devices" }, + { 0x13f6, "C-Media" }, + { 0x14f1, "Conexant" }, + { 0x17e8, "Chrontel" }, + { 0x1854, "LG" }, + { 0x1aec, "Wolfson Microelectronics" }, + { 0x1af4, "QEMU" }, + { 0x434d, "C-Media" }, + { 0x8086, "Intel" }, + { 0x8384, "SigmaTel" }, + {} /* terminator */ +}; + +/* + * find a matching codec preset + */ +static int hda_bus_match(struct device *dev, struct device_driver *drv) +{ + struct hda_codec *codec = container_of(dev, struct hda_codec, dev); + struct hda_codec_driver *driver = + container_of(drv, struct hda_codec_driver, driver); + const struct hda_codec_preset *preset; + /* check probe_id instead of vendor_id if set */ + u32 id = codec->probe_id ? codec->probe_id : codec->vendor_id; + + for (preset = driver->preset; preset->id; preset++) { + u32 mask = preset->mask; + + if (preset->afg && preset->afg != codec->afg) + continue; + if (preset->mfg && preset->mfg != codec->mfg) + continue; + if (!mask) + mask = ~0; + if (preset->id == (id & mask) && + (!preset->rev || preset->rev == codec->revision_id)) { + codec->preset = preset; + return 1; + } + } + return 0; +} + +/* reset the codec name from the preset */ +static int codec_refresh_name(struct hda_codec *codec, const char *name) +{ + char tmp[16]; + + kfree(codec->chip_name); + if (!name) { + sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); + name = tmp; + } + codec->chip_name = kstrdup(name, GFP_KERNEL); + return codec->chip_name ? 0 : -ENOMEM; +} + +static int hda_codec_driver_probe(struct device *dev) +{ + struct hda_codec *codec = dev_to_hda_codec(dev); + struct module *owner = dev->driver->owner; + int err; + + if (WARN_ON(!codec->preset)) + return -EINVAL; + + err = codec_refresh_name(codec, codec->preset->name); + if (err < 0) + goto error; + + if (!try_module_get(owner)) { + err = -EINVAL; + goto error; + } + + err = codec->preset->patch(codec); + if (err < 0) { + module_put(owner); + goto error; + } + + return 0; + + error: + codec->preset = NULL; + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); + return err; +} + +static int hda_codec_driver_remove(struct device *dev) +{ + struct hda_codec *codec = dev_to_hda_codec(dev); + + if (codec->patch_ops.free) + codec->patch_ops.free(codec); + codec->preset = NULL; + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); + module_put(dev->driver->owner); + return 0; +} + +int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, + struct module *owner) +{ + drv->driver.name = name; + drv->driver.owner = owner; + drv->driver.bus = &snd_hda_bus_type; + drv->driver.probe = hda_codec_driver_probe; + drv->driver.remove = hda_codec_driver_remove; + /* TODO: PM and others */ + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(__hda_codec_driver_register); + +void hda_codec_driver_unregister(struct hda_codec_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(hda_codec_driver_unregister); + +static inline bool codec_probed(struct hda_codec *codec) +{ + return device_attach(hda_codec_dev(codec)) > 0 && codec->preset; +} + +/* try to auto-load and bind the codec module */ +static void codec_bind_module(struct hda_codec *codec) +{ +#ifdef MODULE + request_module("snd-hda-codec-id:%08x", codec->vendor_id); + if (codec_probed(codec)) + return; + request_module("snd-hda-codec-id:%04x*", + (codec->vendor_id >> 16) & 0xffff); + if (codec_probed(codec)) + return; +#endif +} + +/* store the codec vendor name */ +static int get_codec_vendor_name(struct hda_codec *codec) +{ + const struct hda_vendor_id *c; + const char *vendor = NULL; + u16 vendor_id = codec->vendor_id >> 16; + char tmp[16]; + + for (c = hda_vendor_ids; c->id; c++) { + if (c->id == vendor_id) { + vendor = c->name; + break; + } + } + if (!vendor) { + sprintf(tmp, "Generic %04x", vendor_id); + vendor = tmp; + } + codec->vendor_name = kstrdup(vendor, GFP_KERNEL); + if (!codec->vendor_name) + return -ENOMEM; + return 0; +} + +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) +/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ +static bool is_likely_hdmi_codec(struct hda_codec *codec) +{ + hda_nid_t nid = codec->start_nid; + int i; + + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + switch (get_wcaps_type(wcaps)) { + case AC_WID_AUD_IN: + return false; /* HDMI parser supports only HDMI out */ + case AC_WID_AUD_OUT: + if (!(wcaps & AC_WCAP_DIGITAL)) + return false; + break; + } + } + return true; +} +#else +/* no HDMI codec parser support */ +#define is_likely_hdmi_codec(codec) false +#endif /* CONFIG_SND_HDA_CODEC_HDMI */ + +static int codec_bind_generic(struct hda_codec *codec) +{ + if (codec->probe_id) + return -ENODEV; + + if (is_likely_hdmi_codec(codec)) { + codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI; +#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) + request_module("snd-hda-codec-hdmi"); +#endif + if (codec_probed(codec)) + return 0; + } + + codec->probe_id = HDA_CODEC_ID_GENERIC; +#if IS_MODULE(CONFIG_SND_HDA_GENERIC) + request_module("snd-hda-codec-generic"); +#endif + if (codec_probed(codec)) + return 0; + return -ENODEV; +} + +#if IS_ENABLED(CONFIG_SND_HDA_GENERIC) +#define is_generic_config(codec) \ + (codec->modelname && !strcmp(codec->modelname, "generic")) +#else +#define is_generic_config(codec) 0 +#endif + +/** + * snd_hda_codec_configure - (Re-)configure the HD-audio codec + * @codec: the HDA codec + * + * Start parsing of the given codec tree and (re-)initialize the whole + * patch instance. + * + * Returns 0 if successful or a negative error code. + */ +int snd_hda_codec_configure(struct hda_codec *codec) +{ + int err; + + if (!codec->vendor_name) { + err = get_codec_vendor_name(codec); + if (err < 0) + return err; + } + + if (is_generic_config(codec)) + codec->probe_id = HDA_CODEC_ID_GENERIC; + else + codec->probe_id = 0; + + err = device_add(hda_codec_dev(codec)); + if (err < 0) + return err; + + if (!codec->preset) + codec_bind_module(codec); + if (!codec->preset) { + err = codec_bind_generic(codec); + if (err < 0) { + codec_err(codec, "Unable to bind the codec\n"); + goto error; + } + } + + /* audio codec should override the mixer name */ + if (codec->afg || !*codec->bus->card->mixername) + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); + return 0; + + error: + device_del(hda_codec_dev(codec)); + return err; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_configure); + +/* + * bus registration + */ +struct bus_type snd_hda_bus_type = { + .name = "hdaudio", + .match = hda_bus_match, +}; + +static int __init hda_codec_init(void) +{ + return bus_register(&snd_hda_bus_type); +} + +static void __exit hda_codec_exit(void) +{ + bus_unregister(&snd_hda_bus_type); +} + +module_init(hda_codec_init); +module_exit(hda_codec_exit); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5e755eb6f19a..61c8174e8013 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -40,69 +40,6 @@ #define CREATE_TRACE_POINTS #include "hda_trace.h" -/* - * vendor / preset table - */ - -struct hda_vendor_id { - unsigned int id; - const char *name; -}; - -/* codec vendor labels */ -static struct hda_vendor_id hda_vendor_ids[] = { - { 0x1002, "ATI" }, - { 0x1013, "Cirrus Logic" }, - { 0x1057, "Motorola" }, - { 0x1095, "Silicon Image" }, - { 0x10de, "Nvidia" }, - { 0x10ec, "Realtek" }, - { 0x1102, "Creative" }, - { 0x1106, "VIA" }, - { 0x111d, "IDT" }, - { 0x11c1, "LSI" }, - { 0x11d4, "Analog Devices" }, - { 0x13f6, "C-Media" }, - { 0x14f1, "Conexant" }, - { 0x17e8, "Chrontel" }, - { 0x1854, "LG" }, - { 0x1aec, "Wolfson Microelectronics" }, - { 0x1af4, "QEMU" }, - { 0x434d, "C-Media" }, - { 0x8086, "Intel" }, - { 0x8384, "SigmaTel" }, - {} /* terminator */ -}; - -static DEFINE_MUTEX(preset_mutex); -static LIST_HEAD(hda_preset_tables); - -/** - * snd_hda_add_codec_preset - Add a codec preset to the chain - * @preset: codec preset table to add - */ -int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) -{ - mutex_lock(&preset_mutex); - list_add_tail(&preset->list, &hda_preset_tables); - mutex_unlock(&preset_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); - -/** - * snd_hda_delete_codec_preset - Delete a codec preset from the chain - * @preset: codec preset table to delete - */ -int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) -{ - mutex_lock(&preset_mutex); - list_del(&preset->list); - mutex_unlock(&preset_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); - #ifdef CONFIG_PM #define codec_in_pm(codec) ((codec)->in_pm) static void hda_power_work(struct work_struct *work); @@ -885,111 +822,6 @@ int snd_hda_bus_new(struct snd_card *card, } EXPORT_SYMBOL_GPL(snd_hda_bus_new); -#if IS_ENABLED(CONFIG_SND_HDA_GENERIC) -#define is_generic_config(codec) \ - (codec->modelname && !strcmp(codec->modelname, "generic")) -#else -#define is_generic_config(codec) 0 -#endif - -#ifdef MODULE -#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ -#else -#define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ -#endif - -/* - * find a matching codec preset - */ -static const struct hda_codec_preset * -find_codec_preset(struct hda_codec *codec) -{ - struct hda_codec_preset_list *tbl; - const struct hda_codec_preset *preset; - unsigned int mod_requested = 0; - - again: - mutex_lock(&preset_mutex); - list_for_each_entry(tbl, &hda_preset_tables, list) { - if (!try_module_get(tbl->owner)) { - codec_err(codec, "cannot module_get\n"); - continue; - } - for (preset = tbl->preset; preset->id; preset++) { - u32 mask = preset->mask; - if (preset->afg && preset->afg != codec->afg) - continue; - if (preset->mfg && preset->mfg != codec->mfg) - continue; - if (!mask) - mask = ~0; - if (preset->id == (codec->vendor_id & mask) && - (!preset->rev || - preset->rev == codec->revision_id)) { - mutex_unlock(&preset_mutex); - codec->owner = tbl->owner; - return preset; - } - } - module_put(tbl->owner); - } - mutex_unlock(&preset_mutex); - - if (mod_requested < HDA_MODREQ_MAX_COUNT) { - if (!mod_requested) - request_module("snd-hda-codec-id:%08x", - codec->vendor_id); - else - request_module("snd-hda-codec-id:%04x*", - (codec->vendor_id >> 16) & 0xffff); - mod_requested++; - goto again; - } - return NULL; -} - -/* - * get_codec_name - store the codec name - */ -static int get_codec_name(struct hda_codec *codec) -{ - const struct hda_vendor_id *c; - const char *vendor = NULL; - u16 vendor_id = codec->vendor_id >> 16; - char tmp[16]; - - if (codec->vendor_name) - goto get_chip_name; - - for (c = hda_vendor_ids; c->id; c++) { - if (c->id == vendor_id) { - vendor = c->name; - break; - } - } - if (!vendor) { - sprintf(tmp, "Generic %04x", vendor_id); - vendor = tmp; - } - codec->vendor_name = kstrdup(vendor, GFP_KERNEL); - if (!codec->vendor_name) - return -ENOMEM; - - get_chip_name: - if (codec->chip_name) - return 0; - - if (codec->preset && codec->preset->name) - codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); - else { - sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); - codec->chip_name = kstrdup(tmp, GFP_KERNEL); - } - if (!codec->chip_name) - return -ENOMEM; - return 0; -} - /* * look for an AFG and MFG nodes */ @@ -1300,20 +1132,6 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) return p; } -/* - * Dynamic symbol binding for the codec parsers - */ - -#define load_parser(codec, sym) \ - ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym)) - -static void unload_parser(struct hda_codec *codec) -{ - if (codec->parser) - symbol_put_addr(codec->parser); - codec->parser = NULL; -} - /* * codec destructor */ @@ -1322,6 +1140,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) if (!codec) return; cancel_delayed_work_sync(&codec->jackpoll_work); + if (device_is_registered(hda_codec_dev(codec))) + device_del(hda_codec_dev(codec)); snd_hda_jack_tbl_clear(codec); free_init_pincfgs(codec); #ifdef CONFIG_PM @@ -1335,12 +1155,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->spdif_out); remove_conn_list(codec); codec->bus->caddr_tbl[codec->addr] = NULL; - if (codec->patch_ops.free) - codec->patch_ops.free(codec); hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ snd_hda_sysfs_clear(codec); - unload_parser(codec); - module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->vendor_name); @@ -1348,7 +1164,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) kfree(codec->modelname); kfree(codec->wcaps); codec->bus->num_codecs--; - put_device(&codec->dev); + put_device(hda_codec_dev(codec)); } static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, @@ -1360,10 +1176,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, static int snd_hda_codec_dev_register(struct snd_device *device) { struct hda_codec *codec = device->device_data; - int err = device_add(&codec->dev); - if (err < 0) - return err; snd_hda_register_beep_device(codec); return 0; } @@ -1373,7 +1186,6 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device) struct hda_codec *codec = device->device_data; snd_hda_detach_beep_device(codec); - device_del(&codec->dev); return 0; } @@ -1386,7 +1198,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) /* just free the container */ static void snd_hda_codec_dev_release(struct device *dev) { - kfree(container_of(dev, struct hda_codec, dev)); + kfree(dev_to_hda_codec(dev)); } /** @@ -1402,6 +1214,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct hda_codec **codecp) { struct hda_codec *codec; + struct device *dev; char component[31]; hda_nid_t fg; int err; @@ -1429,14 +1242,14 @@ int snd_hda_codec_new(struct hda_bus *bus, return -ENOMEM; } - device_initialize(&codec->dev); - codec->dev.parent = &bus->card->card_dev; - codec->dev.class = sound_class; - codec->dev.release = snd_hda_codec_dev_release; - codec->dev.groups = snd_hda_dev_attr_groups; - dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number, - codec_addr); - dev_set_drvdata(&codec->dev, codec); /* for sysfs */ + dev = hda_codec_dev(codec); + device_initialize(dev); + dev->parent = bus->card->dev; + dev->bus = &snd_hda_bus_type; + dev->release = snd_hda_codec_dev_release; + dev->groups = snd_hda_dev_attr_groups; + dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); + dev_set_drvdata(dev, codec); /* for sysfs */ codec->bus = bus; codec->addr = codec_addr; @@ -1587,92 +1400,6 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); - -#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) -/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ -static bool is_likely_hdmi_codec(struct hda_codec *codec) -{ - hda_nid_t nid = codec->start_nid; - int i; - - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - switch (get_wcaps_type(wcaps)) { - case AC_WID_AUD_IN: - return false; /* HDMI parser supports only HDMI out */ - case AC_WID_AUD_OUT: - if (!(wcaps & AC_WCAP_DIGITAL)) - return false; - break; - } - } - return true; -} -#else -/* no HDMI codec parser support */ -#define is_likely_hdmi_codec(codec) false -#endif /* CONFIG_SND_HDA_CODEC_HDMI */ - -/** - * snd_hda_codec_configure - (Re-)configure the HD-audio codec - * @codec: the HDA codec - * - * Start parsing of the given codec tree and (re-)initialize the whole - * patch instance. - * - * Returns 0 if successful or a negative error code. - */ -int snd_hda_codec_configure(struct hda_codec *codec) -{ - int (*patch)(struct hda_codec *) = NULL; - int err; - - codec->preset = find_codec_preset(codec); - if (!codec->vendor_name || !codec->chip_name) { - err = get_codec_name(codec); - if (err < 0) - return err; - } - - if (!is_generic_config(codec) && codec->preset) - patch = codec->preset->patch; - if (!patch) { - unload_parser(codec); /* to be sure */ - if (is_likely_hdmi_codec(codec)) { -#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) - patch = load_parser(codec, snd_hda_parse_hdmi_codec); -#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI) - patch = snd_hda_parse_hdmi_codec; -#endif - } - if (!patch) { -#if IS_MODULE(CONFIG_SND_HDA_GENERIC) - patch = load_parser(codec, snd_hda_parse_generic_codec); -#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC) - patch = snd_hda_parse_generic_codec; -#endif - } - if (!patch) { - codec_err(codec, "No codec parser is available\n"); - return -ENODEV; - } - } - - err = patch(codec); - if (err < 0) { - unload_parser(codec); - return err; - } - - /* audio codec should override the mixer name */ - if (codec->afg || !*codec->bus->card->mixername) - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), - "%s %s", codec->vendor_name, codec->chip_name); - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_codec_configure); - /* update the stream-id if changed */ static void update_pcm_stream_id(struct hda_codec *codec, struct hda_cvt_setup *p, hda_nid_t nid, @@ -2739,8 +2466,9 @@ int snd_hda_codec_reset(struct hda_codec *codec) } } snd_hda_detach_beep_device(codec); - if (codec->patch_ops.free) - codec->patch_ops.free(codec); + if (device_is_registered(hda_codec_dev(codec))) + device_del(hda_codec_dev(codec)); + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); snd_hda_jack_tbl_clear(codec); codec->proc_widget_hook = NULL; @@ -2759,9 +2487,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) codec->preset = NULL; codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; - unload_parser(codec); - module_put(codec->owner); - codec->owner = NULL; /* allow device access again */ snd_hda_unlock_devices(bus); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 96421a3b32cd..3d42717e0e65 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -174,15 +174,22 @@ struct hda_codec_preset { int (*patch)(struct hda_codec *codec); }; -struct hda_codec_preset_list { +#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101 +#define HDA_CODEC_ID_GENERIC 0x00000201 + +struct hda_codec_driver { + struct device_driver driver; const struct hda_codec_preset *preset; - struct module *owner; - struct list_head list; }; -/* initial hook */ -int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset); -int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset); +int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, + struct module *owner); +#define hda_codec_driver_register(drv) \ + __hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE) +void hda_codec_driver_unregister(struct hda_codec_driver *drv); +#define module_hda_codec_driver(drv) \ + module_driver(drv, hda_codec_driver_register, \ + hda_codec_driver_unregister) /* ops set by the preset patch */ struct hda_codec_ops { @@ -286,11 +293,10 @@ struct hda_codec { u32 vendor_id; u32 subsystem_id; u32 revision_id; + u32 probe_id; /* overridden id for probing */ /* detected preset */ const struct hda_codec_preset *preset; - struct module *owner; - int (*parser)(struct hda_codec *codec); const char *vendor_name; /* codec vendor name */ const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */ @@ -408,6 +414,11 @@ struct hda_codec { struct snd_array verbs; }; +#define dev_to_hda_codec(_dev) container_of(_dev, struct hda_codec, dev) +#define hda_codec_dev(_dev) (&(_dev)->dev) + +extern struct bus_type snd_hda_bus_type; + /* direction */ enum { HDA_INPUT, HDA_OUTPUT diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b680b4ec6331..947d1a50f384 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -5493,13 +5493,11 @@ static const struct hda_codec_ops generic_patch_ops = { #endif }; -/** +/* * snd_hda_parse_generic_codec - Generic codec parser * @codec: the HDA codec - * - * This should be called from the HDA codec core. */ -int snd_hda_parse_generic_codec(struct hda_codec *codec) +static int snd_hda_parse_generic_codec(struct hda_codec *codec) { struct hda_gen_spec *spec; int err; @@ -5525,7 +5523,17 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) snd_hda_gen_free(codec); return err; } -EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec); + +static const struct hda_codec_preset snd_hda_preset_generic[] = { + { .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec }, + {} /* terminator */ +}; + +static struct hda_codec_driver generic_driver = { + .preset = snd_hda_preset_generic, +}; + +module_hda_codec_driver(generic_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic HD-audio codec parser"); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 49c08a7278c4..2f7d9646a41d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -350,12 +350,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); -/* - * generic codec parser - */ -int snd_hda_parse_generic_codec(struct hda_codec *codec); -int snd_hda_parse_hdmi_codec(struct hda_codec *codec); - /* * generic proc interface */ @@ -783,9 +777,13 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); /* */ -#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args) -#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args) -#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args) -#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args) +#define codec_err(codec, fmt, args...) \ + dev_err(hda_codec_dev(codec), fmt, ##args) +#define codec_warn(codec, fmt, args...) \ + dev_warn(hda_codec_dev(codec), fmt, ##args) +#define codec_info(codec, fmt, args...) \ + dev_info(hda_codec_dev(codec), fmt, ##args) +#define codec_dbg(codec, fmt, args...) \ + dev_dbg(hda_codec_dev(codec), fmt, ##args) #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d285904cdb64..af4c7be86c27 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1194,20 +1194,8 @@ MODULE_ALIAS("snd-hda-codec-id:11d4*"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Analog Devices HD-audio codec"); -static struct hda_codec_preset_list analog_list = { +static struct hda_codec_driver analog_driver = { .preset = snd_hda_preset_analog, - .owner = THIS_MODULE, }; -static int __init patch_analog_init(void) -{ - return snd_hda_add_codec_preset(&analog_list); -} - -static void __exit patch_analog_exit(void) -{ - snd_hda_delete_codec_preset(&analog_list); -} - -module_init(patch_analog_init) -module_exit(patch_analog_exit) +module_hda_codec_driver(analog_driver); diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 5e65999e0d8e..447302695195 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -98,20 +98,8 @@ MODULE_ALIAS("snd-hda-codec-id:1102000d"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); -static struct hda_codec_preset_list ca0110_list = { +static struct hda_codec_driver ca0110_driver = { .preset = snd_hda_preset_ca0110, - .owner = THIS_MODULE, }; -static int __init patch_ca0110_init(void) -{ - return snd_hda_add_codec_preset(&ca0110_list); -} - -static void __exit patch_ca0110_exit(void) -{ - snd_hda_delete_codec_preset(&ca0110_list); -} - -module_init(patch_ca0110_init) -module_exit(patch_ca0110_exit) +module_hda_codec_driver(ca0110_driver); diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index e0383eea9880..81991b4134cd 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4702,20 +4702,8 @@ MODULE_ALIAS("snd-hda-codec-id:11020011"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Creative Sound Core3D codec"); -static struct hda_codec_preset_list ca0132_list = { +static struct hda_codec_driver ca0132_driver = { .preset = snd_hda_preset_ca0132, - .owner = THIS_MODULE, }; -static int __init patch_ca0132_init(void) -{ - return snd_hda_add_codec_preset(&ca0132_list); -} - -static void __exit patch_ca0132_exit(void) -{ - snd_hda_delete_codec_preset(&ca0132_list); -} - -module_init(patch_ca0132_init) -module_exit(patch_ca0132_exit) +module_hda_codec_driver(ca0132_driver); diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 1589c9bcce3e..1af133933bc0 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1219,20 +1219,8 @@ MODULE_ALIAS("snd-hda-codec-id:10134213"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); -static struct hda_codec_preset_list cirrus_list = { +static struct hda_codec_driver cirrus_driver = { .preset = snd_hda_preset_cirrus, - .owner = THIS_MODULE, }; -static int __init patch_cirrus_init(void) -{ - return snd_hda_add_codec_preset(&cirrus_list); -} - -static void __exit patch_cirrus_exit(void) -{ - snd_hda_delete_codec_preset(&cirrus_list); -} - -module_init(patch_cirrus_init) -module_exit(patch_cirrus_exit) +module_hda_codec_driver(cirrus_driver); diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index c895a8f21192..617d9012e78a 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -137,20 +137,8 @@ MODULE_ALIAS("snd-hda-codec-id:434d4980"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("C-Media HD-audio codec"); -static struct hda_codec_preset_list cmedia_list = { +static struct hda_codec_driver cmedia_driver = { .preset = snd_hda_preset_cmedia, - .owner = THIS_MODULE, }; -static int __init patch_cmedia_init(void) -{ - return snd_hda_add_codec_preset(&cmedia_list); -} - -static void __exit patch_cmedia_exit(void) -{ - snd_hda_delete_codec_preset(&cmedia_list); -} - -module_init(patch_cmedia_init) -module_exit(patch_cmedia_exit) +module_hda_codec_driver(cmedia_driver); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index fd3ed18670e9..15a0a7d38c35 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1007,20 +1007,8 @@ MODULE_ALIAS("snd-hda-codec-id:14f151d7"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); -static struct hda_codec_preset_list conexant_list = { +static struct hda_codec_driver conexant_driver = { .preset = snd_hda_preset_conexant, - .owner = THIS_MODULE, }; -static int __init patch_conexant_init(void) -{ - return snd_hda_add_codec_preset(&conexant_list); -} - -static void __exit patch_conexant_exit(void) -{ - snd_hda_delete_codec_preset(&conexant_list); -} - -module_init(patch_conexant_init) -module_exit(patch_conexant_exit) +module_hda_codec_driver(conexant_driver); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b422e406a9cb..f1812aabd63e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3300,15 +3300,6 @@ static int patch_via_hdmi(struct hda_codec *codec) return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID); } -/* - * called from hda_codec.c for generic HDMI support - */ -int snd_hda_parse_hdmi_codec(struct hda_codec *codec) -{ - return patch_generic_hdmi(codec); -} -EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec); - /* * patch entries */ @@ -3373,6 +3364,8 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862883, .name = "Braswell HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, +/* special ID for generic HDMI */ +{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -3442,20 +3435,8 @@ MODULE_ALIAS("snd-hda-codec-intelhdmi"); MODULE_ALIAS("snd-hda-codec-nvhdmi"); MODULE_ALIAS("snd-hda-codec-atihdmi"); -static struct hda_codec_preset_list intel_list = { +static struct hda_codec_driver hdmi_driver = { .preset = snd_hda_preset_hdmi, - .owner = THIS_MODULE, }; -static int __init patch_hdmi_init(void) -{ - return snd_hda_add_codec_preset(&intel_list); -} - -static void __exit patch_hdmi_exit(void) -{ - snd_hda_delete_codec_preset(&intel_list); -} - -module_init(patch_hdmi_init) -module_exit(patch_hdmi_exit) +module_hda_codec_driver(hdmi_driver); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2b24a8b3dac..70808f92276a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6514,20 +6514,8 @@ MODULE_ALIAS("snd-hda-codec-id:10ec*"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek HD-audio codec"); -static struct hda_codec_preset_list realtek_list = { +static struct hda_codec_driver realtek_driver = { .preset = snd_hda_preset_realtek, - .owner = THIS_MODULE, }; -static int __init patch_realtek_init(void) -{ - return snd_hda_add_codec_preset(&realtek_list); -} - -static void __exit patch_realtek_exit(void) -{ - snd_hda_delete_codec_preset(&realtek_list); -} - -module_init(patch_realtek_init) -module_exit(patch_realtek_exit) +module_hda_codec_driver(realtek_driver); diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 3208ad69583e..38a477333321 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -319,20 +319,8 @@ MODULE_ALIAS("snd-hda-codec-id:18540018"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); -static struct hda_codec_preset_list si3054_list = { +static struct hda_codec_driver si3054_driver = { .preset = snd_hda_preset_si3054, - .owner = THIS_MODULE, }; -static int __init patch_si3054_init(void) -{ - return snd_hda_add_codec_preset(&si3054_list); -} - -static void __exit patch_si3054_exit(void) -{ - snd_hda_delete_codec_preset(&si3054_list); -} - -module_init(patch_si3054_init) -module_exit(patch_si3054_exit) +module_hda_codec_driver(si3054_driver); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 87eff3173ce9..6a2163056216 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5091,20 +5091,8 @@ MODULE_ALIAS("snd-hda-codec-id:111d*"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); -static struct hda_codec_preset_list sigmatel_list = { +static struct hda_codec_driver sigmatel_driver = { .preset = snd_hda_preset_sigmatel, - .owner = THIS_MODULE, }; -static int __init patch_sigmatel_init(void) -{ - return snd_hda_add_codec_preset(&sigmatel_list); -} - -static void __exit patch_sigmatel_exit(void) -{ - snd_hda_delete_codec_preset(&sigmatel_list); -} - -module_init(patch_sigmatel_init) -module_exit(patch_sigmatel_exit) +module_hda_codec_driver(sigmatel_driver); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 3de6d3d779c9..2045f33b1ace 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1884,23 +1884,11 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { MODULE_ALIAS("snd-hda-codec-id:1106*"); -static struct hda_codec_preset_list via_list = { +static struct hda_codec_driver via_driver = { .preset = snd_hda_preset_via, - .owner = THIS_MODULE, }; MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VIA HD-audio codec"); -static int __init patch_via_init(void) -{ - return snd_hda_add_codec_preset(&via_list); -} - -static void __exit patch_via_exit(void) -{ - snd_hda_delete_codec_preset(&via_list); -} - -module_init(patch_via_init) -module_exit(patch_via_exit) +module_hda_codec_driver(via_driver); -- GitLab From 59ed1eade1d6ec24751baca99305f9713a5d779e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Feb 2015 15:39:59 +0100 Subject: [PATCH 0044/1910] ALSA: hda - Move codec suspend/resume to codec driver This patch moves the suspend/resume mechanisms down to each codec driver level, as we have a proper codec driver bound on the bus now. Then we get the asynchronous PM gratis without fiddling much in the driver level. As a soft-landing transition, implement the common suspend/resume pm ops for hda_codec_driver and keep the each codec driver intact. Only the callers of suspend/resume in the controller side (azx_suspend() and azx_resume()) are removed. Another involved place is azx_bus_reset() calling the temporary suspend and resume as a hackish method of bus reset. The HD-audio core provide a helper function snd_hda_bus_reset() instead. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_bind.c | 3 +- sound/pci/hda/hda_codec.c | 93 ++++++++++++---------------------- sound/pci/hda/hda_codec.h | 6 +-- sound/pci/hda/hda_controller.c | 11 +--- sound/pci/hda/hda_intel.c | 6 --- sound/pci/hda/hda_tegra.c | 6 --- 6 files changed, 39 insertions(+), 86 deletions(-) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index adf6b475dee1..ce2dd7b0dc07 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -138,7 +139,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, drv->driver.bus = &snd_hda_bus_type; drv->driver.probe = hda_codec_driver_probe; drv->driver.remove = hda_codec_driver_remove; - /* TODO: PM and others */ + drv->driver.pm = &hda_codec_driver_pm; return driver_register(&drv->driver); } EXPORT_SYMBOL_GPL(__hda_codec_driver_register); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 61c8174e8013..3d6ff60e6c14 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1250,6 +1250,7 @@ int snd_hda_codec_new(struct hda_bus *bus, dev->groups = snd_hda_dev_attr_groups; dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); dev_set_drvdata(dev, codec); /* for sysfs */ + device_enable_async_suspend(dev); codec->bus = bus; codec->addr = codec_addr; @@ -3970,8 +3971,31 @@ static void hda_call_codec_resume(struct hda_codec *codec) codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ } + +static int hda_codec_driver_suspend(struct device *dev) +{ + struct hda_codec *codec = dev_to_hda_codec(dev); + int i; + + cancel_delayed_work_sync(&codec->jackpoll_work); + for (i = 0; i < codec->num_pcms; i++) + snd_pcm_suspend_all(codec->pcm_info[i].pcm); + hda_call_codec_suspend(codec, false); + return 0; +} + +static int hda_codec_driver_resume(struct device *dev) +{ + hda_call_codec_resume(dev_to_hda_codec(dev)); + return 0; +} #endif /* CONFIG_PM */ +/* referred in hda_bind.c */ +const struct dev_pm_ops hda_codec_driver_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_codec_driver_suspend, + hda_codec_driver_resume) +}; /** * snd_hda_build_controls - build mixer controls @@ -5505,77 +5529,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); - -#ifdef CONFIG_PM -/* - * power management - */ - - -static void hda_async_suspend(void *data, async_cookie_t cookie) -{ - hda_call_codec_suspend(data, false); -} - -static void hda_async_resume(void *data, async_cookie_t cookie) -{ - hda_call_codec_resume(data); -} - /** - * snd_hda_suspend - suspend the codecs - * @bus: the HDA bus - * - * Returns 0 if successful. + * snd_hda_bus_reset - Reset the bus + * @bus: HD-audio bus */ -int snd_hda_suspend(struct hda_bus *bus) +void snd_hda_bus_reset(struct hda_bus *bus) { struct hda_codec *codec; - ASYNC_DOMAIN_EXCLUSIVE(domain); list_for_each_entry(codec, &bus->codec_list, list) { + /* FIXME: maybe a better way needed for forced reset */ cancel_delayed_work_sync(&codec->jackpoll_work); +#ifdef CONFIG_PM if (hda_codec_is_power_on(codec)) { - if (bus->num_codecs > 1) - async_schedule_domain(hda_async_suspend, codec, - &domain); - else - hda_call_codec_suspend(codec, false); - } - } - - if (bus->num_codecs > 1) - async_synchronize_full_domain(&domain); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_suspend); - -/** - * snd_hda_resume - resume the codecs - * @bus: the HDA bus - * - * Returns 0 if successful. - */ -int snd_hda_resume(struct hda_bus *bus) -{ - struct hda_codec *codec; - ASYNC_DOMAIN_EXCLUSIVE(domain); - - list_for_each_entry(codec, &bus->codec_list, list) { - if (bus->num_codecs > 1) - async_schedule_domain(hda_async_resume, codec, &domain); - else + hda_call_codec_suspend(codec, false); hda_call_codec_resume(codec); + } +#endif } - - if (bus->num_codecs > 1) - async_synchronize_full_domain(&domain); - - return 0; } -EXPORT_SYMBOL_GPL(snd_hda_resume); -#endif /* CONFIG_PM */ +EXPORT_SYMBOL_GPL(snd_hda_bus_reset); /* * generic arrays diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 3d42717e0e65..1fa3dd9baf52 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -567,14 +567,12 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, int snd_hda_lock_devices(struct hda_bus *bus); void snd_hda_unlock_devices(struct hda_bus *bus); +void snd_hda_bus_reset(struct hda_bus *bus); /* * power management */ -#ifdef CONFIG_PM -int snd_hda_suspend(struct hda_bus *bus); -int snd_hda_resume(struct hda_bus *bus); -#endif +extern const struct dev_pm_ops hda_codec_driver_pm; static inline int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 4c7a6f9bfcde..30ddb751806a 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1780,15 +1780,8 @@ static void azx_bus_reset(struct hda_bus *bus) bus->in_reset = 1; azx_stop_chip(chip); azx_init_chip(chip, true); -#ifdef CONFIG_PM - if (chip->initialized) { - struct azx_pcm *p; - list_for_each_entry(p, &chip->pcm_list, list) - snd_pcm_suspend_all(p->pcm); - snd_hda_suspend(chip->bus); - snd_hda_resume(chip->bus); - } -#endif + if (chip->initialized) + snd_hda_bus_reset(chip->bus); bus->in_reset = 0; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5e00cc4a722f..9db1b078801f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -772,7 +772,6 @@ static int azx_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct azx_pcm *p; if (!card) return 0; @@ -784,10 +783,6 @@ static int azx_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); - list_for_each_entry(p, &chip->pcm_list, list) - snd_pcm_suspend_all(p->pcm); - if (chip->initialized) - snd_hda_suspend(chip->bus); azx_stop_chip(chip); azx_enter_link_reset(chip); if (chip->irq >= 0) { @@ -830,7 +825,6 @@ static int azx_resume(struct device *dev) azx_init_chip(chip, true); - snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 1bd7a9e04046..f6949e413a50 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -249,14 +249,9 @@ static int hda_tegra_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - struct azx_pcm *p; struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - list_for_each_entry(p, &chip->pcm_list, list) - snd_pcm_suspend_all(p->pcm); - if (chip->initialized) - snd_hda_suspend(chip->bus); azx_stop_chip(chip); azx_enter_link_reset(chip); @@ -277,7 +272,6 @@ static int hda_tegra_resume(struct device *dev) azx_init_chip(chip, 1); - snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; -- GitLab From cc72da7d4d063ab9e690e56e0ef1ca1c24ee1635 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 16:00:22 +0100 Subject: [PATCH 0045/1910] ALSA: hda - Use standard runtime PM for codec power-save control Like the previous transition of suspend/resume, now move the power-save code to the standard runtime PM. As usual for runtime PM, it's a bit tricky, but this simplified codes a lot in the end. For keeping the usage compatibility, power_save module option still controls the whole power-saving behavior on all codecs. The value is translated to pm_runtime_*_autosuspend() and pm_runtime_allow() / pm_runtime_forbid() calls. snd_hda_power_up() and snd_hda_power_down() are translated to pm_runtime_get_sync() and pm_runtime_put_autosuspend(), respectively. Since we can do call pm_runtime_get_sync() more reliably, the sync version is used always and snd_hda_power_up_d3wait() is dropped. Another slight difference is that snd_hda_power_up()/down() don't call runtime_pm code during the suspend/resume transition phase. Calling them there isn't safe unlike our own code, resulted in unexpected behavior (endless wakeups). The hda_power_count tracepoint was removed, as it doesn't match well with the new code. Last but not least, we need to set ignore_children flag in the parent dev.power field so that the runtime PM of the controller chip won't get confused. The notification is still done in the bus pm_notify callback. We'll get rid of this hack in the later patch. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 241 +++++++++++++-------------------- sound/pci/hda/hda_codec.h | 67 +-------- sound/pci/hda/hda_controller.c | 2 +- sound/pci/hda/hda_intel.c | 2 + sound/pci/hda/hda_trace.h | 24 ---- 5 files changed, 106 insertions(+), 230 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3d6ff60e6c14..d0dbc62c9147 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include "hda_codec.h" #include @@ -41,10 +43,9 @@ #include "hda_trace.h" #ifdef CONFIG_PM -#define codec_in_pm(codec) ((codec)->in_pm) -static void hda_power_work(struct work_struct *work); -static void hda_keep_power_on(struct hda_codec *codec); -#define hda_codec_is_power_on(codec) ((codec)->power_on) +#define codec_in_pm(codec) atomic_read(&(codec)->in_pm) +#define hda_codec_is_power_on(codec) \ + (!pm_runtime_suspended(hda_codec_dev(codec))) static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) { @@ -60,7 +61,6 @@ static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) #else #define codec_in_pm(codec) 0 -static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(codec, state) {} #endif @@ -1144,10 +1144,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) device_del(hda_codec_dev(codec)); snd_hda_jack_tbl_clear(codec); free_init_pincfgs(codec); -#ifdef CONFIG_PM - cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); -#endif list_del(&codec->list); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); @@ -1178,6 +1175,10 @@ static int snd_hda_codec_dev_register(struct snd_device *device) struct hda_codec *codec = device->device_data; snd_hda_register_beep_device(codec); + if (device_is_registered(hda_codec_dev(codec))) { + snd_hda_power_sync(codec); + pm_runtime_enable(hda_codec_dev(codec)); + } return 0; } @@ -1274,13 +1275,14 @@ int snd_hda_codec_new(struct hda_bus *bus, codec->fixup_id = HDA_FIXUP_ID_NOT_SET; #ifdef CONFIG_PM - spin_lock_init(&codec->power_lock); - INIT_DELAYED_WORK(&codec->power_work, hda_power_work); /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. * the caller has to power down appropriatley after initialization * phase. */ - hda_keep_power_on(codec); + pm_runtime_set_active(hda_codec_dev(codec)); + pm_runtime_get_noresume(hda_codec_dev(codec)); + codec->power_jiffies = jiffies; + hda_call_pm_notify(codec, true); #endif snd_hda_sysfs_init(codec); @@ -2453,10 +2455,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) /* OK, let it free */ cancel_delayed_work_sync(&codec->jackpoll_work); -#ifdef CONFIG_PM - cancel_delayed_work_sync(&codec->power_work); flush_workqueue(bus->workq); -#endif snd_hda_ctls_clear(codec); /* release PCMs */ for (i = 0; i < codec->num_pcms; i++) { @@ -3893,31 +3892,40 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif #ifdef CONFIG_PM +/* update the power on/off account with the current jiffies */ +static void update_power_acct(struct hda_codec *codec, bool on) +{ + unsigned long delta = jiffies - codec->power_jiffies; + + if (on) + codec->power_on_acct += delta; + else + codec->power_off_acct += delta; + codec->power_jiffies += delta; +} + +void snd_hda_update_power_acct(struct hda_codec *codec) +{ + update_power_acct(codec, hda_codec_is_power_on(codec)); +} + /* * call suspend and power-down; used both from PM and power-save * this function returns the power state in the end */ -static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) +static unsigned int hda_call_codec_suspend(struct hda_codec *codec) { unsigned int state; - codec->in_pm = 1; + atomic_inc(&codec->in_pm); if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); state = hda_set_power_state(codec, AC_PWRST_D3); - /* Cancel delayed work if we aren't currently running from it. */ - if (!in_wq) - cancel_delayed_work_sync(&codec->power_work); - spin_lock(&codec->power_lock); - snd_hda_update_power_acct(codec); trace_hda_power_down(codec); - codec->power_on = 0; - codec->power_transition = 0; - codec->power_jiffies = jiffies; - spin_unlock(&codec->power_lock); - codec->in_pm = 0; + update_power_acct(codec, true); + atomic_dec(&codec->in_pm); return state; } @@ -3942,14 +3950,14 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec) */ static void hda_call_codec_resume(struct hda_codec *codec) { - codec->in_pm = 1; + atomic_inc(&codec->in_pm); + trace_hda_power_up(codec); hda_mark_cmd_cache_dirty(codec); - /* set as if powered on for avoiding re-entering the resume - * in the resume / power-save sequence - */ - hda_keep_power_on(codec); + codec->power_jiffies = jiffies; + hda_call_pm_notify(codec, true); + hda_set_power_state(codec, AC_PWRST_D0); restore_shutup_pins(codec); hda_exec_init_verbs(codec); @@ -3967,34 +3975,38 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_jackpoll_work(&codec->jackpoll_work.work); else snd_hda_jack_report_sync(codec); - - codec->in_pm = 0; - snd_hda_power_down(codec); /* flag down before returning */ + atomic_dec(&codec->in_pm); } -static int hda_codec_driver_suspend(struct device *dev) +static int hda_codec_runtime_suspend(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + unsigned int state; int i; cancel_delayed_work_sync(&codec->jackpoll_work); for (i = 0; i < codec->num_pcms; i++) snd_pcm_suspend_all(codec->pcm_info[i].pcm); - hda_call_codec_suspend(codec, false); + state = hda_call_codec_suspend(codec); + if (!codec->bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) + hda_call_pm_notify(codec, false); return 0; } -static int hda_codec_driver_resume(struct device *dev) +static int hda_codec_runtime_resume(struct device *dev) { hda_call_codec_resume(dev_to_hda_codec(dev)); + pm_runtime_mark_last_busy(dev); return 0; } #endif /* CONFIG_PM */ /* referred in hda_bind.c */ const struct dev_pm_ops hda_codec_driver_pm = { - SET_SYSTEM_SLEEP_PM_OPS(hda_codec_driver_suspend, - hda_codec_driver_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, + NULL) }; /** @@ -4733,127 +4745,66 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); #ifdef CONFIG_PM -static void hda_power_work(struct work_struct *work) +/** + * snd_hda_power_up - Power-up the codec + * @codec: HD-audio codec + * + * Increment the usage counter and resume the device if not done yet. + */ +void snd_hda_power_up(struct hda_codec *codec) { - struct hda_codec *codec = - container_of(work, struct hda_codec, power_work.work); - struct hda_bus *bus = codec->bus; - unsigned int state; + struct device *dev = hda_codec_dev(codec); - spin_lock(&codec->power_lock); - if (codec->power_transition > 0) { /* during power-up sequence? */ - spin_unlock(&codec->power_lock); + if (codec_in_pm(codec)) return; - } - if (!codec->power_on || codec->power_count) { - codec->power_transition = 0; - spin_unlock(&codec->power_lock); - return; - } - spin_unlock(&codec->power_lock); - - state = hda_call_codec_suspend(codec, true); - if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) - hda_call_pm_notify(codec, false); + pm_runtime_get_sync(dev); } +EXPORT_SYMBOL_GPL(snd_hda_power_up); -static void hda_keep_power_on(struct hda_codec *codec) +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the usage counter and schedules the autosuspend if none used. + */ +void snd_hda_power_down(struct hda_codec *codec) { - spin_lock(&codec->power_lock); - codec->power_count++; - codec->power_on = 1; - codec->power_jiffies = jiffies; - spin_unlock(&codec->power_lock); - hda_call_pm_notify(codec, true); -} + struct device *dev = hda_codec_dev(codec); -/* update the power on/off account with the current jiffies */ -void snd_hda_update_power_acct(struct hda_codec *codec) -{ - unsigned long delta = jiffies - codec->power_jiffies; - if (codec->power_on) - codec->power_on_acct += delta; - else - codec->power_off_acct += delta; - codec->power_jiffies += delta; -} - -/* Transition to powered up, if wait_power_down then wait for a pending - * transition to D3 to complete. A pending D3 transition is indicated - * with power_transition == -1. */ -/* call this with codec->power_lock held! */ -static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) -{ - /* Return if power_on or transitioning to power_on, unless currently - * powering down. */ - if ((codec->power_on || codec->power_transition > 0) && - !(wait_power_down && codec->power_transition < 0)) + if (codec_in_pm(codec)) return; - spin_unlock(&codec->power_lock); - - cancel_delayed_work_sync(&codec->power_work); - - spin_lock(&codec->power_lock); - /* If the power down delayed work was cancelled above before starting, - * then there is no need to go through power up here. - */ - if (codec->power_on) { - if (codec->power_transition < 0) - codec->power_transition = 0; - return; - } - - trace_hda_power_up(codec); - snd_hda_update_power_acct(codec); - codec->power_on = 1; - codec->power_jiffies = jiffies; - codec->power_transition = 1; /* avoid reentrance */ - spin_unlock(&codec->power_lock); - - hda_call_codec_resume(codec); - - spin_lock(&codec->power_lock); - codec->power_transition = 0; -} - -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) - -/* Transition to powered down */ -static void __snd_hda_power_down(struct hda_codec *codec) -{ - if (!codec->power_on || codec->power_count || codec->power_transition) - return; - - if (power_save(codec)) { - codec->power_transition = -1; /* avoid reentrance */ - queue_delayed_work(codec->bus->workq, &codec->power_work, - msecs_to_jiffies(power_save(codec) * 1000)); - } + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } +EXPORT_SYMBOL_GPL(snd_hda_power_down); /** - * snd_hda_power_save - Power-up/down/sync the codec + * snd_hda_power_sync - Synchronize the power_save option * @codec: HD-audio codec - * @delta: the counter delta to change - * @d3wait: sync for D3 transition complete * - * Change the power-up counter via @delta, and power up or down the hardware - * appropriately. For the power-down, queue to the delayed action. - * Passing zero to @delta means to synchronize the power state. + * Synchronize the runtime PM autosuspend state from the power_save option. */ -void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) +void snd_hda_power_sync(struct hda_codec *codec) { - spin_lock(&codec->power_lock); - codec->power_count += delta; - trace_hda_power_count(codec); - if (delta > 0) - __snd_hda_power_up(codec, d3wait); - else - __snd_hda_power_down(codec); - spin_unlock(&codec->power_lock); + struct device *dev = hda_codec_dev(codec); + int delay; + + if (!codec->bus->power_save) + return; + + delay = *codec->bus->power_save * 1000; + if (delay > 0) { + pm_runtime_set_autosuspend_delay(dev, delay); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + if (!pm_runtime_suspended(dev)) + pm_runtime_mark_last_busy(dev); + } else { + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_forbid(dev); + } } -EXPORT_SYMBOL_GPL(snd_hda_power_save); +EXPORT_SYMBOL_GPL(snd_hda_power_sync); /** * snd_hda_check_amp_list_power - Check the amp list and update the power @@ -5542,7 +5493,7 @@ void snd_hda_bus_reset(struct hda_bus *bus) cancel_delayed_work_sync(&codec->jackpoll_work); #ifdef CONFIG_PM if (hda_codec_is_power_on(codec)) { - hda_call_codec_suspend(codec, false); + hda_call_codec_suspend(codec); hda_call_codec_resume(codec); } #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1fa3dd9baf52..593956fc384b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -372,17 +372,12 @@ struct hda_codec { unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ #ifdef CONFIG_PM - unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_up_notified:1; /* PM notified to controller */ - unsigned int in_pm:1; /* suspend/resume being performed */ - int power_transition; /* power-state in transition */ - int power_count; /* current (global) power refcount */ - struct delayed_work power_work; /* delayed task for powerdown */ + atomic_t in_pm; /* suspend/resume being performed */ unsigned long power_on_acct; unsigned long power_off_acct; unsigned long power_jiffies; - spinlock_t power_lock; #endif /* filter the requested power state per nid */ @@ -595,64 +590,16 @@ const char *snd_hda_get_jack_location(u32 cfg); * power saving */ #ifdef CONFIG_PM -void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait); +void snd_hda_power_up(struct hda_codec *codec); +void snd_hda_power_down(struct hda_codec *codec); +void snd_hda_power_sync(struct hda_codec *codec); void snd_hda_update_power_acct(struct hda_codec *codec); #else -static inline void snd_hda_power_save(struct hda_codec *codec, int delta, - bool d3wait) {} +static inline void snd_hda_power_up(struct hda_codec *codec) {} +static inline void snd_hda_power_down(struct hda_codec *codec) {} +static inline void snd_hda_power_sync(struct hda_codec *codec) {} #endif -/** - * snd_hda_power_up - Power-up the codec - * @codec: HD-audio codec - * - * Increment the power-up counter and power up the hardware really when - * not turned on yet. - */ -static inline void snd_hda_power_up(struct hda_codec *codec) -{ - snd_hda_power_save(codec, 1, false); -} - -/** - * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending - * D3 transition to complete. This differs from snd_hda_power_up() when - * power_transition == -1. snd_hda_power_up sees this case as a nop, - * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers - * back up. - * @codec: HD-audio codec - * - * Cancel any power down operation hapenning on the work queue, then power up. - */ -static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) -{ - snd_hda_power_save(codec, 1, true); -} - -/** - * snd_hda_power_down - Power-down the codec - * @codec: HD-audio codec - * - * Decrement the power-up counter and schedules the power-off work if - * the counter rearches to zero. - */ -static inline void snd_hda_power_down(struct hda_codec *codec) -{ - snd_hda_power_save(codec, -1, false); -} - -/** - * snd_hda_power_sync - Synchronize the power-save status - * @codec: HD-audio codec - * - * Synchronize the actual power state with the power account; - * called when power_save parameter is changed - */ -static inline void snd_hda_power_sync(struct hda_codec *codec) -{ - snd_hda_power_save(codec, 0, false); -} - #ifdef CONFIG_SND_HDA_PATCH_LOADER /* * patch firmware diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 30ddb751806a..522c54f94740 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -836,7 +836,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) buff_step); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, buff_step); - snd_hda_power_up_d3wait(apcm->codec); + snd_hda_power_up(apcm->codec); err = hinfo->ops.open(hinfo, apcm->codec, substream); if (err < 0) { azx_release_device(azx_dev); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9db1b078801f..26510e60cbe2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1087,6 +1087,7 @@ static int azx_free(struct azx *chip) azx_stop_chip(chip); } + pci->dev.power.ignore_children = 0; /* FIXME */ if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); if (chip->msi) @@ -1796,6 +1797,7 @@ static int azx_probe(struct pci_dev *pci, return err; } + pci->dev.power.ignore_children = 1; /* FIXME */ err = azx_create(card, pci, dev, pci_id->driver_data, &pci_hda_ops, &chip); if (err < 0) diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h index 3a1c63161eb1..c0e1c7d24dbe 100644 --- a/sound/pci/hda/hda_trace.h +++ b/sound/pci/hda/hda_trace.h @@ -87,30 +87,6 @@ DEFINE_EVENT(hda_power, hda_power_up, TP_PROTO(struct hda_codec *codec), TP_ARGS(codec) ); - -TRACE_EVENT(hda_power_count, - TP_PROTO(struct hda_codec *codec), - TP_ARGS(codec), - TP_STRUCT__entry( - __field( unsigned int, card ) - __field( unsigned int, addr ) - __field( int, power_count ) - __field( int, power_on ) - __field( int, power_transition ) - ), - - TP_fast_assign( - __entry->card = (codec)->bus->card->number; - __entry->addr = (codec)->addr; - __entry->power_count = (codec)->power_count; - __entry->power_on = (codec)->power_on; - __entry->power_transition = (codec)->power_transition; - ), - - TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d", - __entry->card, __entry->addr, __entry->power_count, - __entry->power_on, __entry->power_transition) -); #endif /* CONFIG_PM */ TRACE_EVENT(hda_unsol_event, -- GitLab From 052a9f698268e606ca01eb1ce2a672e548f2ce11 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Mon, 9 Feb 2015 00:18:11 -0800 Subject: [PATCH 0046/1910] ALSA: Add params_set_format helper Add a helper to set pcm format directly from params Signed-off-by: Fang, Yang A Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/pcm_params.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 3c45f3924ba7..c704357775fc 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) return snd_pcm_format_physical_width(params_format(p)); } +static inline void +params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) +{ + snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), + (__force int)fmt); +} + #endif /* __SOUND_PCM_PARAMS_H */ -- GitLab From 369a9f5f397fe3258ab937ec7a9c2229d0b1a015 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Mon, 9 Feb 2015 00:18:12 -0800 Subject: [PATCH 0047/1910] ASoC: Intel: fix machine driver warnings this patch will fix below sparse warnings warning: incorrect type in argument 2 (different base types) expected unsigned int [unsigned] val got restricted snd_pcm_format_t [usertype] sound/soc/intel/haswell.c:61:37 sound/soc/intel/broadwell.c:115:37: sound/soc/intel/bytcr_dpcm_rt5640.c:118:37: sound/soc/intel/cht_bsw_rt5672.c:183:37: sound/soc/intel/cht_bsw_rt5645.c:208:37: Signed-off-by: Fang, Yang A Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/broadwell.c | 4 +--- sound/soc/intel/bytcr_dpcm_rt5640.c | 4 +--- sound/soc/intel/cht_bsw_rt5645.c | 4 +--- sound/soc/intel/cht_bsw_rt5672.c | 4 +--- sound/soc/intel/haswell.c | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 9cf7d01479ad..fba2ef5dac42 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -110,9 +110,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP0 to 16 bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S16_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index 59308629043e..3b262d01c1b3 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c @@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index bd29617a9ab9..dd935255a020 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index ff016621583a..c56f9dfe2129 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP2 to 24-bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S24_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 35edf51a52aa..00fddd3f5dfb 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c @@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = 2; /* set SSP0 to 16 bit */ - snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - - SNDRV_PCM_HW_PARAM_FIRST_MASK], - SNDRV_PCM_FORMAT_S16_LE); + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); return 0; } -- GitLab From 48c7699fb2c799d084ce490bceea14fe04ad12a1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:53 +0530 Subject: [PATCH 0048/1910] ASoC: core: allow pcms to be registered as nonatomic ALSA core with commit 257f8cce5d40 - "ALSA: pcm: Allow nonatomic trigger operations" allows trigger ops to implemented as nonatomic. For ASoC, we can specify this in dailinks and is updated while snd_pcm is created Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Cc: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-pcm.c | 1 + 2 files changed, 4 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..76bc944dcb5c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -954,6 +954,9 @@ struct snd_soc_dai_link { unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; + /* Mark this pcm with non atomic ops */ + bool nonatomic; + /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6b0136e7cb88..6e3781e88f9a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2511,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; -- GitLab From 76ca1c2cd8fc0b8764c6360263e2fbca43495ab2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:54 +0530 Subject: [PATCH 0049/1910] ASoC: Intel: mark cht machine driver with nonatomic trigger The DSP messages are sent with nonatomic context, which include trigger messages, so mark the driver as nonatomic Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index c56f9dfe2129..a5098d6f988b 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -216,6 +216,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", .ignore_suspend = 1, + .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, @@ -238,6 +239,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .cpu_dai_name = "ssp2-port", .platform_name = "sst-mfld-platform", .no_pcm = 1, + .nonatomic = true, .codec_dai_name = "rt5670-aif1", .codec_name = "i2c-10EC5670:00", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF -- GitLab From 7b9ca9d7e561ebdc93b43277eb69d20a0dc8f5cd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:55 +0530 Subject: [PATCH 0050/1910] ASoC: Intel: update MMX ID to 3 The updated firmware expects the MMX ID to be used as 3, so update the driver as well Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-atom-controls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index dfebfdd5eb2a..daecc58f28af 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -150,7 +150,7 @@ enum sst_cmd_type { enum sst_task { SST_TASK_SBA = 1, - SST_TASK_MMX, + SST_TASK_MMX = 3, }; enum sst_type { -- GitLab From e0b87d476bc13fc55e7000a84cd1d87c8fdc1f2f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:56 +0530 Subject: [PATCH 0051/1910] ASoC: Intel: add support for pause and resume in sst This adds missing pcm pause and resume ops in the driver Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst_drv_interface.c | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 5f75ef3cdd22..5d56fcdd58d8 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -572,6 +572,35 @@ static int sst_stream_drop(struct device *dev, int str_id) return sst_drop_stream(ctx, str_id); } +static int sst_stream_pause(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + + return sst_pause_stream(ctx, str_id); +} + +static int sst_stream_resume(struct device *dev, int str_id) +{ + struct stream_info *str_info; + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->sst_state != SST_FW_RUNNING) + return 0; + + str_info = get_stream_info(ctx, str_id); + if (!str_info) + return -EINVAL; + return sst_resume_stream(ctx, str_id); +} + static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) { int str_id = 0; @@ -633,6 +662,8 @@ static struct sst_ops pcm_ops = { .stream_init = sst_stream_init, .stream_start = sst_stream_start, .stream_drop = sst_stream_drop, + .stream_pause = sst_stream_pause, + .stream_pause_release = sst_stream_resume, .stream_read_tstamp = sst_read_timestamp, .send_byte_stream = sst_send_byte_stream, .close = sst_close_pcm_stream, -- GitLab From fc9406ab9b4a9aac0ab9ad213993824cbe9c65ac Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:57 +0530 Subject: [PATCH 0052/1910] ASoC: Intel: add support for pcm stream suspend/resume The driver didn't implement support for pcm stream suspend and resume, so add it Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7523cbef8780..ea0fa4b90bb0 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; ret_val = stream->ops->stream_pause_release(sst->dev, str_id); -- GitLab From 54e6beccc67129c474aad7578951112c6cf28e01 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 12 Feb 2015 09:59:58 +0530 Subject: [PATCH 0053/1910] ASoC: Intel: add support for platform suspend This adds support for platform suspend and resume. We ensure all pcms are suspended by invoking snd_soc_suspend() and then stop the DSP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 58 +++++++++++++++++++++++++ sound/soc/intel/sst-mfld-platform.h | 1 + 2 files changed, 59 insertions(+) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index ea0fa4b90bb0..2fbaf2c75d17 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -667,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) static int sst_soc_probe(struct snd_soc_platform *platform) { + struct sst_data *drv = dev_get_drvdata(platform->dev); + + drv->soc_card = platform->component.card; return sst_dsp_init_v2_dpcm(platform); } @@ -729,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int sst_soc_prepare(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* suspend all pcms first */ + snd_soc_suspend(drv->soc_card->dev); + snd_soc_poweroff(drv->soc_card->dev); + + /* set the SSPs to idle */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + send_ssp_cmd(dai, dai->name, 0); + sst_handle_vb_timer(dai, false); + } + } + + return 0; +} + +static void sst_soc_complete(struct device *dev) +{ + struct sst_data *drv = dev_get_drvdata(dev); + int i; + + /* restart SSPs */ + for (i = 0; i < drv->soc_card->num_rtd; i++) { + struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + + if (dai->active) { + sst_handle_vb_timer(dai, true); + send_ssp_cmd(dai, dai->name, 1); + } + } + snd_soc_resume(drv->soc_card->dev); +} + +#else + +#define sst_soc_prepare NULL +#define sst_soc_complete NULL + +#endif + + +static const struct dev_pm_ops sst_platform_pm = { + .prepare = sst_soc_prepare, + .complete = sst_soc_complete, +}; + static struct platform_driver sst_platform_driver = { .driver = { .name = "sst-mfld-platform", + .pm = &sst_platform_pm, }, .probe = sst_platform_probe, .remove = sst_platform_remove, diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 79c8d1246a8f..9094314be2b0 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -174,6 +174,7 @@ struct sst_data { struct sst_platform_data *pdata; struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; + struct snd_soc_card *soc_card; }; int sst_register_dsp(struct sst_device *sst); int sst_unregister_dsp(struct sst_device *sst); -- GitLab From 5c88b4e91d3b6a3d701d7b134fa945e6309e7068 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 12 Feb 2015 10:00:01 +0530 Subject: [PATCH 0054/1910] ASoC: Intel: Add memcpy32_fromio as well Export 32-bit version of memcpy for use in suspend/resume. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst.h | 3 +++ sound/soc/intel/sst/sst_loader.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 562bc483d6b7..f793780a50a2 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -544,4 +544,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, int sst_context_init(struct intel_sst_drv *ctx); void sst_context_cleanup(struct intel_sst_drv *ctx); void sst_configure_runtime_pm(struct intel_sst_drv *ctx); +void memcpy32_toio(void __iomem *dst, const void *src, int count); +void memcpy32_fromio(void *dst, const void __iomem *src, int count); + #endif diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index 7888cd707853..e88907ae8b15 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -39,7 +39,15 @@ #include "sst.h" #include "../sst-dsp.h" -static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) +void memcpy32_toio(void __iomem *dst, const void *src, int count) +{ + /* __iowrite32_copy uses 32-bit count values so divide by 4 for + * right count in words + */ + __iowrite32_copy(dst, src, count/4); +} + +void memcpy32_fromio(void *dst, const void __iomem *src, int count) { /* __iowrite32_copy uses 32-bit count values so divide by 4 for * right count in words -- GitLab From 4a8448d4289d7210053a43f9f21e42929beb159b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 24 Feb 2015 11:39:44 +0530 Subject: [PATCH 0055/1910] ASoC: Intel: add pm support in sst ipc driver This adds support for system pm support. We need to save the dsp memory which gets lost on suspend and restore that on resume Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst.c | 128 ++++++++++++++++++++++++++++++++++++++ sound/soc/intel/sst/sst.h | 9 +++ 2 files changed, 137 insertions(+) diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 8a8d56a146e7..8f938112a01f 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -415,6 +415,83 @@ static int intel_sst_runtime_suspend(struct device *dev) return ret; } +static int intel_sst_suspend(struct device *dev) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save; + int i, ret = 0; + + /* check first if we are already in SW reset */ + if (ctx->sst_state == SST_RESET) + return 0; + + /* + * check if any stream is active and running + * they should already by suspend by soc_suspend + */ + for (i = 1; i <= ctx->info.max_streams; i++) { + struct stream_info *stream = &ctx->streams[i]; + + if (stream->status == STREAM_RUNNING) { + dev_err(dev, "stream %d is running, cant susupend, abort\n", i); + return -EBUSY; + } + } + synchronize_irq(ctx->irq_num); + flush_workqueue(ctx->post_msg_wq); + + /* Move the SST state to Reset */ + sst_set_fw_state_locked(ctx, SST_RESET); + + /* tell DSP we are suspending */ + if (ctx->ops->save_dsp_context(ctx)) + return -EBUSY; + + /* save the memories */ + fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); + if (!fw_save) + return -ENOMEM; + fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); + if (!fw_save->iram) { + ret = -ENOMEM; + goto iram; + } + fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); + if (!fw_save->dram) { + ret = -ENOMEM; + goto dram; + } + fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + if (!fw_save->sram) { + ret = -ENOMEM; + goto sram; + } + + fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); + if (!fw_save->ddr) { + ret = -ENOMEM; + goto ddr; + } + + memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base); + memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base); + memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE); + memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base); + + ctx->fw_save = fw_save; + ctx->ops->reset(ctx); + return 0; +ddr: + kfree(fw_save->sram); +sram: + kfree(fw_save->dram); +dram: + kfree(fw_save->iram); +iram: + kfree(fw_save); + return ret; +} + static int intel_sst_runtime_resume(struct device *dev) { int ret = 0; @@ -430,7 +507,58 @@ static int intel_sst_runtime_resume(struct device *dev) return ret; } +static int intel_sst_resume(struct device *dev) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + struct sst_fw_save *fw_save = ctx->fw_save; + int ret = 0; + struct sst_block *block; + + if (!fw_save) + return intel_sst_runtime_resume(dev); + + sst_set_fw_state_locked(ctx, SST_FW_LOADING); + + /* we have to restore the memory saved */ + ctx->ops->reset(ctx); + + ctx->fw_save = NULL; + + memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base); + memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base); + memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); + memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); + + kfree(fw_save->sram); + kfree(fw_save->dram); + kfree(fw_save->iram); + kfree(fw_save->ddr); + kfree(fw_save); + + block = sst_create_block(ctx, 0, FW_DWNL_ID); + if (block == NULL) + return -ENOMEM; + + + /* start and wait for ack */ + ctx->ops->start(ctx); + ret = sst_wait_timeout(ctx, block); + if (ret) { + dev_err(ctx->dev, "fw download failed %d\n", ret); + /* FW download failed due to timeout */ + ret = -EBUSY; + + } else { + sst_set_fw_state_locked(ctx, SST_FW_RUNNING); + } + + sst_free_block(ctx, block); + return ret; +} + const struct dev_pm_ops intel_sst_pm = { + .suspend = intel_sst_suspend, + .resume = intel_sst_resume, .runtime_suspend = intel_sst_runtime_suspend, .runtime_resume = intel_sst_runtime_resume, }; diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index f793780a50a2..3f493862e98d 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -337,6 +337,13 @@ struct sst_shim_regs64 { u64 csr2; }; +struct sst_fw_save { + void *iram; + void *dram; + void *sram; + void *ddr; +}; + /** * struct intel_sst_drv - driver ops * @@ -428,6 +435,8 @@ struct intel_sst_drv { * persistent till worker thread gets called */ char firmware_name[FW_NAME_SIZE]; + + struct sst_fw_save *fw_save; }; /* misc definitions */ -- GitLab From 9308d1456e30e374d93957e3376a09370be9dc52 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 24 Feb 2015 11:39:45 +0530 Subject: [PATCH 0056/1910] ASoC: Intel: Move the fw download to power_control Thus removing the runtime_resume handler. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst.c | 18 +---------------- sound/soc/intel/sst/sst_drv_interface.c | 27 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 8f938112a01f..4d8f73ac5dd9 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -492,21 +492,6 @@ static int intel_sst_suspend(struct device *dev) return ret; } -static int intel_sst_runtime_resume(struct device *dev) -{ - int ret = 0; - struct intel_sst_drv *ctx = dev_get_drvdata(dev); - - if (ctx->sst_state == SST_RESET) { - ret = sst_load_fw(ctx); - if (ret) { - dev_err(dev, "FW download fail %d\n", ret); - sst_set_fw_state_locked(ctx, SST_RESET); - } - } - return ret; -} - static int intel_sst_resume(struct device *dev) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); @@ -515,7 +500,7 @@ static int intel_sst_resume(struct device *dev) struct sst_block *block; if (!fw_save) - return intel_sst_runtime_resume(dev); + return 0; sst_set_fw_state_locked(ctx, SST_FW_LOADING); @@ -560,6 +545,5 @@ const struct dev_pm_ops intel_sst_pm = { .suspend = intel_sst_suspend, .resume = intel_sst_resume, .runtime_suspend = intel_sst_runtime_suspend, - .runtime_resume = intel_sst_runtime_resume, }; EXPORT_SYMBOL_GPL(intel_sst_pm); diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 5d56fcdd58d8..549af7d7f6d0 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -138,12 +138,31 @@ int sst_get_stream(struct intel_sst_drv *ctx, static int sst_power_control(struct device *dev, bool state) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); + int ret = 0; - dev_dbg(ctx->dev, "state:%d", state); - if (state == true) - return pm_runtime_get_sync(dev); - else + if (state == true) { + ret = pm_runtime_get_sync(dev); + dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", + atomic_read(&dev->power.usage_count)); + if (ret < 0) { + dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); + return ret; + } + if ((ctx->sst_state == SST_RESET) && + (atomic_read(&dev->power.usage_count) == 1)) { + ret = sst_load_fw(ctx); + if (ret) { + dev_err(dev, "FW download fail %d\n", ret); + sst_set_fw_state_locked(ctx, SST_RESET); + ret = sst_pm_runtime_put(ctx); + } + } + } else { + dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", + atomic_read(&dev->power.usage_count)); return sst_pm_runtime_put(ctx); + } + return ret; } /* -- GitLab From 583e58a0f0e996008780fe4df0f7640890a9b69a Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 24 Feb 2015 11:39:46 +0530 Subject: [PATCH 0057/1910] ASoC: Intel: Remove ignore suspend support In our platform we want platform and codec driver routines to get invoked and don't need the machine routines so remove here Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index a5098d6f988b..67db5101bc89 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -215,7 +215,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, @@ -246,7 +245,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBS_CFS, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, -- GitLab From 3f2dcbeaeb2badb951a68e7d525ff4e55d0b0678 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 24 Feb 2015 11:39:47 +0530 Subject: [PATCH 0058/1910] ASoC: Intel: Remove soc pm handling to allow platform driver handle it Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index 67db5101bc89..bc8dcacd5e6a 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -283,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5672", - .pm = &snd_soc_pm_ops, }, .probe = snd_cht_mc_probe, }; -- GitLab From 34d7c3905adb9a9d8f8155857c76314125510817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 21 Feb 2015 16:33:24 +0100 Subject: [PATCH 0059/1910] ASoC: improve usage of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify drivers accordingly. Also there is an *_optional variant that serves well here. The sematics is slightly changed here by using it as error checking is more strict now: If GPIOLIB is not enabled an error is returned instead of just ignoring the gpio. On one hand this is bad for devices that don't "have" the respective gpio as the driver is failing now. On the other hand there is no means to assert that this gpio is really not needed or if only the driver to control it is not available. The latter is a real reason to fail and so it's defensive to fail here, too. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 17 +++++------------ sound/soc/codecs/cs35l32.c | 19 ++++++------------- sound/soc/codecs/cs4265.c | 19 ++++++------------- sound/soc/codecs/sta350.c | 30 +++++++++--------------------- sound/soc/codecs/tas2552.c | 13 +++---------- 5 files changed, 29 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 70ab35744aba..7ad8e156e2df 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->dvdd_reg = NULL; } - adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); - if (IS_ERR(adau1977->reset_gpio)) { - ret = PTR_ERR(adau1977->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return PTR_ERR(adau1977->reset_gpio); - adau1977->reset_gpio = NULL; - } + adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(adau1977->reset_gpio)) + return PTR_ERR(adau1977->reset_gpio); dev_set_drvdata(dev, adau1977); - if (adau1977->reset_gpio) { - ret = gpiod_direction_output(adau1977->reset_gpio, 0); - if (ret) - return ret; + if (adau1977->reset_gpio) ndelay(100); - } ret = adau1977_power_enable(adau1977); if (ret) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index f2b8aad21274..60598b230341 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, } /* Reset the Device */ - cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs35l32->reset_gpio)) { - ret = PTR_ERR(cs35l32->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs35l32->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs35l32->reset_gpio, 0); - if (ret) - return ret; + cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs35l32->reset_gpio)) + return PTR_ERR(cs35l32->reset_gpio); + + if (cs35l32->reset_gpio) gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); - } /* initialize codec */ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index ce6086835ebd..cac48ddf3ba6 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, return ret; } - cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev, - "reset-gpios"); - if (IS_ERR(cs4265->reset_gpio)) { - ret = PTR_ERR(cs4265->reset_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - cs4265->reset_gpio = NULL; - } else { - ret = gpiod_direction_output(cs4265->reset_gpio, 0); - if (ret) - return ret; + cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs4265->reset_gpio)) + return PTR_ERR(cs4265->reset_gpio); + + if (cs4265->reset_gpio) { mdelay(1); gpiod_set_value_cansleep(cs4265->reset_gpio, 1); - } i2c_set_clientdata(i2c_client, cs4265); diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index bda2ee18769e..669e3228241e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c, #endif /* GPIOs */ - sta350->gpiod_nreset = devm_gpiod_get(dev, "reset"); - if (IS_ERR(sta350->gpiod_nreset)) { - ret = PTR_ERR(sta350->gpiod_nreset); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_nreset = NULL; - } else { - gpiod_direction_output(sta350->gpiod_nreset, 0); - } - - sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down"); - if (IS_ERR(sta350->gpiod_power_down)) { - ret = PTR_ERR(sta350->gpiod_power_down); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - sta350->gpiod_power_down = NULL; - } else { - gpiod_direction_output(sta350->gpiod_power_down, 0); - } + sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_nreset)) + return PTR_ERR(sta350->gpiod_nreset); + + sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down", + GPIOD_OUT_LOW); + if (IS_ERR(sta350->gpiod_power_down)) + return PTR_ERR(sta350->gpiod_power_down); /* regulators */ for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index ae23acdd2708..dfb4ff5cc9ea 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client, if (data == NULL) return -ENOMEM; - data->enable_gpio = devm_gpiod_get(dev, "enable"); - if (IS_ERR(data->enable_gpio)) { - ret = PTR_ERR(data->enable_gpio); - if (ret != -ENOENT && ret != -ENOSYS) - return ret; - - data->enable_gpio = NULL; - } else { - gpiod_direction_output(data->enable_gpio, 0); - } + data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(data->enable_gpio)) + return PTR_ERR(data->enable_gpio); data->tas2552_client = client; data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); -- GitLab From 5890bd5256bc026c425361fa087dc05c7a24d853 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 16 Feb 2015 22:02:47 +0100 Subject: [PATCH 0060/1910] ASoC: pcm512x: Rearrange to not repeat dacsrc_rate / dac_div Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 9974f201a08f..f11c76f1acfe 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -863,28 +863,29 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = sck_rate; } + osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); + if (osr_div > 128) { + dev_err(dev, "Failed to find OSR divider\n"); + return -EINVAL; + } + dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate); if (dac_div > 128) { dev_err(dev, "Failed to find DAC divider\n"); return -EINVAL; } + dac_rate = dacsrc_rate / dac_div; - ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000); - if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) { + ncp_div = DIV_ROUND_CLOSEST(dac_rate, 1536000); + if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { /* run NCP no faster than 2048000 Hz, but why? */ - ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000); + ncp_div = DIV_ROUND_UP(dac_rate, 2048000); if (ncp_div > 128) { dev_err(dev, "Failed to find NCP divider\n"); return -EINVAL; } } - osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); - if (osr_div > 128) { - dev_err(dev, "Failed to find OSR divider\n"); - return -EINVAL; - } - idac = mck_rate / (dsp_div * sample_rate); ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); -- GitLab From f29933c9ae4b8f30c713186d3babb630c7cfb4f2 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 23 Feb 2015 21:03:33 +0100 Subject: [PATCH 0061/1910] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP When using non-standard rates, a relatively small amount of overclocking can make a big difference to a number of cases. - Not all rates are possible to achieve with the PLL, due to divider restrictions. - The higher oversampling rates that can be used by the DAC, the simpler the analog output filters get (mirror frequencies move up, away from the desired spectrum). - The more work the DSP can perform per sample, the better. For standard rates, there is little to gain as everything is designed just right, and the needed overclocking to make a real difference would be significant. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 161 ++++++++++++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index f11c76f1acfe..4b5f1fe9be97 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -54,6 +54,9 @@ struct pcm512x_priv { int pll_d; int pll_p; unsigned long real_pll; + unsigned long overclock_pll; + unsigned long overclock_dac; + unsigned long overclock_dsp; }; /* @@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg) } } +static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_pll; + return 0; +} + +static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_pll = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dsp; + return 0; +} + +static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dsp = ucontrol->value.integer.value[0]; + return 0; +} + +static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = pcm512x->overclock_dac; + return 0; +} + +static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); + + switch (codec->dapm.bias_level) { + case SND_SOC_BIAS_OFF: + case SND_SOC_BIAS_STANDBY: + break; + default: + return -EBUSY; + } + + pcm512x->overclock_dac = ucontrol->value.integer.value[0]; + return 0; +} + static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); @@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), + +SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0, + pcm512x_overclock_pll_get, pcm512x_overclock_pll_put), +SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put), +SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0, + pcm512x_overclock_dac_get, pcm512x_overclock_dac_put), }; static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { @@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { { "OUTR", NULL, "DACR" }, }; +static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x) +{ + return 25000000 + 25000000 * pcm512x->overclock_pll / 100; +} + +static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x) +{ + return 50000000 + 50000000 * pcm512x->overclock_dsp / 100; +} + +static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x, + unsigned long rate) +{ + return rate + rate * pcm512x->overclock_dac / 100; +} + +static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x) +{ + if (!pcm512x->pll_out) + return 25000000; + return pcm512x_pll_max(pcm512x); +} + +static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x, + unsigned long dac_rate) +{ + /* + * If the DAC is not actually overclocked, use the good old + * NCP target rate... + */ + if (dac_rate <= 6144000) + return 1536000; + /* + * ...but if the DAC is in fact overclocked, bump the NCP target + * rate to get the recommended dividers even when overclocking. + */ + return pcm512x_dac_max(pcm512x, 1536000); +} + static const u32 pcm512x_dai_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000, @@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = { static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct pcm512x_priv *pcm512x = rule->private; struct snd_interval ranges[2]; int frame_size; @@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params, */ memset(ranges, 0, sizeof(ranges)); ranges[0].min = 8000; - ranges[0].max = 25000000 / frame_size / 2; + ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2; ranges[1].min = DIV_ROUND_UP(16000000, frame_size); ranges[1].max = 384000; break; @@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, return snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, pcm512x_hw_rule_rate, - NULL, + pcm512x, SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); @@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, unsigned long bclk_rate) { struct device *dev = dai->dev; + struct snd_soc_codec *codec = dai->codec; + struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); unsigned long sck_rate; int pow2; @@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai, * as many factors of 2 as possible, as that makes it easier * to find a fast DAC rate */ - pow2 = 1 << fls((25000000 - 16000000) / bclk_rate); + pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); for (; pow2; pow2 >>= 1) { - sck_rate = rounddown(25000000, bclk_rate * pow2); + sck_rate = rounddown(pcm512x_pll_max(pcm512x), + bclk_rate * pow2); if (sck_rate >= 16000000) break; } @@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai, return 0; /* futile, quit early */ /* run DAC no faster than 6144000 Hz */ - for (dac_rate = rounddown(6144000, osr_rate); + for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate); dac_rate; dac_rate -= osr_rate) { @@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, osr_rate = 16 * sample_rate; /* run DSP no faster than 50 MHz */ - dsp_div = mck_rate > 50000000 ? 2 : 1; + dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1; dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); if (dac_rate) { @@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, dacsrc_rate = pllin_rate; } else { /* run DAC no faster than 6144000 Hz */ - unsigned long dac_mul = 6144000 / osr_rate; + unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000) + / osr_rate; unsigned long sck_mul = sck_rate / osr_rate; for (; dac_mul; dac_mul--) { @@ -876,7 +1014,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, } dac_rate = dacsrc_rate / dac_div; - ncp_div = DIV_ROUND_CLOSEST(dac_rate, 1536000); + ncp_div = DIV_ROUND_CLOSEST(dac_rate, + pcm512x_ncp_target(pcm512x, dac_rate)); if (ncp_div > 128 || dac_rate / ncp_div > 2048000) { /* run NCP no faster than 2048000 Hz, but why? */ ncp_div = DIV_ROUND_UP(dac_rate, 2048000); @@ -938,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, return ret; } - if (sample_rate <= 48000) + if (sample_rate <= pcm512x_dac_max(pcm512x, 48000)) fssp = PCM512x_FSSP_48KHZ; - else if (sample_rate <= 96000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000)) fssp = PCM512x_FSSP_96KHZ; - else if (sample_rate <= 192000) + else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000)) fssp = PCM512x_FSSP_192KHZ; else fssp = PCM512x_FSSP_384KHZ; -- GitLab From f23e860edbb3f2208c0ab3448e756689bb4a3760 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sat, 14 Feb 2015 17:22:49 -0800 Subject: [PATCH 0062/1910] ASoC: core: Add extra dapm properties for Device Tree The current helper functions, snd_soc_of_parse_audio_simple_widgets() and snd_soc_of_parse_audio_routing(), set dapm_widgets and dapm_routes without caring if they are already set by using build-in widgets and routes in the card driver. So there could be one of them, build-in one or Device Tree one, overrided by the other depending on which one was assigned later. This patch adds an extra pair of dapm_widgets and dapm_routes for DT use only so as to prevent unexpected overriding. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..f66a1ef98a40 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1071,11 +1071,16 @@ struct snd_soc_card { /* * Card-specific routes and widgets. + * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in. */ const struct snd_soc_dapm_widget *dapm_widgets; int num_dapm_widgets; const struct snd_soc_dapm_route *dapm_routes; int num_dapm_routes; + const struct snd_soc_dapm_widget *of_dapm_widgets; + int num_of_dapm_widgets; + const struct snd_soc_dapm_route *of_dapm_routes; + int num_of_dapm_routes; bool fully_routed; struct work_struct deferred_resume_work; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 30579ca5bacb..5c0658d49609 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1561,6 +1561,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, card->num_dapm_widgets); + if (card->of_dapm_widgets) + snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + /* initialise the sound card only once */ if (card->probe) { ret = card->probe(card); @@ -1616,6 +1620,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, card->num_dapm_routes); + if (card->of_dapm_routes) + snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); + for (i = 0; i < card->num_links; i++) { if (card->dai_link[i].dai_fmt) snd_soc_runtime_set_dai_fmt(&card->rtd[i], @@ -3223,8 +3231,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, widgets[i].name = wname; } - card->dapm_widgets = widgets; - card->num_dapm_widgets = num_widgets; + card->of_dapm_widgets = widgets; + card->num_of_dapm_widgets = num_widgets; return 0; } @@ -3308,8 +3316,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, } } - card->num_dapm_routes = num_routes; - card->dapm_routes = routes; + card->num_of_dapm_routes = num_routes; + card->of_dapm_routes = routes; return 0; } -- GitLab From 3185878a70e721644b0e32ebbc0a039616551949 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sat, 14 Feb 2015 17:22:50 -0800 Subject: [PATCH 0063/1910] ASoC: fsl-asoc-card: Add snd_soc_of_parse_audio_routing() This patch adds snd_soc_of_parse_audio_routing() to get dapm routes configurations via Device Tree. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 3f6959c8e2f7..de438871040b 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + goto asrc_fail; + } + /* Normal DAI Link */ priv->dai_link[0].cpu_of_node = cpu_np; priv->dai_link[0].codec_of_node = codec_np; -- GitLab From e2cef68d5903cc2052e9f6e46b323b7ead695e73 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Tue, 10 Feb 2015 17:01:56 +0800 Subject: [PATCH 0064/1910] ASoC: rt286: add jack detection disable with NULL jack passed Some platforms, e.g. WSB, don't need jack detection when system is in Suspend, for power save reason. Here add headphone/mic jack detection disable feature with NULL jack passed in, when disabled, it will disable interrupt, and disable LDO1, which is used for jack detection when headphone is plugged in. Signed-off-by: Jie Yang Reviewed-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index f374840a5a7c..16723b167fbf 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -395,9 +395,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) rt286->jack = jack; - /* Send an initial empty report */ - snd_soc_jack_report(rt286->jack, 0, - SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + if (jack) { + /* enable IRQ */ + if (rt286->jack->status | SND_JACK_HEADPHONE) + snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1"); + regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2); + /* Send an initial empty report */ + snd_soc_jack_report(rt286->jack, rt286->jack->status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + } else { + /* disable IRQ */ + regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0); + snd_soc_dapm_disable_pin(&codec->dapm, "LDO1"); + } + snd_soc_dapm_sync(&codec->dapm); return 0; } -- GitLab From ed97604e362c67fb5410ce2cbe8769b818cdc0af Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 6 Feb 2015 08:04:00 -0800 Subject: [PATCH 0065/1910] leds: leds-pwm: drop one pwm_get_period() call pwm_get_period() is called twice in case the child parameter is set. I assume retrieving this parameter once is enough therefore this patch removes the conditial invocation of pwm_get_period(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Bryan Wu --- drivers/leds/leds-pwm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index f668500a2157..1d07e3e83d29 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -121,9 +121,6 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, return ret; } - if (child) - led_data->period = pwm_get_period(led_data->pwm); - led_data->can_sleep = pwm_can_sleep(led_data->pwm); if (led_data->can_sleep) INIT_WORK(&led_data->work, led_pwm_work); -- GitLab From 0c571785813cf3294cdbb1f2fb1a9b19e11935f6 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Fri, 13 Feb 2015 08:06:47 -0800 Subject: [PATCH 0066/1910] leds: flash: remove stray include directive Avoid including v4l2-controls.h, as this is stray code from the early versions of the LED / V4L2 flash API integration patches. LED Flash class doesn't depend on V4L2 subsystem. Signed-off-by: Jacek Anaszewski Signed-off-by: Bryan Wu --- include/linux/led-class-flash.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/led-class-flash.h b/include/linux/led-class-flash.h index 5ba2facd7a51..3b5b9643cea1 100644 --- a/include/linux/led-class-flash.h +++ b/include/linux/led-class-flash.h @@ -13,7 +13,6 @@ #define __LINUX_FLASH_LEDS_H_INCLUDED #include -#include struct device_node; struct led_classdev_flash; -- GitLab From 4980bdf0213c9b5f876551b2ceb8ed8ece30deaf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 3 Dec 2014 15:55:49 +0900 Subject: [PATCH 0067/1910] kconfig: fix a misspelling in scripts/kconfig/merge_config.sh Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/kconfig/merge_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index 2ab91b9b100d..2118af84e661 100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -92,7 +92,7 @@ TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) echo "Using $INITFILE as base" cat $INITFILE > $TMP_FILE -# Merge files, printing warnings on overrided values +# Merge files, printing warnings on overridden values for MERGE_FILE in $MERGE_LIST ; do echo "Merging $MERGE_FILE" CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) -- GitLab From 70529b1a1784503169416df19ce3d68746401340 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 27 Jan 2015 17:11:42 +0100 Subject: [PATCH 0068/1910] kconfig: Get rid of the P() macro in headers This was originally meant for dlopen()ing a potential kconfig shared library. The unused dlopen code has already been removed in commit 5a6f8d2b (kconfig: nuke LKC_DIRECT_LINK cruft), so let's remove the rest. The lkc_proto.h change was made with the following sed script: sed -r 's/^P\(([^,]*), *([^,]*), *(.*)\);/\2 \1\3;/' Plus some manual adjustments. Signed-off-by: Michal Marek --- scripts/kconfig/lkc.h | 2 - scripts/kconfig/lkc_proto.h | 88 ++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index d5daa7af8b49..e418a30bbc40 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -21,9 +21,7 @@ static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; extern "C" { #endif -#define P(name,type,arg) extern type name arg #include "lkc_proto.h" -#undef P #define SRCTREE "srctree" diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index ecdb9659b67d..ceddbcf1e5ac 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -1,57 +1,55 @@ #include /* confdata.c */ -P(conf_parse,void,(const char *name)); -P(conf_read,int,(const char *name)); -P(conf_read_simple,int,(const char *name, int)); -P(conf_write_defconfig,int,(const char *name)); -P(conf_write,int,(const char *name)); -P(conf_write_autoconf,int,(void)); -P(conf_get_changed,bool,(void)); -P(conf_set_changed_callback, void,(void (*fn)(void))); -P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); +void conf_parse(const char *name); +int conf_read(const char *name); +int conf_read_simple(const char *name, int); +int conf_write_defconfig(const char *name); +int conf_write(const char *name); +int conf_write_autoconf(void); +bool conf_get_changed(void); +void conf_set_changed_callback(void (*fn)(void)); +void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap)); /* menu.c */ -P(rootmenu,struct menu,); +extern struct menu rootmenu; -P(menu_is_empty, bool, (struct menu *menu)); -P(menu_is_visible, bool, (struct menu *menu)); -P(menu_has_prompt, bool, (struct menu *menu)); -P(menu_get_prompt,const char *,(struct menu *menu)); -P(menu_get_root_menu,struct menu *,(struct menu *menu)); -P(menu_get_parent_menu,struct menu *,(struct menu *menu)); -P(menu_has_help,bool,(struct menu *menu)); -P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head - *head)); -P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head - *head)); -P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); +bool menu_is_empty(struct menu *menu); +bool menu_is_visible(struct menu *menu); +bool menu_has_prompt(struct menu *menu); +const char * menu_get_prompt(struct menu *menu); +struct menu * menu_get_root_menu(struct menu *menu); +struct menu * menu_get_parent_menu(struct menu *menu); +bool menu_has_help(struct menu *menu); +const char * menu_get_help(struct menu *menu); +void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head); +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); +void menu_get_ext_help(struct menu *menu, struct gstr *help); /* symbol.c */ -P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); +extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; -P(sym_lookup,struct symbol *,(const char *name, int flags)); -P(sym_find,struct symbol *,(const char *name)); -P(sym_expand_string_value,const char *,(const char *in)); -P(sym_escape_string_value, const char *,(const char *in)); -P(sym_re_search,struct symbol **,(const char *pattern)); -P(sym_type_name,const char *,(enum symbol_type type)); -P(sym_calc_value,void,(struct symbol *sym)); -P(sym_get_type,enum symbol_type,(struct symbol *sym)); -P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); -P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); -P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); -P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); -P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); -P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); -P(sym_is_changable,bool,(struct symbol *sym)); -P(sym_get_choice_prop,struct property *,(struct symbol *sym)); -P(sym_get_default_prop,struct property *,(struct symbol *sym)); -P(sym_get_string_value,const char *,(struct symbol *sym)); +struct symbol * sym_lookup(const char *name, int flags); +struct symbol * sym_find(const char *name); +const char * sym_expand_string_value(const char *in); +const char * sym_escape_string_value(const char *in); +struct symbol ** sym_re_search(const char *pattern); +const char * sym_type_name(enum symbol_type type); +void sym_calc_value(struct symbol *sym); +enum symbol_type sym_get_type(struct symbol *sym); +bool sym_tristate_within_range(struct symbol *sym,tristate tri); +bool sym_set_tristate_value(struct symbol *sym,tristate tri); +tristate sym_toggle_tristate_value(struct symbol *sym); +bool sym_string_valid(struct symbol *sym, const char *newval); +bool sym_string_within_range(struct symbol *sym, const char *str); +bool sym_set_string_value(struct symbol *sym, const char *newval); +bool sym_is_changable(struct symbol *sym); +struct property * sym_get_choice_prop(struct symbol *sym); +struct property * sym_get_default_prop(struct symbol *sym); +const char * sym_get_string_value(struct symbol *sym); -P(prop_get_type_name,const char *,(enum prop_type type)); +const char * prop_get_type_name(enum prop_type type); /* expr.c */ -P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); -P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); +int expr_compare_type(enum expr_type t1, enum expr_type t2); +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); -- GitLab From 463157444e377bf9b279101b1f16a94c4648c03a Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 24 Feb 2015 16:32:09 +0100 Subject: [PATCH 0069/1910] kconfig: Remove dead code Signed-off-by: Michal Marek --- scripts/kconfig/expr.c | 4 ---- scripts/kconfig/gconf.c | 24 ------------------------ scripts/kconfig/lkc.h | 1 - scripts/kconfig/util.c | 10 ---------- 4 files changed, 39 deletions(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index d6626521f9b9..4b4cf8e21314 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -978,9 +978,6 @@ tristate expr_calc_value(struct expr *e) int expr_compare_type(enum expr_type t1, enum expr_type t2) { -#if 0 - return 1; -#else if (t1 == t2) return 0; switch (t1) { @@ -1005,7 +1002,6 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2) } printf("[%dgt%d?]", t1, t2); return 0; -#endif } static inline struct expr * diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index d0a35b21f308..344b9e340ecb 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -169,14 +169,6 @@ void init_main_window(const gchar * glade_file) style = gtk_widget_get_style(main_wnd); widget = glade_xml_get_widget(xml, "toolbar1"); -#if 0 /* Use stock Gtk icons instead */ - replace_button_icon(xml, main_wnd->window, style, - "button1", (gchar **) xpm_back); - replace_button_icon(xml, main_wnd->window, style, - "button2", (gchar **) xpm_load); - replace_button_icon(xml, main_wnd->window, style, - "button3", (gchar **) xpm_save); -#endif replace_button_icon(xml, main_wnd->window, style, "button4", (gchar **) xpm_single_view); replace_button_icon(xml, main_wnd->window, style, @@ -184,22 +176,6 @@ void init_main_window(const gchar * glade_file) replace_button_icon(xml, main_wnd->window, style, "button6", (gchar **) xpm_tree_view); -#if 0 - switch (view_mode) { - case SINGLE_VIEW: - widget = glade_xml_get_widget(xml, "button4"); - g_signal_emit_by_name(widget, "clicked"); - break; - case SPLIT_VIEW: - widget = glade_xml_get_widget(xml, "button5"); - g_signal_emit_by_name(widget, "clicked"); - break; - case FULL_VIEW: - widget = glade_xml_get_widget(xml, "button6"); - g_signal_emit_by_name(widget, "clicked"); - break; - } -#endif txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", "foreground", "red", diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index e418a30bbc40..9f845eab56cb 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -135,7 +135,6 @@ struct gstr { int max_width; }; struct gstr str_new(void); -struct gstr str_assign(const char *s); void str_free(struct gstr *gs); void str_append(struct gstr *gs, const char *s); void str_printf(struct gstr *gs, const char *fmt, ...); diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 94f9c83e324f..0e76042473cc 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -88,16 +88,6 @@ struct gstr str_new(void) return gs; } -/* Allocate and assign growable string */ -struct gstr str_assign(const char *s) -{ - struct gstr gs; - gs.s = strdup(s); - gs.len = strlen(s) + 1; - gs.max_width = 0; - return gs; -} - /* Free storage for growable string */ void str_free(struct gstr *gs) { -- GitLab From ad8d40cda3ad22ad9e8863d55a5c88f85c0173f0 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 24 Feb 2015 16:37:13 +0100 Subject: [PATCH 0070/1910] kconfig: Remove unnecessary prototypes from headers Signed-off-by: Michal Marek --- scripts/kconfig/confdata.c | 5 +++++ scripts/kconfig/expr.c | 18 ++++++++++------ scripts/kconfig/expr.h | 5 ----- scripts/kconfig/lkc.h | 11 ---------- scripts/kconfig/lkc_proto.h | 3 --- scripts/kconfig/menu.c | 4 ++-- scripts/kconfig/symbol.c | 42 ++++++++++++++++++------------------- 7 files changed, 40 insertions(+), 48 deletions(-) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 28df18dd1147..c814f57672fc 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -16,6 +16,11 @@ #include "lkc.h" +struct conf_printer { + void (*print_symbol)(FILE *, struct symbol *, const char *, void *); + void (*print_comment)(FILE *, const char *, void *); +}; + static void conf_warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 4b4cf8e21314..fb0a2a286dca 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -11,6 +11,12 @@ #define DEBUG_EXPR 0 +static int expr_eq(struct expr *e1, struct expr *e2); +static struct expr *expr_eliminate_yn(struct expr *e); +static struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +static struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +static void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); + struct expr *expr_alloc_symbol(struct symbol *sym) { struct expr *e = xcalloc(1, sizeof(*e)); @@ -186,7 +192,7 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) #undef e1 #undef e2 -int expr_eq(struct expr *e1, struct expr *e2) +static int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; @@ -228,7 +234,7 @@ int expr_eq(struct expr *e1, struct expr *e2) return 0; } -struct expr *expr_eliminate_yn(struct expr *e) +static struct expr *expr_eliminate_yn(struct expr *e) { struct expr *tmp; @@ -823,7 +829,7 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym) return false; } -struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) +static struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) { struct expr *tmp = NULL; expr_extract_eq(E_AND, &tmp, ep1, ep2); @@ -834,7 +840,7 @@ struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) return tmp; } -struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) +static struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) { struct expr *tmp = NULL; expr_extract_eq(E_OR, &tmp, ep1, ep2); @@ -845,7 +851,7 @@ struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) return tmp; } -void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) +static void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) { #define e1 (*ep1) #define e2 (*ep2) @@ -976,7 +982,7 @@ tristate expr_calc_value(struct expr *e) } } -int expr_compare_type(enum expr_type t1, enum expr_type t2) +static int expr_compare_type(enum expr_type t1, enum expr_type t2) { if (t1 == t2) return 0; diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 412ea8a2abb8..a2fc96a2bd2c 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -205,18 +205,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); struct expr *expr_copy(const struct expr *org); void expr_free(struct expr *e); -int expr_eq(struct expr *e1, struct expr *e2); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); tristate expr_calc_value(struct expr *e); -struct expr *expr_eliminate_yn(struct expr *e); struct expr *expr_trans_bool(struct expr *e); struct expr *expr_eliminate_dups(struct expr *e); struct expr *expr_transform(struct expr *e); int expr_contains_symbol(struct expr *dep, struct symbol *sym); bool expr_depends_symbol(struct expr *dep, struct symbol *sym); -struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); -struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); -void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 9f845eab56cb..91ca126ea080 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -68,9 +68,6 @@ struct kconf_id { enum symbol_type stype; }; -extern int zconfdebug; - -int zconfparse(void); void zconfdump(FILE *out); void zconf_starthelp(void); FILE *zconf_fopen(const char *name); @@ -88,11 +85,6 @@ void sym_add_change_count(int count); bool conf_set_all_new_symbols(enum conf_def_mode mode); void set_all_choice_values(struct symbol *csym); -struct conf_printer { - void (*print_symbol)(FILE *, struct symbol *, const char *, void *); - void (*print_comment)(FILE *, const char *, void *); -}; - /* confdata.c and expr.c */ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) { @@ -111,7 +103,6 @@ void menu_add_entry(struct symbol *sym); void menu_end_entry(void); void menu_add_dep(struct expr *dep); void menu_add_visibility(struct expr *dep); -struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); @@ -145,8 +136,6 @@ extern struct expr *sym_env_list; void sym_init(void); void sym_clear_all_valid(void); -void sym_set_all_changed(void); -void sym_set_changed(struct symbol *sym); struct symbol *sym_choice_default(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index ceddbcf1e5ac..d5398718ec2a 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -22,7 +22,6 @@ struct menu * menu_get_root_menu(struct menu *menu); struct menu * menu_get_parent_menu(struct menu *menu); bool menu_has_help(struct menu *menu); const char * menu_get_help(struct menu *menu); -void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); void menu_get_ext_help(struct menu *menu, struct gstr *help); @@ -45,11 +44,9 @@ bool sym_string_within_range(struct symbol *sym, const char *str); bool sym_set_string_value(struct symbol *sym, const char *newval); bool sym_is_changable(struct symbol *sym); struct property * sym_get_choice_prop(struct symbol *sym); -struct property * sym_get_default_prop(struct symbol *sym); const char * sym_get_string_value(struct symbol *sym); const char * prop_get_type_name(enum prop_type type); /* expr.c */ -int expr_compare_type(enum expr_type t1, enum expr_type t2); void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 72c9dba84c5d..b05cc3d4a9be 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -125,7 +125,7 @@ void menu_set_type(int type) sym_type_name(sym->type), sym_type_name(type)); } -struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) { struct property *prop = prop_alloc(type, current_entry->sym); @@ -615,7 +615,7 @@ static struct property *get_symbol_prop(struct symbol *sym) /* * head is optional and may be NULL */ -void get_symbol_str(struct gstr *r, struct symbol *sym, +static void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head) { bool hit; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 7caabdb51c64..6731377f9bb2 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -112,7 +112,7 @@ struct property *sym_get_env_prop(struct symbol *sym) return NULL; } -struct property *sym_get_default_prop(struct symbol *sym) +static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; @@ -186,6 +186,26 @@ static void sym_validate_range(struct symbol *sym) sym->curr.val = strdup(str); } +static void sym_set_changed(struct symbol *sym) +{ + struct property *prop; + + sym->flags |= SYMBOL_CHANGED; + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu) + prop->menu->flags |= MENU_CHANGED; + } +} + +static void sym_set_all_changed(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym_set_changed(sym); +} + static void sym_calc_visibility(struct symbol *sym) { struct property *prop; @@ -451,26 +471,6 @@ void sym_clear_all_valid(void) sym_calc_value(modules_sym); } -void sym_set_changed(struct symbol *sym) -{ - struct property *prop; - - sym->flags |= SYMBOL_CHANGED; - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu) - prop->menu->flags |= MENU_CHANGED; - } -} - -void sym_set_all_changed(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym_set_changed(sym); -} - bool sym_tristate_within_range(struct symbol *sym, tristate val) { int type = sym_get_type(sym); -- GitLab From 19449593d60b75654fe33a98c4fb8ff8a38ac1e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:27:10 +0300 Subject: [PATCH 0071/1910] sound: sys_timer: indent poll_def_tmr() correctly The indenting here was really whacky and not consistent from one line to the next. I also reverse the "if (opened)" and "if (tmr_running)" tests so that I could remove two indent levels. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/sys_timer.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c index 9f039831114c..2226dda0eff0 100644 --- a/sound/oss/sys_timer.c +++ b/sound/oss/sys_timer.c @@ -50,29 +50,24 @@ tmr2ticks(int tmr_value) static void poll_def_tmr(unsigned long dummy) { + if (!opened) + return; + def_tmr.expires = (1) + jiffies; + add_timer(&def_tmr); - if (opened) - { + if (!tmr_running) + return; - { - def_tmr.expires = (1) + jiffies; - add_timer(&def_tmr); - } + spin_lock(&lock); + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - if (tmr_running) - { - spin_lock(&lock); - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer(0); - } - spin_unlock(&lock); - } - } + if (curr_ticks >= next_event_time) { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } + + spin_unlock(&lock); } static void -- GitLab From df403869e35f88e1e45483d31ee70b4aa3ed8896 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:30:36 +0300 Subject: [PATCH 0072/1910] sound/oss/opl3: remove some stray whitespace Removed an extra tab and a extra space character. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/opl3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 607cee4d545e..b6d19adf8f41 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -666,7 +666,7 @@ static int opl3_start_note (int dev, int voice, int note, int volume) opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; + devc->voc[voice].keyon_byte = data; opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); if (voice_mode == 4) opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); @@ -717,7 +717,7 @@ static void freq_to_fnum (int freq, int *block, int *fnum) static void opl3_command (int io_addr, unsigned int addr, unsigned int val) { - int i; + int i; /* * The original 2-OP synth requires a quite long delay after writing to a -- GitLab From e214e5183d9da3b61f775d3ae7202ea8aa10ebed Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:31:43 +0300 Subject: [PATCH 0073/1910] sound/sb_ess: white space cleanups These weren't aligned on the same lines as the surrounding code and the printk was quite messy. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/sb_ess.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index b47a69026f1b..57f7d25a2cd3 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -604,7 +604,7 @@ static void ess_audio_output_block_audio2 ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ devc->irq_mode_16 = IMODE_OUTPUT; - devc->intr_active_16 = 1; + devc->intr_active_16 = 1; } static void ess_audio_output_block @@ -1183,17 +1183,12 @@ FKS_test (devc); chip = "ES1688"; } - printk ( KERN_INFO "ESS chip %s %s%s\n" - , chip - , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20 - ? "detected" - : "specified" - ) - , ( devc->sbmo.esstype == ESSTYPE_LIKE20 - ? " (kernel 2.0 compatible)" - : "" - ) - ); + printk(KERN_INFO "ESS chip %s %s%s\n", chip, + (devc->sbmo.esstype == ESSTYPE_DETECT || + devc->sbmo.esstype == ESSTYPE_LIKE20) ? + "detected" : "specified", + devc->sbmo.esstype == ESSTYPE_LIKE20 ? + " (kernel 2.0 compatible)" : ""); sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { -- GitLab From f0418d46d6ad25be991d557c6c50d1e61b4ba690 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:32:16 +0300 Subject: [PATCH 0074/1910] sound/sb_midi: a couple indenting fixes Let's make things line up a little bit better. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/sb_midi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c index f139028e85c0..551ee7557b4e 100644 --- a/sound/oss/sb_midi.c +++ b/sound/oss/sb_midi.c @@ -179,14 +179,14 @@ void sb_dsp_midi_init(sb_devc * devc, struct module *owner) { printk(KERN_WARNING "Sound Blaster: failed to allocate MIDI memory.\n"); sound_unload_mididev(dev); - return; + return; } memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, sizeof(struct midi_operations)); if (owner) - midi_devs[dev]->owner = owner; - + midi_devs[dev]->owner = owner; + midi_devs[dev]->devc = devc; -- GitLab From 7f788e0cc07dba7f4eee6ffea30edee3af86e2a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:32:45 +0300 Subject: [PATCH 0075/1910] ALSA: azt3328: some indenting cleanups A few minor tweaks to make things line up correctly. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index a40a2b4c8fd7..33b2a0af1b59 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1385,8 +1385,8 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, .running) && (!chip->codecs[peer_codecs[codec_type].other2] .running)); - } - if (call_function) + } + if (call_function) snd_azf3328_ctrl_enable_codecs(chip, enable); /* ...and adjust clock, too @@ -2126,7 +2126,8 @@ static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { static int snd_azf3328_pcm(struct snd_azf3328 *chip) { -enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ + /* pcm devices */ + enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; struct snd_pcm *pcm; int err; -- GitLab From 9603cded0e2cef003a822985d84b5daff1c7232f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:33:57 +0300 Subject: [PATCH 0076/1910] ALSA: cmipci: remove a stray space character Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/cmipci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1d0f2cad2f5a..6cf464d9043d 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2062,7 +2062,7 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol, val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask; if (reg.invert) val = reg.mask - val; - ucontrol->value.integer.value[1] = val; + ucontrol->value.integer.value[1] = val; } spin_unlock_irq(&cm->reg_lock); return 0; -- GitLab From 5bb400ce4a9b100a2dd3f5db17c4c76877cecade Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 25 Feb 2015 21:37:52 +0530 Subject: [PATCH 0077/1910] ASoC: Intel: wrap runtime_pm usage count under CONFIG_PM The struct dev_pm_ops defines usage_count only when CONFIG_PM is defined. So we should use this variable only in cases where this falg is true. So we define a local variable and read the value under this flag. In non PM cases, we set this to 1. Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst_drv_interface.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 549af7d7f6d0..f0e4b99b3aeb 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -139,17 +139,23 @@ static int sst_power_control(struct device *dev, bool state) { struct intel_sst_drv *ctx = dev_get_drvdata(dev); int ret = 0; + int usage_count = 0; + +#ifdef CONFIG_PM + usage_count = atomic_read(&dev->power.usage_count); +#else + usage_count = 1; +#endif if (state == true) { ret = pm_runtime_get_sync(dev); - dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", - atomic_read(&dev->power.usage_count)); + + dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); if (ret < 0) { dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); return ret; } - if ((ctx->sst_state == SST_RESET) && - (atomic_read(&dev->power.usage_count) == 1)) { + if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) { ret = sst_load_fw(ctx); if (ret) { dev_err(dev, "FW download fail %d\n", ret); @@ -158,8 +164,7 @@ static int sst_power_control(struct device *dev, bool state) } } } else { - dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", - atomic_read(&dev->power.usage_count)); + dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count); return sst_pm_runtime_put(ctx); } return ret; -- GitLab From 92b2ad2c9e18ca2bfa8727af7edcd372d9acaac4 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 24 Feb 2015 22:39:04 -0800 Subject: [PATCH 0078/1910] ASoC: max98357a: Use standard DAI names Use the standard naming convention for the codec DAI. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 4ee23fbc4e12..bf3e933ee895 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -85,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = { }; static struct snd_soc_dai_driver max98357a_dai_driver = { - .name = "max98357a", + .name = "HiFi", .playback = { - .stream_name = "max98357a-playback", + .stream_name = "HiFi Playback", .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32, -- GitLab From bb573928e187fc5b1f91c3a7684791d5dfcca640 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 09:26:04 +0100 Subject: [PATCH 0079/1910] ALSA: hda - Drop power_save value indirection in hda_bus We used to pass the power_save option value to hda_bus via a given pointer. This was needed to refer to the value from the HD-audio core side. However, after the transition to the runtime PM, this is no longer needed. This patch drops the power_save value indirection in hda_bus above, and let the controller driver reprograms the autosuspend value explicitly by a new helper, snd_hda_set_power_save(). Without this call, the HD-audio core doesn't set up the autosuspend and flip the runtime PM. (User may still be able to set up via sysfs, though.) Along with this change, the pointer argument of azx_bus_create() is dropped as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 34 ++++++++++++++++++---------------- sound/pci/hda/hda_codec.h | 5 ++--- sound/pci/hda/hda_controller.c | 5 +---- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 10 ++++------ sound/pci/hda/hda_tegra.c | 5 +++-- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d0dbc62c9147..36cebe0e76b2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1175,10 +1175,8 @@ static int snd_hda_codec_dev_register(struct snd_device *device) struct hda_codec *codec = device->device_data; snd_hda_register_beep_device(codec); - if (device_is_registered(hda_codec_dev(codec))) { - snd_hda_power_sync(codec); + if (device_is_registered(hda_codec_dev(codec))) pm_runtime_enable(hda_codec_dev(codec)); - } return 0; } @@ -4778,21 +4776,10 @@ void snd_hda_power_down(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_power_down); -/** - * snd_hda_power_sync - Synchronize the power_save option - * @codec: HD-audio codec - * - * Synchronize the runtime PM autosuspend state from the power_save option. - */ -void snd_hda_power_sync(struct hda_codec *codec) +static void codec_set_power_save(struct hda_codec *codec, int delay) { struct device *dev = hda_codec_dev(codec); - int delay; - if (!codec->bus->power_save) - return; - - delay = *codec->bus->power_save * 1000; if (delay > 0) { pm_runtime_set_autosuspend_delay(dev, delay); pm_runtime_use_autosuspend(dev); @@ -4804,7 +4791,22 @@ void snd_hda_power_sync(struct hda_codec *codec) pm_runtime_forbid(dev); } } -EXPORT_SYMBOL_GPL(snd_hda_power_sync); + +/** + * snd_hda_set_power_save - reprogram autosuspend for the given delay + * @bus: HD-audio bus + * @delay: autosuspend delay in msec, 0 = off + * + * Synchronize the runtime PM autosuspend state from the power_save option. + */ +void snd_hda_set_power_save(struct hda_bus *bus, int delay) +{ + struct hda_codec *c; + + list_for_each_entry(c, &bus->codec_list, list) + codec_set_power_save(c, delay); +} +EXPORT_SYMBOL_GPL(snd_hda_set_power_save); /** * snd_hda_check_amp_list_power - Check the amp list and update the power diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 593956fc384b..89908f5b9601 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -122,7 +122,6 @@ struct hda_bus { void *private_data; struct pci_dev *pci; const char *modelname; - int *power_save; struct hda_bus_ops ops; /* codec linked list */ @@ -592,12 +591,12 @@ const char *snd_hda_get_jack_location(u32 cfg); #ifdef CONFIG_PM void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); -void snd_hda_power_sync(struct hda_codec *codec); +void snd_hda_set_power_save(struct hda_bus *bus, int delay); void snd_hda_update_power_acct(struct hda_codec *codec); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} -static inline void snd_hda_power_sync(struct hda_codec *codec) {} +static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {} #endif #ifdef CONFIG_SND_HDA_PATCH_LOADER diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 522c54f94740..cfe2c55296b6 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1838,7 +1838,7 @@ static struct hda_bus_ops bus_ops = { }; /* HD-audio bus initialization */ -int azx_bus_create(struct azx *chip, const char *model, int *power_save_to) +int azx_bus_create(struct azx *chip, const char *model) { struct hda_bus *bus; int err; @@ -1852,9 +1852,6 @@ int azx_bus_create(struct azx *chip, const char *model, int *power_save_to) bus->pci = chip->pci; bus->modelname = model; bus->ops = bus_ops; -#ifdef CONFIG_PM - bus->power_save = power_save_to; -#endif if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 0d09aa6b49ac..e4f46a21698a 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -432,7 +432,7 @@ void azx_enter_link_reset(struct azx *chip); irqreturn_t azx_interrupt(int irq, void *dev_id); /* Codec interface */ -int azx_bus_create(struct azx *chip, const char *model, int *power_save_to); +int azx_bus_create(struct azx *chip, const char *model); int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); int azx_init_stream(struct azx *chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 26510e60cbe2..40540048b002 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -173,7 +173,6 @@ static struct kernel_param_ops param_ops_xint = { #define param_check_xint param_check_int static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -static int *power_save_addr = &power_save; module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); @@ -186,7 +185,7 @@ static bool power_save_controller = 1; module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #else -static int *power_save_addr; +#define power_save 0 #endif /* CONFIG_PM */ static int align_buffer_size = -1; @@ -740,7 +739,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) { struct hda_intel *hda; struct azx *chip; - struct hda_codec *c; int prev = power_save; int ret = param_set_int(val, kp); @@ -752,8 +750,7 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) chip = &hda->chip; if (!chip->bus || chip->disabled) continue; - list_for_each_entry(c, &chip->bus->codec_list, list) - snd_hda_power_sync(c); + snd_hda_set_power_save(chip->bus, power_save * 1000); } mutex_unlock(&card_list_lock); return 0; @@ -1889,7 +1886,7 @@ static int azx_probe_continue(struct azx *chip) #endif /* create codec instances */ - err = azx_bus_create(chip, model[dev], power_save_addr); + err = azx_bus_create(chip, model[dev]); if (err < 0) goto out_free; @@ -1933,6 +1930,7 @@ static int azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); + snd_hda_set_power_save(chip->bus, power_save * 1000); if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) pm_runtime_put_noidle(&pci->dev); diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index f6949e413a50..42bc17655df0 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -81,7 +81,7 @@ module_param(power_save, bint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout (in seconds, 0 = disable)."); #else -static int power_save = 0; +#define power_save 0 #endif /* @@ -496,7 +496,7 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; /* create codec instances */ - err = azx_bus_create(chip, NULL, &power_save); + err = azx_bus_create(chip, NULL); if (err < 0) goto out_free; @@ -525,6 +525,7 @@ static int hda_tegra_probe(struct platform_device *pdev) chip->running = 1; power_down_all_codecs(chip); azx_notifier_register(chip); + snd_hda_set_power_save(chip->bus, power_save * 1000); return 0; -- GitLab From 55ed9cd1feee80764937913afe760161b86cfb11 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Feb 2015 17:35:32 +0100 Subject: [PATCH 0080/1910] ALSA: hda - Replace bus pm_notify with the standard runtime PM framework Now the final bit of runtime PM cleanup: instead of manual notification of the power up/down of the codec via hda_bus pm_notify ops, use the standard runtime PM feature. The child codec device will kick off the runtime PM of the parent (PCI) device upon suspend/resume automatically. For managing whether the link can be really turned off, we use the bit flags bus->codec_powered instead of the earlier bus->power_keep_link_on. flag. Each codec driver is responsible to set/clear the bit flag, and the controller device can be turned off only when all these bits are cleared. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 33 ++++++++------------------------- sound/pci/hda/hda_codec.h | 7 +------ sound/pci/hda/hda_controller.c | 19 ------------------- sound/pci/hda/hda_intel.c | 5 ++--- sound/pci/hda/patch_sigmatel.c | 4 +++- 5 files changed, 14 insertions(+), 54 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 36cebe0e76b2..33b8b71f8eaf 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -46,23 +46,9 @@ #define codec_in_pm(codec) atomic_read(&(codec)->in_pm) #define hda_codec_is_power_on(codec) \ (!pm_runtime_suspended(hda_codec_dev(codec))) - -static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) -{ - struct hda_bus *bus = codec->bus; - - if ((power_up && codec->pm_up_notified) || - (!power_up && !codec->pm_up_notified)) - return; - if (bus->ops.pm_notify) - bus->ops.pm_notify(bus, power_up); - codec->pm_up_notified = power_up; -} - #else #define codec_in_pm(codec) 0 #define hda_codec_is_power_on(codec) 1 -#define hda_call_pm_notify(codec, state) {} #endif /** @@ -1152,7 +1138,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->spdif_out); remove_conn_list(codec); codec->bus->caddr_tbl[codec->addr] = NULL; - hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ + clear_bit(codec->addr, &codec->bus->codec_powered); snd_hda_sysfs_clear(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); @@ -1277,10 +1263,10 @@ int snd_hda_codec_new(struct hda_bus *bus, * the caller has to power down appropriatley after initialization * phase. */ + set_bit(codec->addr, &bus->codec_powered); pm_runtime_set_active(hda_codec_dev(codec)); pm_runtime_get_noresume(hda_codec_dev(codec)); codec->power_jiffies = jiffies; - hda_call_pm_notify(codec, true); #endif snd_hda_sysfs_init(codec); @@ -1340,11 +1326,6 @@ int snd_hda_codec_new(struct hda_bus *bus, #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); -#ifdef CONFIG_PM - if (!codec->d3_stop_clk || !codec->epss) - bus->power_keep_link_on = 1; -#endif - /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -3954,7 +3935,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_mark_cmd_cache_dirty(codec); codec->power_jiffies = jiffies; - hda_call_pm_notify(codec, true); hda_set_power_state(codec, AC_PWRST_D0); restore_shutup_pins(codec); @@ -3986,14 +3966,17 @@ static int hda_codec_runtime_suspend(struct device *dev) for (i = 0; i < codec->num_pcms; i++) snd_pcm_suspend_all(codec->pcm_info[i].pcm); state = hda_call_codec_suspend(codec); - if (!codec->bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) - hda_call_pm_notify(codec, false); + if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK)) + clear_bit(codec->addr, &codec->bus->codec_powered); return 0; } static int hda_codec_runtime_resume(struct device *dev) { - hda_call_codec_resume(dev_to_hda_codec(dev)); + struct hda_codec *codec = dev_to_hda_codec(dev); + + set_bit(codec->addr, &codec->bus->codec_powered); + hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 89908f5b9601..457fc589eb46 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -83,10 +83,6 @@ struct hda_bus_ops { struct hda_pcm *pcm); /* reset bus for retry verb */ void (*bus_reset)(struct hda_bus *bus); -#ifdef CONFIG_PM - /* notify power-up/down from codec to controller */ - void (*pm_notify)(struct hda_bus *bus, bool power_up); -#endif #ifdef CONFIG_SND_HDA_DSP_LOADER /* prepare DSP transfer */ int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format, @@ -150,10 +146,10 @@ struct hda_bus { unsigned int rirb_error:1; /* error in codec communication */ unsigned int response_reset:1; /* controller was reset */ unsigned int in_reset:1; /* during reset operation */ - unsigned int power_keep_link_on:1; /* don't power off HDA link */ unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ int primary_dig_out_type; /* primary digital out PCM type */ + unsigned long codec_powered; /* bit flags of powered codecs */ }; /* @@ -372,7 +368,6 @@ struct hda_codec { unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ #ifdef CONFIG_PM unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ - unsigned int pm_up_notified:1; /* PM notified to controller */ atomic_t in_pm; /* suspend/resume being performed */ unsigned long power_on_acct; unsigned long power_off_acct; diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index cfe2c55296b6..789ca66c3094 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1785,22 +1785,6 @@ static void azx_bus_reset(struct hda_bus *bus) bus->in_reset = 0; } -#ifdef CONFIG_PM -/* power-up/down the controller */ -static void azx_power_notify(struct hda_bus *bus, bool power_up) -{ - struct azx *chip = bus->private_data; - - if (!azx_has_pm_runtime(chip)) - return; - - if (power_up) - pm_runtime_get_sync(chip->card->dev); - else - pm_runtime_put_sync(chip->card->dev); -} -#endif - static int get_jackpoll_interval(struct azx *chip) { int i; @@ -1827,9 +1811,6 @@ static struct hda_bus_ops bus_ops = { .get_response = azx_get_response, .attach_pcm = azx_attach_pcm_stream, .bus_reset = azx_bus_reset, -#ifdef CONFIG_PM - .pm_notify = azx_power_notify, -#endif #ifdef CONFIG_SND_HDA_DSP_LOADER .load_dsp_prepare = azx_load_dsp_prepare, .load_dsp_trigger = azx_load_dsp_trigger, diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 40540048b002..738d332351d5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -918,7 +918,8 @@ static int azx_runtime_idle(struct device *dev) if (chip->disabled || hda->init_failed) return 0; - if (!power_save_controller || !azx_has_pm_runtime(chip)) + if (!power_save_controller || !azx_has_pm_runtime(chip) || + chip->bus->codec_powered) return -EBUSY; return 0; @@ -1084,7 +1085,6 @@ static int azx_free(struct azx *chip) azx_stop_chip(chip); } - pci->dev.power.ignore_children = 0; /* FIXME */ if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); if (chip->msi) @@ -1794,7 +1794,6 @@ static int azx_probe(struct pci_dev *pci, return err; } - pci->dev.power.ignore_children = 1; /* FIXME */ err = azx_create(card, pci, dev, pci_id->driver_data, &pci_hda_ops, &chip); if (err < 0) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6a2163056216..2956a6ba6bf0 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2132,8 +2132,10 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ +#ifdef CONFIG_PM /* resetting controller clears GPIO, so we need to keep on */ - codec->bus->power_keep_link_on = 1; + codec->d3_stop_clk = 0; +#endif } } -- GitLab From 709949fbe9632941585dcacabc8a66010030ed10 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 09:58:14 +0100 Subject: [PATCH 0081/1910] ALSA: hda - Power down codec automatically at registration So far, we let the controller driver power down the all codecs at the end of probe. But this can be done better in the codec's dev_register callback. This results in the reduction of duplicated codes in each control driver. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 +++-- sound/pci/hda/hda_intel.c | 14 -------------- sound/pci/hda/hda_tegra.c | 12 ------------ 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 33b8b71f8eaf..6580a367023e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1163,6 +1163,8 @@ static int snd_hda_codec_dev_register(struct snd_device *device) snd_hda_register_beep_device(codec); if (device_is_registered(hda_codec_dev(codec))) pm_runtime_enable(hda_codec_dev(codec)); + /* it was powered up in snd_hda_codec_new(), now all done */ + snd_hda_power_down(codec); return 0; } @@ -1260,8 +1262,7 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. - * the caller has to power down appropriatley after initialization - * phase. + * it's powered down later in snd_hda_codec_dev_register(). */ set_bit(codec->addr, &bus->codec_powered); pm_runtime_set_active(hda_codec_dev(codec)); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 738d332351d5..e75e8137e296 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1604,19 +1604,6 @@ static int azx_first_init(struct azx *chip) return 0; } -static void power_down_all_codecs(struct azx *chip) -{ -#ifdef CONFIG_PM - /* The codecs were powered up in snd_hda_codec_new(). - * Now all initialization done, so turn them down if possible - */ - struct hda_codec *codec; - list_for_each_entry(codec, &chip->bus->codec_list, list) { - snd_hda_power_down(codec); - } -#endif -} - #ifdef CONFIG_SND_HDA_PATCH_LOADER /* callback from request_firmware_nowait() */ static void azx_firmware_cb(const struct firmware *fw, void *context) @@ -1926,7 +1913,6 @@ static int azx_probe_continue(struct azx *chip) goto out_free; chip->running = 1; - power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); snd_hda_set_power_save(chip->bus, power_save * 1000); diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 42bc17655df0..1359fdd20f02 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -337,17 +337,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) return 0; } -/* - * The codecs were powered up in snd_hda_codec_new(). - * Now all initialization done, so turn them down if possible - */ -static void power_down_all_codecs(struct azx *chip) -{ - struct hda_codec *codec; - list_for_each_entry(codec, &chip->bus->codec_list, list) - snd_hda_power_down(codec); -} - static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) { struct snd_card *card = chip->card; @@ -523,7 +512,6 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; chip->running = 1; - power_down_all_codecs(chip); azx_notifier_register(chip); snd_hda_set_power_save(chip->bus, power_save * 1000); -- GitLab From 777ae1946813f1dea24d908c8f318754f090f41f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Feb 2015 14:35:59 +0100 Subject: [PATCH 0082/1910] ALSA: hda - Set parent of input beep devices Set the card device as the parent like other sound devices instead of leaving it empty. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index d6be4e852c4d..e98438e95e79 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -160,6 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep) input_dev->name = "HDA Digital PCBeep"; input_dev->phys = beep->phys; input_dev->id.bustype = BUS_PCI; + input_dev->dev.parent = &codec->bus->card->card_dev; input_dev->id.vendor = codec->vendor_id >> 16; input_dev->id.product = codec->vendor_id & 0xffff; -- GitLab From 7e40b80da452770878943edfe7da80f10f8d25da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Feb 2015 09:42:04 +0100 Subject: [PATCH 0083/1910] ALSA: hda - Remove channel mode helper functions They are no longer used, let's kill them. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 82 --------------------------------------- sound/pci/hda/hda_local.h | 23 ----------- 2 files changed, 105 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6580a367023e..db86b446743c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4843,88 +4843,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); #endif -/* - * Channel mode helper - */ - -/** - * snd_hda_ch_mode_info - Info callback helper for the channel mode enum - * @codec: the HDA codec - * @uinfo: pointer to get/store the data - * @chmode: channel mode array - * @num_chmodes: channel mode array size - */ -int snd_hda_ch_mode_info(struct hda_codec *codec, - struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, - int num_chmodes) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = num_chmodes; - if (uinfo->value.enumerated.item >= num_chmodes) - uinfo->value.enumerated.item = num_chmodes - 1; - sprintf(uinfo->value.enumerated.name, "%dch", - chmode[uinfo->value.enumerated.item].channels); - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); - -/** - * snd_hda_ch_mode_get - Get callback helper for the channel mode enum - * @codec: the HDA codec - * @ucontrol: pointer to get/store the data - * @chmode: channel mode array - * @num_chmodes: channel mode array size - * @max_channels: max number of channels - */ -int snd_hda_ch_mode_get(struct hda_codec *codec, - struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, - int num_chmodes, - int max_channels) -{ - int i; - - for (i = 0; i < num_chmodes; i++) { - if (max_channels == chmode[i].channels) { - ucontrol->value.enumerated.item[0] = i; - break; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); - -/** - * snd_hda_ch_mode_put - Put callback helper for the channel mode enum - * @codec: the HDA codec - * @ucontrol: pointer to get/store the data - * @chmode: channel mode array - * @num_chmodes: channel mode array size - * @max_channelsp: pointer to store the max channels - */ -int snd_hda_ch_mode_put(struct hda_codec *codec, - struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, - int num_chmodes, - int *max_channelsp) -{ - unsigned int mode; - - mode = ucontrol->value.enumerated.item[0]; - if (mode >= num_chmodes) - return -EINVAL; - if (*max_channelsp == chmode[mode].channels) - return 0; - /* change the current channel setting */ - *max_channelsp = chmode[mode].channels; - if (chmode[mode].sequence) - snd_hda_sequence_write_cache(codec, chmode[mode].sequence); - return 1; -} -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); - /* * input MUX helper */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 2f7d9646a41d..8588813163e3 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -272,29 +272,6 @@ int snd_hda_add_imux_item(struct hda_codec *codec, struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); -/* - * Channel mode helper - */ -struct hda_channel_mode { - int channels; - const struct hda_verb *sequence; -}; - -int snd_hda_ch_mode_info(struct hda_codec *codec, - struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, - int num_chmodes); -int snd_hda_ch_mode_get(struct hda_codec *codec, - struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, - int num_chmodes, - int max_channels); -int snd_hda_ch_mode_put(struct hda_codec *codec, - struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, - int num_chmodes, - int *max_channelsp); - /* * Multi-channel / digital-out PCM helper */ -- GitLab From 820cc6cf2c552155ea919e596a85e1f4e5dfa2b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Feb 2015 12:50:46 +0100 Subject: [PATCH 0084/1910] ALSA: hda - Clear pcm pointer assigned to hda_pcm at device removal We leave the pcm field of struct hda_pcm at removal of each device, so far. This hasn't been a problem since unbinding the codec driver isn't supposed to happen and another route via snd_hda_codec_reset() clears all the once. However, for a proper unbind implementation, we need to care about it. This patch does the thing above properly: - Include struct hda_pcm pointer instead of struct hda_pcm_stream pointers in struct azx_dev. This allows us to point the hda_pcm object at dev_free callback. - Introduce to_hda_pcm_stream() macro for better readability. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 22 +++++++++++++++------- sound/pci/hda/hda_controller.h | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 789ca66c3094..1695f0e2bd9d 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -258,11 +258,18 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream, tc->cycle_last = last; } +static inline struct hda_pcm_stream * +to_hda_pcm_stream(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + return &apcm->info->stream[substream->stream]; +} + static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, u64 nsec) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); u64 codec_frames, codec_nsecs; if (!hinfo->ops.get_delay) @@ -398,7 +405,7 @@ static int azx_setup_periods(struct azx *chip, static int azx_pcm_close(struct snd_pcm_substream *substream) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); unsigned long flags; @@ -440,7 +447,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_dev *azx_dev = get_azx_dev(substream); struct azx *chip = apcm->chip; - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); int err; /* reset BDL address */ @@ -467,7 +474,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int bufsize, period_bytes, format_val, stream_tag; int err; @@ -707,7 +714,7 @@ unsigned int azx_get_position(struct azx *chip, if (substream->runtime) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); if (chip->get_delay[stream]) delay += chip->get_delay[stream](chip, azx_dev, pos); @@ -790,7 +797,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { static int azx_pcm_open(struct snd_pcm_substream *substream) { struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev; struct snd_pcm_runtime *runtime = substream->runtime; @@ -904,6 +911,7 @@ static void azx_pcm_free(struct snd_pcm *pcm) struct azx_pcm *apcm = pcm->private_data; if (apcm) { list_del(&apcm->list); + apcm->info->pcm = NULL; kfree(apcm); } } @@ -940,6 +948,7 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, apcm->chip = chip; apcm->pcm = pcm; apcm->codec = codec; + apcm->info = cpcm; pcm->private_data = apcm; pcm->private_free = azx_pcm_free; if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) @@ -947,7 +956,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, list_add_tail(&apcm->list, &chip->pcm_list); cpcm->pcm = pcm; for (s = 0; s < 2; s++) { - apcm->hinfo[s] = &cpcm->stream[s]; if (cpcm->stream[s].substreams) snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index e4f46a21698a..94c1a4719f7f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -283,7 +283,7 @@ struct azx_pcm { struct azx *chip; struct snd_pcm *pcm; struct hda_codec *codec; - struct hda_pcm_stream *hinfo[2]; + struct hda_pcm *info; struct list_head list; }; -- GitLab From 4949009eb8d40a441dcddcd96e101e77d31cf1b2 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 27 Feb 2015 06:28:00 +0300 Subject: [PATCH 0085/1910] xtensa: xtfpga: fix hardware lockup caused by LCD driver LCD driver is always built for the XTFPGA platform, but its base address is not configurable, and is wrong for ML605/KC705. Its initialization locks up KC705 board hardware. Make the whole driver optional, and its base address and bus width configurable. Implement 4-bit bus access method. Cc: stable@vger.kernel.org Signed-off-by: Max Filippov --- arch/xtensa/Kconfig | 30 ++++++++++ arch/xtensa/platforms/xtfpga/Makefile | 3 +- .../xtfpga/include/platform/hardware.h | 3 - .../platforms/xtfpga/include/platform/lcd.h | 15 +++++ arch/xtensa/platforms/xtfpga/lcd.c | 55 ++++++++++++------- 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index e31d4949124a..87be10e8b57a 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -428,6 +428,36 @@ config DEFAULT_MEM_SIZE If unsure, leave the default value here. +config XTFPGA_LCD + bool "Enable XTFPGA LCD driver" + depends on XTENSA_PLATFORM_XTFPGA + default n + help + There's a 2x16 LCD on most of XTFPGA boards, kernel may output + progress messages there during bootup/shutdown. It may be useful + during board bringup. + + If unsure, say N. + +config XTFPGA_LCD_BASE_ADDR + hex "XTFPGA LCD base address" + depends on XTFPGA_LCD + default "0x0d0c0000" + help + Base address of the LCD controller inside KIO region. + Different boards from XTFPGA family have LCD controller at different + addresses. Please consult prototyping user guide for your board for + the correct address. Wrong address here may lead to hardware lockup. + +config XTFPGA_LCD_8BIT_ACCESS + bool "Use 8-bit access to XTFPGA LCD" + depends on XTFPGA_LCD + default n + help + LCD may be connected with 4- or 8-bit interface, 8-bit access may + only be used with 8-bit interface. Please consult prototyping user + guide for your board for the correct interface width. + endmenu menu "Executable file formats" diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile index b9ae206340cd..7839d38b2337 100644 --- a/arch/xtensa/platforms/xtfpga/Makefile +++ b/arch/xtensa/platforms/xtfpga/Makefile @@ -6,4 +6,5 @@ # # Note 2! The CFLAGS definitions are in the main makefile... -obj-y = setup.o lcd.o +obj-y += setup.o +obj-$(CONFIG_XTFPGA_LCD) += lcd.o diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h index 6edd20bb4565..4e0af2662a21 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h @@ -40,9 +40,6 @@ /* UART */ #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) -/* LCD instruction and data addresses. */ -#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) -#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) /* Misc. */ #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h index 0e435645af5a..4c8541ed1139 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h @@ -11,10 +11,25 @@ #ifndef __XTENSA_XTAVNET_LCD_H #define __XTENSA_XTAVNET_LCD_H +#ifdef CONFIG_XTFPGA_LCD /* Display string STR at position POS on the LCD. */ void lcd_disp_at_pos(char *str, unsigned char pos); /* Shift the contents of the LCD display left or right. */ void lcd_shiftleft(void); void lcd_shiftright(void); +#else +static inline void lcd_disp_at_pos(char *str, unsigned char pos) +{ +} + +static inline void lcd_shiftleft(void) +{ +} + +static inline void lcd_shiftright(void) +{ +} +#endif + #endif diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c index 2872301598df..4dc0c1b43f4b 100644 --- a/arch/xtensa/platforms/xtfpga/lcd.c +++ b/arch/xtensa/platforms/xtfpga/lcd.c @@ -1,50 +1,63 @@ /* - * Driver for the LCD display on the Tensilica LX60 Board. + * Driver for the LCD display on the Tensilica XTFPGA board family. + * http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001, 2006 Tensilica Inc. + * Copyright (C) 2015 Cadence Design Systems Inc. */ -/* - * - * FIXME: this code is from the examples from the LX60 user guide. - * - * The lcd_pause function does busy waiting, which is probably not - * great. Maybe the code could be changed to use kernel timers, or - * change the hardware to not need to wait. - */ - +#include #include #include #include #include -#include -#define LCD_PAUSE_ITERATIONS 4000 +/* LCD instruction and data addresses. */ +#define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR)) +#define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4) + #define LCD_CLEAR 0x1 #define LCD_DISPLAY_ON 0xc /* 8bit and 2 lines display */ #define LCD_DISPLAY_MODE8BIT 0x38 +#define LCD_DISPLAY_MODE4BIT 0x28 #define LCD_DISPLAY_POS 0x80 #define LCD_SHIFT_LEFT 0x18 #define LCD_SHIFT_RIGHT 0x1c +static void lcd_put_byte(u8 *addr, u8 data) +{ +#ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS + ACCESS_ONCE(*addr) = data; +#else + ACCESS_ONCE(*addr) = data & 0xf0; + ACCESS_ONCE(*addr) = (data << 4) & 0xf0; +#endif +} + static int __init lcd_init(void) { - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; mdelay(5); - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; udelay(200); - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; + udelay(50); +#ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT; + udelay(50); + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT); udelay(50); - *LCD_INSTR_ADDR = LCD_DISPLAY_ON; +#endif + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON); udelay(50); - *LCD_INSTR_ADDR = LCD_CLEAR; + lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR); mdelay(10); lcd_disp_at_pos("XTENSA LINUX", 0); return 0; @@ -52,10 +65,10 @@ static int __init lcd_init(void) void lcd_disp_at_pos(char *str, unsigned char pos) { - *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos); udelay(100); while (*str != 0) { - *LCD_DATA_ADDR = *str; + lcd_put_byte(LCD_DATA_ADDR, *str); udelay(200); str++; } @@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos) void lcd_shiftleft(void) { - *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT); udelay(50); } void lcd_shiftright(void) { - *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT); udelay(50); } -- GitLab From 6bb71004aa84054058baf4e8a58a53c4e29e5b9c Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 30 Jan 2015 15:39:23 +0100 Subject: [PATCH 0086/1910] crypto: ppc/sha256 - assembler This is the assembler code for SHA256 implementation with the SIMD SPE instruction set. Although being only a 32 bit architecture GPRs are extended to 64 bit presenting two 32 bit values. With the enhanced instruction set we can operate on them in parallel. That helps reducing the time to calculate W16-W64. For increasing performance even more the assembler function can compute hashes for more than one 64 byte input block. That saves a lot of register saving/restoring The state of the used SPE registers is preserved via the stack so we can run from interrupt context. There might be the case that we interrupt ourselves and push sensitive data from another context onto our stack. Clear this area in the stack afterwards to avoid information leakage. The code is endian independant. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/sha256-spe-asm.S | 323 +++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 arch/powerpc/crypto/sha256-spe-asm.S diff --git a/arch/powerpc/crypto/sha256-spe-asm.S b/arch/powerpc/crypto/sha256-spe-asm.S new file mode 100644 index 000000000000..2d10e4c08f03 --- /dev/null +++ b/arch/powerpc/crypto/sha256-spe-asm.S @@ -0,0 +1,323 @@ +/* + * Fast SHA-256 implementation for SPE instruction set (PPC) + * + * This code makes use of the SPE SIMD instruction set as defined in + * http://cache.freescale.com/files/32bit/doc/ref_manual/SPEPIM.pdf + * Implementation is based on optimization guide notes from + * http://cache.freescale.com/files/32bit/doc/app_note/AN2665.pdf + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include + +#define rHP r3 /* pointer to hash values in memory */ +#define rKP r24 /* pointer to round constants */ +#define rWP r4 /* pointer to input data */ + +#define rH0 r5 /* 8 32 bit hash values in 8 registers */ +#define rH1 r6 +#define rH2 r7 +#define rH3 r8 +#define rH4 r9 +#define rH5 r10 +#define rH6 r11 +#define rH7 r12 + +#define rW0 r14 /* 64 bit registers. 16 words in 8 registers */ +#define rW1 r15 +#define rW2 r16 +#define rW3 r17 +#define rW4 r18 +#define rW5 r19 +#define rW6 r20 +#define rW7 r21 + +#define rT0 r22 /* 64 bit temporaries */ +#define rT1 r23 +#define rT2 r0 /* 32 bit temporaries */ +#define rT3 r25 + +#define CMP_KN_LOOP +#define CMP_KC_LOOP \ + cmpwi rT1,0; + +#define INITIALIZE \ + stwu r1,-128(r1); /* create stack frame */ \ + evstdw r14,8(r1); /* We must save non volatile */ \ + evstdw r15,16(r1); /* registers. Take the chance */ \ + evstdw r16,24(r1); /* and save the SPE part too */ \ + evstdw r17,32(r1); \ + evstdw r18,40(r1); \ + evstdw r19,48(r1); \ + evstdw r20,56(r1); \ + evstdw r21,64(r1); \ + evstdw r22,72(r1); \ + evstdw r23,80(r1); \ + stw r24,88(r1); /* save normal registers */ \ + stw r25,92(r1); + + +#define FINALIZE \ + evldw r14,8(r1); /* restore SPE registers */ \ + evldw r15,16(r1); \ + evldw r16,24(r1); \ + evldw r17,32(r1); \ + evldw r18,40(r1); \ + evldw r19,48(r1); \ + evldw r20,56(r1); \ + evldw r21,64(r1); \ + evldw r22,72(r1); \ + evldw r23,80(r1); \ + lwz r24,88(r1); /* restore normal registers */ \ + lwz r25,92(r1); \ + xor r0,r0,r0; \ + stw r0,8(r1); /* Delete sensitive data */ \ + stw r0,16(r1); /* that we might have pushed */ \ + stw r0,24(r1); /* from other context that runs */ \ + stw r0,32(r1); /* the same code. Assume that */ \ + stw r0,40(r1); /* the lower part of the GPRs */ \ + stw r0,48(r1); /* was already overwritten on */ \ + stw r0,56(r1); /* the way down to here */ \ + stw r0,64(r1); \ + stw r0,72(r1); \ + stw r0,80(r1); \ + addi r1,r1,128; /* cleanup stack frame */ + +#ifdef __BIG_ENDIAN__ +#define LOAD_DATA(reg, off) \ + lwz reg,off(rWP); /* load data */ +#define NEXT_BLOCK \ + addi rWP,rWP,64; /* increment per block */ +#else +#define LOAD_DATA(reg, off) \ + lwbrx reg,0,rWP; /* load data */ \ + addi rWP,rWP,4; /* increment per word */ +#define NEXT_BLOCK /* nothing to do */ +#endif + +#define R_LOAD_W(a, b, c, d, e, f, g, h, w, off) \ + LOAD_DATA(w, off) /* 1: W */ \ + rotrwi rT0,e,6; /* 1: S1 = e rotr 6 */ \ + rotrwi rT1,e,11; /* 1: S1' = e rotr 11 */ \ + rotrwi rT2,e,25; /* 1: S1" = e rotr 25 */ \ + xor rT0,rT0,rT1; /* 1: S1 = S1 xor S1' */ \ + and rT3,e,f; /* 1: ch = e and f */ \ + xor rT0,rT0,rT2; /* 1: S1 = S1 xor S1" */ \ + andc rT1,g,e; /* 1: ch' = ~e and g */ \ + lwz rT2,off(rKP); /* 1: K */ \ + xor rT3,rT3,rT1; /* 1: ch = ch xor ch' */ \ + add h,h,rT0; /* 1: temp1 = h + S1 */ \ + add rT3,rT3,w; /* 1: temp1' = ch + w */ \ + rotrwi rT0,a,2; /* 1: S0 = a rotr 2 */ \ + add h,h,rT3; /* 1: temp1 = temp1 + temp1' */ \ + rotrwi rT1,a,13; /* 1: S0' = a rotr 13 */ \ + add h,h,rT2; /* 1: temp1 = temp1 + K */ \ + rotrwi rT3,a,22; /* 1: S0" = a rotr 22 */ \ + xor rT0,rT0,rT1; /* 1: S0 = S0 xor S0' */ \ + add d,d,h; /* 1: d = d + temp1 */ \ + xor rT3,rT0,rT3; /* 1: S0 = S0 xor S0" */ \ + evmergelo w,w,w; /* shift W */ \ + or rT2,a,b; /* 1: maj = a or b */ \ + and rT1,a,b; /* 1: maj' = a and b */ \ + and rT2,rT2,c; /* 1: maj = maj and c */ \ + LOAD_DATA(w, off+4) /* 2: W */ \ + or rT2,rT1,rT2; /* 1: maj = maj or maj' */ \ + rotrwi rT0,d,6; /* 2: S1 = e rotr 6 */ \ + add rT3,rT3,rT2; /* 1: temp2 = S0 + maj */ \ + rotrwi rT1,d,11; /* 2: S1' = e rotr 11 */ \ + add h,h,rT3; /* 1: h = temp1 + temp2 */ \ + rotrwi rT2,d,25; /* 2: S1" = e rotr 25 */ \ + xor rT0,rT0,rT1; /* 2: S1 = S1 xor S1' */ \ + and rT3,d,e; /* 2: ch = e and f */ \ + xor rT0,rT0,rT2; /* 2: S1 = S1 xor S1" */ \ + andc rT1,f,d; /* 2: ch' = ~e and g */ \ + lwz rT2,off+4(rKP); /* 2: K */ \ + xor rT3,rT3,rT1; /* 2: ch = ch xor ch' */ \ + add g,g,rT0; /* 2: temp1 = h + S1 */ \ + add rT3,rT3,w; /* 2: temp1' = ch + w */ \ + rotrwi rT0,h,2; /* 2: S0 = a rotr 2 */ \ + add g,g,rT3; /* 2: temp1 = temp1 + temp1' */ \ + rotrwi rT1,h,13; /* 2: S0' = a rotr 13 */ \ + add g,g,rT2; /* 2: temp1 = temp1 + K */ \ + rotrwi rT3,h,22; /* 2: S0" = a rotr 22 */ \ + xor rT0,rT0,rT1; /* 2: S0 = S0 xor S0' */ \ + or rT2,h,a; /* 2: maj = a or b */ \ + xor rT3,rT0,rT3; /* 2: S0 = S0 xor S0" */ \ + and rT1,h,a; /* 2: maj' = a and b */ \ + and rT2,rT2,b; /* 2: maj = maj and c */ \ + add c,c,g; /* 2: d = d + temp1 */ \ + or rT2,rT1,rT2; /* 2: maj = maj or maj' */ \ + add rT3,rT3,rT2; /* 2: temp2 = S0 + maj */ \ + add g,g,rT3 /* 2: h = temp1 + temp2 */ + +#define R_CALC_W(a, b, c, d, e, f, g, h, w0, w1, w4, w5, w7, k, off) \ + rotrwi rT2,e,6; /* 1: S1 = e rotr 6 */ \ + evmergelohi rT0,w0,w1; /* w[-15] */ \ + rotrwi rT3,e,11; /* 1: S1' = e rotr 11 */ \ + evsrwiu rT1,rT0,3; /* s0 = w[-15] >> 3 */ \ + xor rT2,rT2,rT3; /* 1: S1 = S1 xor S1' */ \ + evrlwi rT0,rT0,25; /* s0' = w[-15] rotr 7 */ \ + rotrwi rT3,e,25; /* 1: S1' = e rotr 25 */ \ + evxor rT1,rT1,rT0; /* s0 = s0 xor s0' */ \ + xor rT2,rT2,rT3; /* 1: S1 = S1 xor S1' */ \ + evrlwi rT0,rT0,21; /* s0' = w[-15] rotr 18 */ \ + add h,h,rT2; /* 1: temp1 = h + S1 */ \ + evxor rT0,rT0,rT1; /* s0 = s0 xor s0' */ \ + and rT2,e,f; /* 1: ch = e and f */ \ + evaddw w0,w0,rT0; /* w = w[-16] + s0 */ \ + andc rT3,g,e; /* 1: ch' = ~e and g */ \ + evsrwiu rT0,w7,10; /* s1 = w[-2] >> 10 */ \ + xor rT2,rT2,rT3; /* 1: ch = ch xor ch' */ \ + evrlwi rT1,w7,15; /* s1' = w[-2] rotr 17 */ \ + add h,h,rT2; /* 1: temp1 = temp1 + ch */ \ + evxor rT0,rT0,rT1; /* s1 = s1 xor s1' */ \ + rotrwi rT2,a,2; /* 1: S0 = a rotr 2 */ \ + evrlwi rT1,w7,13; /* s1' = w[-2] rotr 19 */ \ + rotrwi rT3,a,13; /* 1: S0' = a rotr 13 */ \ + evxor rT0,rT0,rT1; /* s1 = s1 xor s1' */ \ + xor rT2,rT2,rT3; /* 1: S0 = S0 xor S0' */ \ + evldw rT1,off(rKP); /* k */ \ + rotrwi rT3,a,22; /* 1: S0' = a rotr 22 */ \ + evaddw w0,w0,rT0; /* w = w + s1 */ \ + xor rT2,rT2,rT3; /* 1: S0 = S0 xor S0' */ \ + evmergelohi rT0,w4,w5; /* w[-7] */ \ + and rT3,a,b; /* 1: maj = a and b */ \ + evaddw w0,w0,rT0; /* w = w + w[-7] */ \ + CMP_K##k##_LOOP \ + add rT2,rT2,rT3; /* 1: temp2 = S0 + maj */ \ + evaddw rT1,rT1,w0; /* wk = w + k */ \ + xor rT3,a,b; /* 1: maj = a xor b */ \ + evmergehi rT0,rT1,rT1; /* wk1/wk2 */ \ + and rT3,rT3,c; /* 1: maj = maj and c */ \ + add h,h,rT0; /* 1: temp1 = temp1 + wk */ \ + add rT2,rT2,rT3; /* 1: temp2 = temp2 + maj */ \ + add g,g,rT1; /* 2: temp1 = temp1 + wk */ \ + add d,d,h; /* 1: d = d + temp1 */ \ + rotrwi rT0,d,6; /* 2: S1 = e rotr 6 */ \ + add h,h,rT2; /* 1: h = temp1 + temp2 */ \ + rotrwi rT1,d,11; /* 2: S1' = e rotr 11 */ \ + rotrwi rT2,d,25; /* 2: S" = e rotr 25 */ \ + xor rT0,rT0,rT1; /* 2: S1 = S1 xor S1' */ \ + and rT3,d,e; /* 2: ch = e and f */ \ + xor rT0,rT0,rT2; /* 2: S1 = S1 xor S1" */ \ + andc rT1,f,d; /* 2: ch' = ~e and g */ \ + add g,g,rT0; /* 2: temp1 = h + S1 */ \ + xor rT3,rT3,rT1; /* 2: ch = ch xor ch' */ \ + rotrwi rT0,h,2; /* 2: S0 = a rotr 2 */ \ + add g,g,rT3; /* 2: temp1 = temp1 + ch */ \ + rotrwi rT1,h,13; /* 2: S0' = a rotr 13 */ \ + rotrwi rT3,h,22; /* 2: S0" = a rotr 22 */ \ + xor rT0,rT0,rT1; /* 2: S0 = S0 xor S0' */ \ + or rT2,h,a; /* 2: maj = a or b */ \ + and rT1,h,a; /* 2: maj' = a and b */ \ + and rT2,rT2,b; /* 2: maj = maj and c */ \ + xor rT3,rT0,rT3; /* 2: S0 = S0 xor S0" */ \ + or rT2,rT1,rT2; /* 2: maj = maj or maj' */ \ + add c,c,g; /* 2: d = d + temp1 */ \ + add rT3,rT3,rT2; /* 2: temp2 = S0 + maj */ \ + add g,g,rT3 /* 2: h = temp1 + temp2 */ + +_GLOBAL(ppc_spe_sha256_transform) + INITIALIZE + + mtctr r5 + lwz rH0,0(rHP) + lwz rH1,4(rHP) + lwz rH2,8(rHP) + lwz rH3,12(rHP) + lwz rH4,16(rHP) + lwz rH5,20(rHP) + lwz rH6,24(rHP) + lwz rH7,28(rHP) + +ppc_spe_sha256_main: + lis rKP,PPC_SPE_SHA256_K@ha + addi rKP,rKP,PPC_SPE_SHA256_K@l + + R_LOAD_W(rH0, rH1, rH2, rH3, rH4, rH5, rH6, rH7, rW0, 0) + R_LOAD_W(rH6, rH7, rH0, rH1, rH2, rH3, rH4, rH5, rW1, 8) + R_LOAD_W(rH4, rH5, rH6, rH7, rH0, rH1, rH2, rH3, rW2, 16) + R_LOAD_W(rH2, rH3, rH4, rH5, rH6, rH7, rH0, rH1, rW3, 24) + R_LOAD_W(rH0, rH1, rH2, rH3, rH4, rH5, rH6, rH7, rW4, 32) + R_LOAD_W(rH6, rH7, rH0, rH1, rH2, rH3, rH4, rH5, rW5, 40) + R_LOAD_W(rH4, rH5, rH6, rH7, rH0, rH1, rH2, rH3, rW6, 48) + R_LOAD_W(rH2, rH3, rH4, rH5, rH6, rH7, rH0, rH1, rW7, 56) +ppc_spe_sha256_16_rounds: + addi rKP,rKP,64 + R_CALC_W(rH0, rH1, rH2, rH3, rH4, rH5, rH6, rH7, + rW0, rW1, rW4, rW5, rW7, N, 0) + R_CALC_W(rH6, rH7, rH0, rH1, rH2, rH3, rH4, rH5, + rW1, rW2, rW5, rW6, rW0, N, 8) + R_CALC_W(rH4, rH5, rH6, rH7, rH0, rH1, rH2, rH3, + rW2, rW3, rW6, rW7, rW1, N, 16) + R_CALC_W(rH2, rH3, rH4, rH5, rH6, rH7, rH0, rH1, + rW3, rW4, rW7, rW0, rW2, N, 24) + R_CALC_W(rH0, rH1, rH2, rH3, rH4, rH5, rH6, rH7, + rW4, rW5, rW0, rW1, rW3, N, 32) + R_CALC_W(rH6, rH7, rH0, rH1, rH2, rH3, rH4, rH5, + rW5, rW6, rW1, rW2, rW4, N, 40) + R_CALC_W(rH4, rH5, rH6, rH7, rH0, rH1, rH2, rH3, + rW6, rW7, rW2, rW3, rW5, N, 48) + R_CALC_W(rH2, rH3, rH4, rH5, rH6, rH7, rH0, rH1, + rW7, rW0, rW3, rW4, rW6, C, 56) + bt gt,ppc_spe_sha256_16_rounds + + lwz rW0,0(rHP) + NEXT_BLOCK + lwz rW1,4(rHP) + lwz rW2,8(rHP) + lwz rW3,12(rHP) + lwz rW4,16(rHP) + lwz rW5,20(rHP) + lwz rW6,24(rHP) + lwz rW7,28(rHP) + + add rH0,rH0,rW0 + stw rH0,0(rHP) + add rH1,rH1,rW1 + stw rH1,4(rHP) + add rH2,rH2,rW2 + stw rH2,8(rHP) + add rH3,rH3,rW3 + stw rH3,12(rHP) + add rH4,rH4,rW4 + stw rH4,16(rHP) + add rH5,rH5,rW5 + stw rH5,20(rHP) + add rH6,rH6,rW6 + stw rH6,24(rHP) + add rH7,rH7,rW7 + stw rH7,28(rHP) + + bdnz ppc_spe_sha256_main + + FINALIZE + blr + +.data +.align 5 +PPC_SPE_SHA256_K: + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 -- GitLab From c147028ccc249681ef1129fb4b09f71fe6b75715 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 30 Jan 2015 15:39:29 +0100 Subject: [PATCH 0087/1910] crypto: ppc/sha256 - glue Glue code for crypto infrastructure. Call the assembler code where required. Disable preemption during calculation and enable SPE instructions in the kernel prior to the call. Avoid to disable preemption for too long. Take a little care about small input data. Kick out early for input chunks < 64 bytes and replace memset for context cleanup with simple loop. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/sha256_spe_glue.c | 275 ++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 arch/powerpc/crypto/sha256_spe_glue.c diff --git a/arch/powerpc/crypto/sha256_spe_glue.c b/arch/powerpc/crypto/sha256_spe_glue.c new file mode 100644 index 000000000000..f4a616fe1a82 --- /dev/null +++ b/arch/powerpc/crypto/sha256_spe_glue.c @@ -0,0 +1,275 @@ +/* + * Glue code for SHA-256 implementation for SPE instructions (PPC) + * + * Based on generic implementation. The assembler module takes care + * about the SPE registers so it can run from interrupt context. + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MAX_BYTES defines the number of bytes that are allowed to be processed + * between preempt_disable() and preempt_enable(). SHA256 takes ~2,000 + * operations per 64 bytes. e500 cores can issue two arithmetic instructions + * per clock cycle using one 32/64 bit unit (SU1) and one 32 bit unit (SU2). + * Thus 1KB of input data will need an estimated maximum of 18,000 cycles. + * Headroom for cache misses included. Even with the low end model clocked + * at 667 MHz this equals to a critical time window of less than 27us. + * + */ +#define MAX_BYTES 1024 + +extern void ppc_spe_sha256_transform(u32 *state, const u8 *src, u32 blocks); + +static void spe_begin(void) +{ + /* We just start SPE operations and will save SPE registers later. */ + preempt_disable(); + enable_kernel_spe(); +} + +static void spe_end(void) +{ + /* reenable preemption */ + preempt_enable(); +} + +static inline void ppc_sha256_clear_context(struct sha256_state *sctx) +{ + int count = sizeof(struct sha256_state) >> 2; + u32 *ptr = (u32 *)sctx; + + /* make sure we can clear the fast way */ + BUILD_BUG_ON(sizeof(struct sha256_state) % 4); + do { *ptr++ = 0; } while (--count); +} + +static int ppc_spe_sha256_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; + sctx->count = 0; + + return 0; +} + +static int ppc_spe_sha224_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA224_H0; + sctx->state[1] = SHA224_H1; + sctx->state[2] = SHA224_H2; + sctx->state[3] = SHA224_H3; + sctx->state[4] = SHA224_H4; + sctx->state[5] = SHA224_H5; + sctx->state[6] = SHA224_H6; + sctx->state[7] = SHA224_H7; + sctx->count = 0; + + return 0; +} + +static int ppc_spe_sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->count & 0x3f; + const unsigned int avail = 64 - offset; + unsigned int bytes; + const u8 *src = data; + + if (avail > len) { + sctx->count += len; + memcpy((char *)sctx->buf + offset, src, len); + return 0; + } + + sctx->count += len; + + if (offset) { + memcpy((char *)sctx->buf + offset, src, avail); + + spe_begin(); + ppc_spe_sha256_transform(sctx->state, (const u8 *)sctx->buf, 1); + spe_end(); + + len -= avail; + src += avail; + } + + while (len > 63) { + /* cut input data into smaller blocks */ + bytes = (len > MAX_BYTES) ? MAX_BYTES : len; + bytes = bytes & ~0x3f; + + spe_begin(); + ppc_spe_sha256_transform(sctx->state, src, bytes >> 6); + spe_end(); + + src += bytes; + len -= bytes; + }; + + memcpy((char *)sctx->buf, src, len); + return 0; +} + +static int ppc_spe_sha256_final(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->count & 0x3f; + char *p = (char *)sctx->buf + offset; + int padlen; + __be64 *pbits = (__be64 *)(((char *)&sctx->buf) + 56); + __be32 *dst = (__be32 *)out; + + padlen = 55 - offset; + *p++ = 0x80; + + spe_begin(); + + if (padlen < 0) { + memset(p, 0x00, padlen + sizeof (u64)); + ppc_spe_sha256_transform(sctx->state, sctx->buf, 1); + p = (char *)sctx->buf; + padlen = 56; + } + + memset(p, 0, padlen); + *pbits = cpu_to_be64(sctx->count << 3); + ppc_spe_sha256_transform(sctx->state, sctx->buf, 1); + + spe_end(); + + dst[0] = cpu_to_be32(sctx->state[0]); + dst[1] = cpu_to_be32(sctx->state[1]); + dst[2] = cpu_to_be32(sctx->state[2]); + dst[3] = cpu_to_be32(sctx->state[3]); + dst[4] = cpu_to_be32(sctx->state[4]); + dst[5] = cpu_to_be32(sctx->state[5]); + dst[6] = cpu_to_be32(sctx->state[6]); + dst[7] = cpu_to_be32(sctx->state[7]); + + ppc_sha256_clear_context(sctx); + return 0; +} + +static int ppc_spe_sha224_final(struct shash_desc *desc, u8 *out) +{ + u32 D[SHA256_DIGEST_SIZE >> 2]; + __be32 *dst = (__be32 *)out; + + ppc_spe_sha256_final(desc, (u8 *)D); + + /* avoid bytewise memcpy */ + dst[0] = D[0]; + dst[1] = D[1]; + dst[2] = D[2]; + dst[3] = D[3]; + dst[4] = D[4]; + dst[5] = D[5]; + dst[6] = D[6]; + + /* clear sensitive data */ + memzero_explicit(D, SHA256_DIGEST_SIZE); + return 0; +} + +static int ppc_spe_sha256_export(struct shash_desc *desc, void *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int ppc_spe_sha256_import(struct shash_desc *desc, const void *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg algs[2] = { { + .digestsize = SHA256_DIGEST_SIZE, + .init = ppc_spe_sha256_init, + .update = ppc_spe_sha256_update, + .final = ppc_spe_sha256_final, + .export = ppc_spe_sha256_export, + .import = ppc_spe_sha256_import, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256", + .cra_driver_name= "sha256-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}, { + .digestsize = SHA224_DIGEST_SIZE, + .init = ppc_spe_sha224_init, + .update = ppc_spe_sha256_update, + .final = ppc_spe_sha224_final, + .export = ppc_spe_sha256_export, + .import = ppc_spe_sha256_import, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha224", + .cra_driver_name= "sha224-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} }; + +static int __init ppc_spe_sha256_mod_init(void) +{ + return crypto_register_shashes(algs, ARRAY_SIZE(algs)); +} + +static void __exit ppc_spe_sha256_mod_fini(void) +{ + crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); +} + +module_init(ppc_spe_sha256_mod_init); +module_exit(ppc_spe_sha256_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, SPE optimized"); + +MODULE_ALIAS_CRYPTO("sha224"); +MODULE_ALIAS_CRYPTO("sha224-ppc-spe"); +MODULE_ALIAS_CRYPTO("sha256"); +MODULE_ALIAS_CRYPTO("sha256-ppc-spe"); -- GitLab From 2ecc1e95ec70923e642fa481ee7f7ad443798f2a Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 30 Jan 2015 15:39:34 +0100 Subject: [PATCH 0088/1910] crypto: ppc/sha256 - kernel config Integrate the module into the kernel config tree. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Makefile | 2 ++ crypto/Kconfig | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index 2926fb9c570a..a07e763befb5 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -5,5 +5,7 @@ # obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o +obj-$(CONFIG_CRYPTO_SHA256_PPC_SPE) += sha256-ppc-spe.o sha1-powerpc-y := sha1-powerpc-asm.o sha1.o +sha256-ppc-spe-y := sha256-spe-asm.o sha256_spe_glue.o diff --git a/crypto/Kconfig b/crypto/Kconfig index 50f4da44a304..2ca8d15e0b6f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -610,6 +610,15 @@ config CRYPTO_SHA256 This code also includes SHA-224, a 224 bit hash with 112 bits of security against collision attacks. +config CRYPTO_SHA256_PPC_SPE + tristate "SHA224 and SHA256 digest algorithm (PPC SPE)" + depends on PPC && SPE + select CRYPTO_SHA256 + select CRYPTO_HASH + help + SHA224 and SHA256 secure hash standard (DFIPS 180-2) + implemented using powerpc SPE SIMD instruction set. + config CRYPTO_SHA256_SPARC64 tristate "SHA224 and SHA256 digest algorithm (SPARC64)" depends on SPARC64 -- GitLab From 8db8846754767bc955eaf7e28db8a94787d12ce6 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 3 Feb 2015 13:07:05 -0600 Subject: [PATCH 0089/1910] crypto: ccp - Updates for checkpatch warnings/errors Changes to address warnings and errors reported by the checkpatch script. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-aes-cmac.c | 12 +++++++----- drivers/crypto/ccp/ccp-crypto-aes-xts.c | 4 +--- drivers/crypto/ccp/ccp-crypto-aes.c | 3 +-- drivers/crypto/ccp/ccp-crypto-main.c | 5 ++--- drivers/crypto/ccp/ccp-crypto-sha.c | 12 +++++++----- drivers/crypto/ccp/ccp-crypto.h | 3 --- drivers/crypto/ccp/ccp-dev.c | 5 +---- drivers/crypto/ccp/ccp-dev.h | 12 ++++-------- drivers/crypto/ccp/ccp-ops.c | 24 ++++++++++++------------ drivers/crypto/ccp/ccp-pci.c | 2 +- drivers/crypto/ccp/ccp-platform.c | 1 - 11 files changed, 36 insertions(+), 47 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c index 8e162ad82085..ea7e8446956a 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c @@ -23,7 +23,6 @@ #include "ccp-crypto.h" - static int ccp_aes_cmac_complete(struct crypto_async_request *async_req, int ret) { @@ -38,11 +37,13 @@ static int ccp_aes_cmac_complete(struct crypto_async_request *async_req, if (rctx->hash_rem) { /* Save remaining data to buffer */ unsigned int offset = rctx->nbytes - rctx->hash_rem; + scatterwalk_map_and_copy(rctx->buf, rctx->src, offset, rctx->hash_rem, 0); rctx->buf_count = rctx->hash_rem; - } else + } else { rctx->buf_count = 0; + } /* Update result area if supplied */ if (req->result) @@ -202,7 +203,7 @@ static int ccp_aes_cmac_digest(struct ahash_request *req) } static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, - unsigned int key_len) + unsigned int key_len) { struct ccp_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); struct ccp_crypto_ahash_alg *alg = @@ -292,7 +293,8 @@ static int ccp_aes_cmac_cra_init(struct crypto_tfm *tfm) crypto_ahash_set_reqsize(ahash, sizeof(struct ccp_aes_cmac_req_ctx)); cipher_tfm = crypto_alloc_cipher("aes", 0, - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(cipher_tfm)) { pr_warn("could not load aes cipher driver\n"); return PTR_ERR(cipher_tfm); @@ -354,7 +356,7 @@ int ccp_register_aes_cmac_algs(struct list_head *head) ret = crypto_register_ahash(alg); if (ret) { pr_err("%s ahash algorithm registration error (%d)\n", - base->cra_name, ret); + base->cra_name, ret); kfree(ccp_alg); return ret; } diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 0cc5594b7de3..52c7395cb8d8 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -21,7 +21,6 @@ #include "ccp-crypto.h" - struct ccp_aes_xts_def { const char *name; const char *drv_name; @@ -216,7 +215,6 @@ static void ccp_aes_xts_cra_exit(struct crypto_tfm *tfm) ctx->u.aes.tfm_ablkcipher = NULL; } - static int ccp_register_aes_xts_alg(struct list_head *head, const struct ccp_aes_xts_def *def) { @@ -255,7 +253,7 @@ static int ccp_register_aes_xts_alg(struct list_head *head, ret = crypto_register_alg(alg); if (ret) { pr_err("%s ablkcipher algorithm registration error (%d)\n", - alg->cra_name, ret); + alg->cra_name, ret); kfree(ccp_alg); return ret; } diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index e46490db0f63..7984f910884d 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -22,7 +22,6 @@ #include "ccp-crypto.h" - static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) { struct ablkcipher_request *req = ablkcipher_request_cast(async_req); @@ -345,7 +344,7 @@ static int ccp_register_aes_alg(struct list_head *head, ret = crypto_register_alg(alg); if (ret) { pr_err("%s ablkcipher algorithm registration error (%d)\n", - alg->cra_name, ret); + alg->cra_name, ret); kfree(ccp_alg); return ret; } diff --git a/drivers/crypto/ccp/ccp-crypto-main.c b/drivers/crypto/ccp/ccp-crypto-main.c index 4d4e016d755b..bdec01ec608f 100644 --- a/drivers/crypto/ccp/ccp-crypto-main.c +++ b/drivers/crypto/ccp/ccp-crypto-main.c @@ -33,7 +33,6 @@ static unsigned int sha_disable; module_param(sha_disable, uint, 0444); MODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value"); - /* List heads for the supported algorithms */ static LIST_HEAD(hash_algs); static LIST_HEAD(cipher_algs); @@ -48,6 +47,7 @@ struct ccp_crypto_queue { struct list_head *backlog; unsigned int cmd_count; }; + #define CCP_CRYPTO_MAX_QLEN 100 static struct ccp_crypto_queue req_queue; @@ -77,7 +77,6 @@ struct ccp_crypto_cpu { int err; }; - static inline bool ccp_crypto_success(int err) { if (err && (err != -EINPROGRESS) && (err != -EBUSY)) @@ -143,7 +142,7 @@ static void ccp_crypto_complete(void *data, int err) int ret; if (err == -EINPROGRESS) { - /* Only propogate the -EINPROGRESS if necessary */ + /* Only propagate the -EINPROGRESS if necessary */ if (crypto_cmd->ret == -EBUSY) { crypto_cmd->ret = -EINPROGRESS; req->complete(req, -EINPROGRESS); diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c index 96531571f7cf..507b34e0cc19 100644 --- a/drivers/crypto/ccp/ccp-crypto-sha.c +++ b/drivers/crypto/ccp/ccp-crypto-sha.c @@ -23,7 +23,6 @@ #include "ccp-crypto.h" - static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) { struct ahash_request *req = ahash_request_cast(async_req); @@ -37,11 +36,13 @@ static int ccp_sha_complete(struct crypto_async_request *async_req, int ret) if (rctx->hash_rem) { /* Save remaining data to buffer */ unsigned int offset = rctx->nbytes - rctx->hash_rem; + scatterwalk_map_and_copy(rctx->buf, rctx->src, offset, rctx->hash_rem, 0); rctx->buf_count = rctx->hash_rem; - } else + } else { rctx->buf_count = 0; + } /* Update result area if supplied */ if (req->result) @@ -227,8 +228,9 @@ static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key, } key_len = digest_size; - } else + } else { memcpy(ctx->u.sha.key, key, key_len); + } for (i = 0; i < block_size; i++) { ctx->u.sha.ipad[i] = ctx->u.sha.key[i] ^ 0x36; @@ -355,7 +357,7 @@ static int ccp_register_hmac_alg(struct list_head *head, ret = crypto_register_ahash(alg); if (ret) { pr_err("%s ahash algorithm registration error (%d)\n", - base->cra_name, ret); + base->cra_name, ret); kfree(ccp_alg); return ret; } @@ -410,7 +412,7 @@ static int ccp_register_sha_alg(struct list_head *head, ret = crypto_register_ahash(alg); if (ret) { pr_err("%s ahash algorithm registration error (%d)\n", - base->cra_name, ret); + base->cra_name, ret); kfree(ccp_alg); return ret; } diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h index 9aa4ae184f7f..76a96f0f44c6 100644 --- a/drivers/crypto/ccp/ccp-crypto.h +++ b/drivers/crypto/ccp/ccp-crypto.h @@ -13,7 +13,6 @@ #ifndef __CCP_CRYPTO_H__ #define __CCP_CRYPTO_H__ - #include #include #include @@ -25,7 +24,6 @@ #include #include - #define CCP_CRA_PRIORITY 300 struct ccp_crypto_ablkcipher_alg { @@ -68,7 +66,6 @@ static inline struct ccp_crypto_ahash_alg * return container_of(ahash_alg, struct ccp_crypto_ahash_alg, alg); } - /***** AES related defines *****/ struct ccp_aes_ctx { /* Fallback cipher for XTS with unsupported unit sizes */ diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index ca29c120b85f..68c637af2c42 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -37,7 +37,6 @@ struct ccp_tasklet_data { struct ccp_cmd *cmd; }; - static struct ccp_device *ccp_dev; static inline struct ccp_device *ccp_get_device(void) { @@ -297,10 +296,8 @@ struct ccp_device *ccp_alloc_struct(struct device *dev) struct ccp_device *ccp; ccp = kzalloc(sizeof(*ccp), GFP_KERNEL); - if (ccp == NULL) { - dev_err(dev, "unable to allocate device struct\n"); + if (!ccp) return NULL; - } ccp->dev = dev; INIT_LIST_HEAD(&ccp->cmd); diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 62ff35a6b9ec..6ff89031fb96 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -21,7 +21,7 @@ #include #include #include - +#include #define MAX_DMAPOOL_NAME_LEN 32 @@ -33,7 +33,6 @@ #define CACHE_NONE 0x00 #define CACHE_WB_NO_ALLOC 0xb7 - /****** Register Mappings ******/ #define Q_MASK_REG 0x000 #define TRNG_OUT_REG 0x00c @@ -54,8 +53,8 @@ #define CMD_Q_CACHE_BASE 0x228 #define CMD_Q_CACHE_INC 0x20 -#define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f); -#define CMD_Q_DEPTH(__qs) (((__qs) >> 12) & 0x0000000f); +#define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f) +#define CMD_Q_DEPTH(__qs) (((__qs) >> 12) & 0x0000000f) /****** REQ0 Related Values ******/ #define REQ0_WAIT_FOR_WRITE 0x00000004 @@ -103,7 +102,6 @@ /****** REQ6 Related Values ******/ #define REQ6_MEMTYPE_SHIFT 16 - /****** Key Storage Block ******/ #define KSB_START 77 #define KSB_END 127 @@ -114,7 +112,7 @@ #define CCP_JOBID_MASK 0x0000003f #define CCP_DMAPOOL_MAX_SIZE 64 -#define CCP_DMAPOOL_ALIGN (1 << 5) +#define CCP_DMAPOOL_ALIGN BIT(5) #define CCP_REVERSE_BUF_SIZE 64 @@ -142,7 +140,6 @@ #define CCP_ECC_RESULT_OFFSET 60 #define CCP_ECC_RESULT_SUCCESS 0x0001 - struct ccp_device; struct ccp_cmd; @@ -261,7 +258,6 @@ struct ccp_device { unsigned int axcache; }; - int ccp_pci_init(void); void ccp_pci_exit(void); diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 8729364261d7..71f2e3c89424 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -27,7 +27,6 @@ #include "ccp-dev.h" - enum ccp_memtype { CCP_MEMTYPE_SYSTEM = 0, CCP_MEMTYPE_KSB, @@ -515,7 +514,6 @@ static int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev, if (!wa->dma_count) return -ENOMEM; - return 0; } @@ -763,8 +761,9 @@ static void ccp_prepare_data(struct ccp_data *src, struct ccp_data *dst, sg_dst_len = sg_dma_len(dst->sg_wa.sg) - dst->sg_wa.sg_used; sg_dst_len = min_t(u64, src->sg_wa.bytes_left, sg_dst_len); op_len = min(sg_src_len, sg_dst_len); - } else + } else { op_len = sg_src_len; + } /* The data operation length will be at least block_size in length * or the smaller of available sg room remaining for the source or @@ -1131,9 +1130,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) goto e_ctx; - if (in_place) + if (in_place) { dst = src; - else { + } else { ret = ccp_init_data(&dst, cmd_q, aes->dst, aes->src_len, AES_BLOCK_SIZE, DMA_FROM_DEVICE); if (ret) @@ -1304,9 +1303,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, if (ret) goto e_ctx; - if (in_place) + if (in_place) { dst = src; - else { + } else { ret = ccp_init_data(&dst, cmd_q, xts->dst, xts->src_len, unit_size, DMA_FROM_DEVICE); if (ret) @@ -1451,8 +1450,9 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) goto e_ctx; } memcpy(ctx.address, init, CCP_SHA_CTXSIZE); - } else + } else { ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + } ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, CCP_PASSTHRU_BYTESWAP_256BIT); @@ -1732,9 +1732,9 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, if (ret) goto e_mask; - if (in_place) + if (in_place) { dst = src; - else { + } else { ret = ccp_init_data(&dst, cmd_q, pt->dst, pt->src_len, CCP_PASSTHRU_MASKSIZE, DMA_FROM_DEVICE); if (ret) @@ -1974,7 +1974,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) src.address += CCP_ECC_OPERAND_SIZE; /* Set the first point Z coordianate to 1 */ - *(src.address) = 0x01; + *src.address = 0x01; src.address += CCP_ECC_OPERAND_SIZE; if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) { @@ -1989,7 +1989,7 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) src.address += CCP_ECC_OPERAND_SIZE; /* Set the second point Z coordianate to 1 */ - *(src.address) = 0x01; + *src.address = 0x01; src.address += CCP_ECC_OPERAND_SIZE; } else { /* Copy the Domain "a" parameter */ diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c index 7f89c946adfe..1980f77c29ef 100644 --- a/drivers/crypto/ccp/ccp-pci.c +++ b/drivers/crypto/ccp/ccp-pci.c @@ -204,7 +204,7 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = -EIO; ccp->io_map = pci_iomap(pdev, bar, 0); - if (ccp->io_map == NULL) { + if (!ccp->io_map) { dev_err(dev, "pci_iomap failed\n"); goto e_device; } diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index 8c50bad25f7e..9e09c5023b5f 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -26,7 +26,6 @@ #include "ccp-dev.h" - static int ccp_get_irq(struct ccp_device *ccp) { struct device *dev = ccp->dev; -- GitLab From a5bd093af0d11611b765d3cbd354e0a39975caab Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 3 Feb 2015 13:07:11 -0600 Subject: [PATCH 0090/1910] crypto: ccp - Update CCP build support Add HAS_IOMEM as a Kconfig dependency. Always include ccp-platform.c in the CCP build and conditionally include ccp-pci.c. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 2 +- drivers/crypto/ccp/Makefile | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 2fb0fdfc87df..b840b79655bc 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -391,7 +391,7 @@ config CRYPTO_DEV_ATMEL_SHA config CRYPTO_DEV_CCP bool "Support for AMD Cryptographic Coprocessor" - depends on (X86 && PCI) || ARM64 + depends on ((X86 && PCI) || ARM64) && HAS_IOMEM default n help The AMD Cryptographic Coprocessor provides hardware support diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index 7f592d8d07bb..55a1f3951578 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -1,11 +1,6 @@ obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o -ccp-objs := ccp-dev.o ccp-ops.o -ifdef CONFIG_X86 -ccp-objs += ccp-pci.o -endif -ifdef CONFIG_ARM64 -ccp-objs += ccp-platform.o -endif +ccp-objs := ccp-dev.o ccp-ops.o ccp-platform.o +ccp-$(CONFIG_PCI) += ccp-pci.o obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o ccp-crypto-objs := ccp-crypto-main.o \ -- GitLab From 261bf074899a1a4624d8a0c6bfae3e92d12ef19f Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 3 Feb 2015 13:07:17 -0600 Subject: [PATCH 0091/1910] crypto: ccp - Use dma_set_mask_and_coherent to set DMA mask Replace the setting of the DMA masks with the dma_set_mask_and_coherent function call. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-platform.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index 9e09c5023b5f..04265a3c3608 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -109,8 +109,11 @@ static int ccp_platform_probe(struct platform_device *pdev) if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; - *(dev->dma_mask) = DMA_BIT_MASK(48); - dev->coherent_dma_mask = DMA_BIT_MASK(48); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); + goto e_free; + } if (of_property_read_bool(dev->of_node, "dma-coherent")) ccp->axcache = CACHE_WB_NO_ALLOC; -- GitLab From be03a3a0961eba0bc695fa91ac87efe5f4b8f40c Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 3 Feb 2015 13:07:23 -0600 Subject: [PATCH 0092/1910] crypto: ccp - Convert calls to their devm_ counterparts Where applicable, convert calls to their devm_ counterparts, e.g. kzalloc to devm_kzalloc. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 2 +- drivers/crypto/ccp/ccp-pci.c | 19 +++++-------------- drivers/crypto/ccp/ccp-platform.c | 11 +++-------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 68c637af2c42..861bacc1bb94 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -295,7 +295,7 @@ struct ccp_device *ccp_alloc_struct(struct device *dev) { struct ccp_device *ccp; - ccp = kzalloc(sizeof(*ccp), GFP_KERNEL); + ccp = devm_kzalloc(dev, sizeof(*ccp), GFP_KERNEL); if (!ccp) return NULL; ccp->dev = dev; diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c index 1980f77c29ef..af190d4795a8 100644 --- a/drivers/crypto/ccp/ccp-pci.c +++ b/drivers/crypto/ccp/ccp-pci.c @@ -174,11 +174,10 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!ccp) goto e_err; - ccp_pci = kzalloc(sizeof(*ccp_pci), GFP_KERNEL); - if (!ccp_pci) { - ret = -ENOMEM; - goto e_free1; - } + ccp_pci = devm_kzalloc(dev, sizeof(*ccp_pci), GFP_KERNEL); + if (!ccp_pci) + goto e_err; + ccp->dev_specific = ccp_pci; ccp->get_irq = ccp_get_irqs; ccp->free_irq = ccp_free_irqs; @@ -186,7 +185,7 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = pci_request_regions(pdev, "ccp"); if (ret) { dev_err(dev, "pci_request_regions failed (%d)\n", ret); - goto e_free2; + goto e_err; } ret = pci_enable_device(pdev); @@ -239,12 +238,6 @@ static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) e_regions: pci_release_regions(pdev); -e_free2: - kfree(ccp_pci); - -e_free1: - kfree(ccp); - e_err: dev_notice(dev, "initialization failed\n"); return ret; @@ -266,8 +259,6 @@ static void ccp_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); - kfree(ccp); - dev_notice(dev, "disabled\n"); } diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index 04265a3c3608..20661f099198 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -103,7 +103,7 @@ static int ccp_platform_probe(struct platform_device *pdev) ccp->io_map = devm_ioremap_resource(dev, ior); if (IS_ERR(ccp->io_map)) { ret = PTR_ERR(ccp->io_map); - goto e_free; + goto e_err; } ccp->io_regs = ccp->io_map; @@ -112,7 +112,7 @@ static int ccp_platform_probe(struct platform_device *pdev) ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); if (ret) { dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); - goto e_free; + goto e_err; } if (of_property_read_bool(dev->of_node, "dma-coherent")) @@ -124,15 +124,12 @@ static int ccp_platform_probe(struct platform_device *pdev) ret = ccp_init(ccp); if (ret) - goto e_free; + goto e_err; dev_notice(dev, "enabled\n"); return 0; -e_free: - kfree(ccp); - e_err: dev_notice(dev, "initialization failed\n"); return ret; @@ -145,8 +142,6 @@ static int ccp_platform_remove(struct platform_device *pdev) ccp_destroy(ccp); - kfree(ccp); - dev_notice(dev, "disabled\n"); return 0; -- GitLab From 6c5063434098b956252d8bb45d7546ff717717e6 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 3 Feb 2015 13:07:29 -0600 Subject: [PATCH 0093/1910] crypto: ccp - Add ACPI support Add support for ACPI to the CCP platform driver. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 2 +- drivers/crypto/ccp/ccp-platform.c | 96 +++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index b840b79655bc..7e94413da6e3 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -391,7 +391,7 @@ config CRYPTO_DEV_ATMEL_SHA config CRYPTO_DEV_CCP bool "Support for AMD Cryptographic Coprocessor" - depends on ((X86 && PCI) || ARM64) && HAS_IOMEM + depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM default n help The AMD Cryptographic Coprocessor provides hardware support diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index 20661f099198..b1c20b2b5647 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -23,9 +23,16 @@ #include #include #include +#include +#include #include "ccp-dev.h" +struct ccp_platform { + int use_acpi; + int coherent; +}; + static int ccp_get_irq(struct ccp_device *ccp) { struct device *dev = ccp->dev; @@ -83,10 +90,64 @@ static struct resource *ccp_find_mmio_area(struct ccp_device *ccp) return NULL; } +#ifdef CONFIG_ACPI +static int ccp_acpi_support(struct ccp_device *ccp) +{ + struct ccp_platform *ccp_platform = ccp->dev_specific; + struct acpi_device *adev = ACPI_COMPANION(ccp->dev); + acpi_handle handle; + acpi_status status; + unsigned long long data; + int cca; + + /* Retrieve the device cache coherency value */ + handle = adev->handle; + do { + status = acpi_evaluate_integer(handle, "_CCA", NULL, &data); + if (!ACPI_FAILURE(status)) { + cca = data; + break; + } + } while (!ACPI_FAILURE(status)); + + if (ACPI_FAILURE(status)) { + dev_err(ccp->dev, "error obtaining acpi coherency value\n"); + return -EINVAL; + } + + ccp_platform->coherent = !!cca; + + return 0; +} +#else /* CONFIG_ACPI */ +static int ccp_acpi_support(struct ccp_device *ccp) +{ + return -EINVAL; +} +#endif + +#ifdef CONFIG_OF +static int ccp_of_support(struct ccp_device *ccp) +{ + struct ccp_platform *ccp_platform = ccp->dev_specific; + + ccp_platform->coherent = of_dma_is_coherent(ccp->dev->of_node); + + return 0; +} +#else +static int ccp_of_support(struct ccp_device *ccp) +{ + return -EINVAL; +} +#endif + static int ccp_platform_probe(struct platform_device *pdev) { struct ccp_device *ccp; + struct ccp_platform *ccp_platform; struct device *dev = &pdev->dev; + struct acpi_device *adev = ACPI_COMPANION(dev); struct resource *ior; int ret; @@ -95,10 +156,16 @@ static int ccp_platform_probe(struct platform_device *pdev) if (!ccp) goto e_err; - ccp->dev_specific = NULL; + ccp_platform = devm_kzalloc(dev, sizeof(*ccp_platform), GFP_KERNEL); + if (!ccp_platform) + goto e_err; + + ccp->dev_specific = ccp_platform; ccp->get_irq = ccp_get_irqs; ccp->free_irq = ccp_free_irqs; + ccp_platform->use_acpi = (!adev || acpi_disabled) ? 0 : 1; + ior = ccp_find_mmio_area(ccp); ccp->io_map = devm_ioremap_resource(dev, ior); if (IS_ERR(ccp->io_map)) { @@ -115,7 +182,14 @@ static int ccp_platform_probe(struct platform_device *pdev) goto e_err; } - if (of_property_read_bool(dev->of_node, "dma-coherent")) + if (ccp_platform->use_acpi) + ret = ccp_acpi_support(ccp); + else + ret = ccp_of_support(ccp); + if (ret) + goto e_err; + + if (ccp_platform->coherent) ccp->axcache = CACHE_WB_NO_ALLOC; else ccp->axcache = CACHE_NONE; @@ -197,15 +271,29 @@ static int ccp_platform_resume(struct platform_device *pdev) } #endif -static const struct of_device_id ccp_platform_ids[] = { +#ifdef CONFIG_ACPI +static const struct acpi_device_id ccp_acpi_match[] = { + { "AMDI0C00", 0 }, + { }, +}; +#endif + +#ifdef CONFIG_OF +static const struct of_device_id ccp_of_match[] = { { .compatible = "amd,ccp-seattle-v1a" }, { }, }; +#endif static struct platform_driver ccp_platform_driver = { .driver = { .name = "AMD Cryptographic Coprocessor", - .of_match_table = ccp_platform_ids, +#ifdef CONFIG_ACPI + .acpi_match_table = ccp_acpi_match, +#endif +#ifdef CONFIG_OF + .of_match_table = ccp_of_match, +#endif }, .probe = ccp_platform_probe, .remove = ccp_platform_remove, -- GitLab From 66c046b407166686aeea2e8c0abfa1c4e4b94f26 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 10:29:35 +0000 Subject: [PATCH 0094/1910] crypto: sha-mb - Fix big integer constant sparse warning this patch fixes following sparse warning: sha1_mb_mgr_init_avx2.c:59:31: warning: constant 0xF76543210 is so big it is long Signed-off-by: Lad, Prabhakar Signed-off-by: Herbert Xu --- arch/x86/crypto/sha-mb/sha1_mb_mgr_init_avx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/crypto/sha-mb/sha1_mb_mgr_init_avx2.c b/arch/x86/crypto/sha-mb/sha1_mb_mgr_init_avx2.c index 4ca7e166a2aa..822acb5b464c 100644 --- a/arch/x86/crypto/sha-mb/sha1_mb_mgr_init_avx2.c +++ b/arch/x86/crypto/sha-mb/sha1_mb_mgr_init_avx2.c @@ -56,7 +56,7 @@ void sha1_mb_mgr_init_avx2(struct sha1_mb_mgr *state) { unsigned int j; - state->unused_lanes = 0xF76543210; + state->unused_lanes = 0xF76543210ULL; for (j = 0; j < 8; j++) { state->lens[j] = 0xFFFFFFFF; state->ldata[j].job_in_lane = NULL; -- GitLab From 41a4695ca46d8798f89b477855973eb2ad3f4f69 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 27 Feb 2013 08:37:56 -0800 Subject: [PATCH 0095/1910] Yama: do not modify global sysctl table entry When the sysctl table is constified, we won't be able to directly modify it. Instead, use a table copy that carries any needed changes. Suggested-by: PaX Team Signed-off-by: Kees Cook --- security/yama/yama_lsm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 13c88fbcf037..24aae2ae2b30 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -379,20 +379,17 @@ static struct security_operations yama_ops = { static int yama_dointvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - int rc; + struct ctl_table table_copy; if (write && !capable(CAP_SYS_PTRACE)) return -EPERM; - rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (rc) - return rc; - /* Lock the max value if it ever gets set. */ - if (write && *(int *)table->data == *(int *)table->extra2) - table->extra1 = table->extra2; + table_copy = *table; + if (*(int *)table_copy.data == *(int *)table_copy.extra2) + table_copy.extra1 = table_copy.extra2; - return rc; + return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos); } static int zero; -- GitLab From 44aa1d4413876cca0962debc9483ba009d71737f Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Fri, 27 Feb 2015 16:23:59 -0500 Subject: [PATCH 0096/1910] security/yama: Remove unnecessary selects from Kconfig. Yama selects SECURITYFS and SECURITY_PATH, but requires neither. Remove them. Signed-off-by: Stephen Smalley Signed-off-by: Kees Cook --- security/yama/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 20ef5143c0c0..3123e1da2fed 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig @@ -1,8 +1,6 @@ config SECURITY_YAMA bool "Yama support" depends on SECURITY - select SECURITYFS - select SECURITY_PATH default n help This selects Yama, which extends DAC support with additional -- GitLab From 20a26faa7e623fd1344bc39d201a27ea440b2ad2 Mon Sep 17 00:00:00 2001 From: "Marcelo H. Cerri" Date: Fri, 6 Feb 2015 14:56:50 -0200 Subject: [PATCH 0097/1910] crypto: vmx - Adding VMX module for Power 8 This patch adds routines supporting VMX instructions on the Power 8. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/vmx.c | 88 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 drivers/crypto/vmx/vmx.c diff --git a/drivers/crypto/vmx/vmx.c b/drivers/crypto/vmx/vmx.c new file mode 100644 index 000000000000..44d8d5cfe40d --- /dev/null +++ b/drivers/crypto/vmx/vmx.c @@ -0,0 +1,88 @@ +/** + * Routines supporting VMX instructions on the Power 8 + * + * Copyright (C) 2015 International Business Machines Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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. + * + * Author: Marcelo Henrique Cerri + */ + +#include +#include +#include +#include +#include +#include +#include + +extern struct shash_alg p8_ghash_alg; +extern struct crypto_alg p8_aes_alg; +extern struct crypto_alg p8_aes_cbc_alg; +extern struct crypto_alg p8_aes_ctr_alg; +static struct crypto_alg *algs[] = { + &p8_aes_alg, + &p8_aes_cbc_alg, + &p8_aes_ctr_alg, + NULL, +}; + +int __init p8_init(void) +{ + int ret = 0; + struct crypto_alg **alg_it; + + if (!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO)) + return -ENODEV; + + for (alg_it = algs; *alg_it; alg_it++) { + ret = crypto_register_alg(*alg_it); + printk(KERN_INFO "crypto_register_alg '%s' = %d\n", + (*alg_it)->cra_name, ret); + if (ret) { + for (alg_it--; alg_it >= algs; alg_it--) + crypto_unregister_alg(*alg_it); + break; + } + } + if (ret) + return ret; + + ret = crypto_register_shash(&p8_ghash_alg); + if (ret) { + for (alg_it = algs; *alg_it; alg_it++) + crypto_unregister_alg(*alg_it); + } + return ret; +} + +void __exit p8_exit(void) +{ + struct crypto_alg **alg_it; + + for (alg_it = algs; *alg_it; alg_it++) { + printk(KERN_INFO "Removing '%s'\n", (*alg_it)->cra_name); + crypto_unregister_alg(*alg_it); + } + crypto_unregister_shash(&p8_ghash_alg); +} + +module_init(p8_init); +module_exit(p8_exit); + +MODULE_AUTHOR("Marcelo Cerri"); +MODULE_DESCRIPTION("IBM VMX cryptogaphic acceleration instructions support on Power 8"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.0"); + -- GitLab From 8676590a159320a9de2a1818df14a3bac3f065a1 Mon Sep 17 00:00:00 2001 From: "Marcelo H. Cerri" Date: Fri, 6 Feb 2015 14:57:22 -0200 Subject: [PATCH 0098/1910] crypto: vmx - Adding AES routines for VMX module This patch adds AES routines to VMX module in order to make use of VMX cryptographic acceleration instructions on Power 8 CPU. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aes.c | 139 +++++++++++++++++++++++++++++++++ drivers/crypto/vmx/aesp8-ppc.h | 20 +++++ 2 files changed, 159 insertions(+) create mode 100644 drivers/crypto/vmx/aes.c create mode 100644 drivers/crypto/vmx/aesp8-ppc.h diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c new file mode 100644 index 000000000000..ab300ea19434 --- /dev/null +++ b/drivers/crypto/vmx/aes.c @@ -0,0 +1,139 @@ +/** + * AES routines supporting VMX instructions on the Power 8 + * + * Copyright (C) 2015 International Business Machines Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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. + * + * Author: Marcelo Henrique Cerri + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "aesp8-ppc.h" + +struct p8_aes_ctx { + struct crypto_cipher *fallback; + struct aes_key enc_key; + struct aes_key dec_key; +}; + +static int p8_aes_init(struct crypto_tfm *tfm) +{ + const char *alg; + struct crypto_cipher *fallback; + struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!(alg = crypto_tfm_alg_name(tfm))) { + printk(KERN_ERR "Failed to get algorithm name.\n"); + return -ENOENT; + } + + fallback = crypto_alloc_cipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback)) { + printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", + alg, PTR_ERR(fallback)); + return PTR_ERR(fallback); + } + printk(KERN_INFO "Using '%s' as fallback implementation.\n", + crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); + + crypto_cipher_set_flags(fallback, + crypto_cipher_get_flags((struct crypto_cipher *) tfm)); + ctx->fallback = fallback; + + return 0; +} + +static void p8_aes_exit(struct crypto_tfm *tfm) +{ + struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (ctx->fallback) { + crypto_free_cipher(ctx->fallback); + ctx->fallback = NULL; + } +} + +static int p8_aes_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + int ret; + struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + pagefault_disable(); + enable_kernel_altivec(); + ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); + ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key); + pagefault_enable(); + + ret += crypto_cipher_setkey(ctx->fallback, key, keylen); + return ret; +} + +static void p8_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (in_interrupt()) { + crypto_cipher_encrypt_one(ctx->fallback, dst, src); + } else { + pagefault_disable(); + enable_kernel_altivec(); + aes_p8_encrypt(src, dst, &ctx->enc_key); + pagefault_enable(); + } +} + +static void p8_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (in_interrupt()) { + crypto_cipher_decrypt_one(ctx->fallback, dst, src); + } else { + pagefault_disable(); + enable_kernel_altivec(); + aes_p8_decrypt(src, dst, &ctx->dec_key); + pagefault_enable(); + } +} + +struct crypto_alg p8_aes_alg = { + .cra_name = "aes", + .cra_driver_name = "p8_aes", + .cra_module = THIS_MODULE, + .cra_priority = 1000, + .cra_type = NULL, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK, + .cra_alignmask = 0, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct p8_aes_ctx), + .cra_init = p8_aes_init, + .cra_exit = p8_aes_exit, + .cra_cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = p8_aes_setkey, + .cia_encrypt = p8_aes_encrypt, + .cia_decrypt = p8_aes_decrypt, + }, +}; + diff --git a/drivers/crypto/vmx/aesp8-ppc.h b/drivers/crypto/vmx/aesp8-ppc.h new file mode 100644 index 000000000000..e963945a83e1 --- /dev/null +++ b/drivers/crypto/vmx/aesp8-ppc.h @@ -0,0 +1,20 @@ +#include +#include + +#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1)) + +struct aes_key { + u8 key[AES_MAX_KEYLENGTH]; + int rounds; +}; + +int aes_p8_set_encrypt_key(const u8 *userKey, const int bits, + struct aes_key *key); +int aes_p8_set_decrypt_key(const u8 *userKey, const int bits, + struct aes_key *key); +void aes_p8_encrypt(const u8 *in, u8 *out, const struct aes_key *key); +void aes_p8_decrypt(const u8 *in, u8 *out,const struct aes_key *key); +void aes_p8_cbc_encrypt(const u8 *in, u8 *out, size_t len, + const struct aes_key *key, u8 *iv, const int enc); +void aes_p8_ctr32_encrypt_blocks(const u8 *in, u8 *out, + size_t len, const struct aes_key *key, const u8 *iv); -- GitLab From 8c755ace357c77fbfea61a2ce07d9723a9bb482f Mon Sep 17 00:00:00 2001 From: "Marcelo H. Cerri" Date: Fri, 6 Feb 2015 14:57:53 -0200 Subject: [PATCH 0099/1910] crypto: vmx - Adding CBC routines for VMX module This patch adds AES CBC routines to VMX module in order to make use of VMX cryptographic acceleration instructions on Power 8 CPU. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aes_cbc.c | 184 +++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 drivers/crypto/vmx/aes_cbc.c diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c new file mode 100644 index 000000000000..1a559b7dddb5 --- /dev/null +++ b/drivers/crypto/vmx/aes_cbc.c @@ -0,0 +1,184 @@ +/** + * AES CBC routines supporting VMX instructions on the Power 8 + * + * Copyright (C) 2015 International Business Machines Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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. + * + * Author: Marcelo Henrique Cerri + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aesp8-ppc.h" + +struct p8_aes_cbc_ctx { + struct crypto_blkcipher *fallback; + struct aes_key enc_key; + struct aes_key dec_key; +}; + +static int p8_aes_cbc_init(struct crypto_tfm *tfm) +{ + const char *alg; + struct crypto_blkcipher *fallback; + struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!(alg = crypto_tfm_alg_name(tfm))) { + printk(KERN_ERR "Failed to get algorithm name.\n"); + return -ENOENT; + } + + fallback = crypto_alloc_blkcipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback)) { + printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", + alg, PTR_ERR(fallback)); + return PTR_ERR(fallback); + } + printk(KERN_INFO "Using '%s' as fallback implementation.\n", + crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); + + crypto_blkcipher_set_flags(fallback, + crypto_blkcipher_get_flags((struct crypto_blkcipher *) tfm)); + ctx->fallback = fallback; + + return 0; +} + +static void p8_aes_cbc_exit(struct crypto_tfm *tfm) +{ + struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + + if (ctx->fallback) { + crypto_free_blkcipher(ctx->fallback); + ctx->fallback = NULL; + } +} + +static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + int ret; + struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + + pagefault_disable(); + enable_kernel_altivec(); + ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); + ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key); + pagefault_enable(); + + ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen); + return ret; +} + +static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + int ret; + struct blkcipher_walk walk; + struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx( + crypto_blkcipher_tfm(desc->tfm)); + struct blkcipher_desc fallback_desc = { + .tfm = ctx->fallback, + .info = desc->info, + .flags = desc->flags + }; + + if (in_interrupt()) { + ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes); + } else { + pagefault_disable(); + enable_kernel_altivec(); + + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt(desc, &walk); + while ((nbytes = walk.nbytes)) { + aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, + nbytes & AES_BLOCK_MASK, &ctx->enc_key, walk.iv, 1); + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + + pagefault_enable(); + } + + return ret; +} + +static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + int ret; + struct blkcipher_walk walk; + struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx( + crypto_blkcipher_tfm(desc->tfm)); + struct blkcipher_desc fallback_desc = { + .tfm = ctx->fallback, + .info = desc->info, + .flags = desc->flags + }; + + if (in_interrupt()) { + ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src, nbytes); + } else { + pagefault_disable(); + enable_kernel_altivec(); + + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt(desc, &walk); + while ((nbytes = walk.nbytes)) { + aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, + nbytes & AES_BLOCK_MASK, &ctx->dec_key, walk.iv, 0); + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + + pagefault_enable(); + } + + return ret; +} + + +struct crypto_alg p8_aes_cbc_alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "p8_aes_cbc", + .cra_module = THIS_MODULE, + .cra_priority = 1000, + .cra_type = &crypto_blkcipher_type, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, + .cra_alignmask = 0, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct p8_aes_cbc_ctx), + .cra_init = p8_aes_cbc_init, + .cra_exit = p8_aes_cbc_exit, + .cra_blkcipher = { + .ivsize = 0, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = p8_aes_cbc_setkey, + .encrypt = p8_aes_cbc_encrypt, + .decrypt = p8_aes_cbc_decrypt, + }, +}; + -- GitLab From 4f7f60d312b3816542412ee90e05f06b50a51489 Mon Sep 17 00:00:00 2001 From: "Marcelo H. Cerri" Date: Fri, 6 Feb 2015 14:58:31 -0200 Subject: [PATCH 0100/1910] crypto: vmx - Adding CTR routines for VMX module This patch adds AES CTR routines to VMX module in order to make use of VMX cryptographic acceleration instructions on Power 8 CPU. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aes_ctr.c | 167 +++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 drivers/crypto/vmx/aes_ctr.c diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c new file mode 100644 index 000000000000..96dbee4bf4a6 --- /dev/null +++ b/drivers/crypto/vmx/aes_ctr.c @@ -0,0 +1,167 @@ +/** + * AES CTR routines supporting VMX instructions on the Power 8 + * + * Copyright (C) 2015 International Business Machines Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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. + * + * Author: Marcelo Henrique Cerri + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "aesp8-ppc.h" + +struct p8_aes_ctr_ctx { + struct crypto_blkcipher *fallback; + struct aes_key enc_key; +}; + +static int p8_aes_ctr_init(struct crypto_tfm *tfm) +{ + const char *alg; + struct crypto_blkcipher *fallback; + struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!(alg = crypto_tfm_alg_name(tfm))) { + printk(KERN_ERR "Failed to get algorithm name.\n"); + return -ENOENT; + } + + fallback = crypto_alloc_blkcipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback)) { + printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", + alg, PTR_ERR(fallback)); + return PTR_ERR(fallback); + } + printk(KERN_INFO "Using '%s' as fallback implementation.\n", + crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); + + crypto_blkcipher_set_flags(fallback, + crypto_blkcipher_get_flags((struct crypto_blkcipher *) tfm)); + ctx->fallback = fallback; + + return 0; +} + +static void p8_aes_ctr_exit(struct crypto_tfm *tfm) +{ + struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + + if (ctx->fallback) { + crypto_free_blkcipher(ctx->fallback); + ctx->fallback = NULL; + } +} + +static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + int ret; + struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + + pagefault_disable(); + enable_kernel_altivec(); + ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); + pagefault_enable(); + + ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen); + return ret; +} + +static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx, + struct blkcipher_walk *walk) +{ + u8 *ctrblk = walk->iv; + u8 keystream[AES_BLOCK_SIZE]; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + + pagefault_disable(); + enable_kernel_altivec(); + aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key); + pagefault_enable(); + + crypto_xor(keystream, src, nbytes); + memcpy(dst, keystream, nbytes); + crypto_inc(ctrblk, AES_BLOCK_SIZE); +} + +static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + int ret; + struct blkcipher_walk walk; + struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx( + crypto_blkcipher_tfm(desc->tfm)); + struct blkcipher_desc fallback_desc = { + .tfm = ctx->fallback, + .info = desc->info, + .flags = desc->flags + }; + + if (in_interrupt()) { + ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes); + } else { + blkcipher_walk_init(&walk, dst, src, nbytes); + ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); + while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { + pagefault_disable(); + enable_kernel_altivec(); + aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, walk.dst.virt.addr, + (nbytes & AES_BLOCK_MASK)/AES_BLOCK_SIZE, &ctx->enc_key, walk.iv); + pagefault_enable(); + + crypto_inc(walk.iv, AES_BLOCK_SIZE); + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + if (walk.nbytes) { + p8_aes_ctr_final(ctx, &walk); + ret = blkcipher_walk_done(desc, &walk, 0); + } + } + + return ret; +} + +struct crypto_alg p8_aes_ctr_alg = { + .cra_name = "ctr(aes)", + .cra_driver_name = "p8_aes_ctr", + .cra_module = THIS_MODULE, + .cra_priority = 1000, + .cra_type = &crypto_blkcipher_type, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK, + .cra_alignmask = 0, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx), + .cra_init = p8_aes_ctr_init, + .cra_exit = p8_aes_ctr_exit, + .cra_blkcipher = { + .ivsize = 0, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = p8_aes_ctr_setkey, + .encrypt = p8_aes_ctr_crypt, + .decrypt = p8_aes_ctr_crypt, + }, +}; -- GitLab From cc333cd68dfae191ce02308657a50f21d63b7cd5 Mon Sep 17 00:00:00 2001 From: "Marcelo H. Cerri" Date: Fri, 6 Feb 2015 14:59:05 -0200 Subject: [PATCH 0101/1910] crypto: vmx - Adding GHASH routines for VMX module This patch adds GHASH routines to VMX module in order to make use of VMX cryptographic acceleration instructions on Power 8 CPU. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/ghash.c | 214 +++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 drivers/crypto/vmx/ghash.c diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c new file mode 100644 index 000000000000..d0ffe277af5c --- /dev/null +++ b/drivers/crypto/vmx/ghash.c @@ -0,0 +1,214 @@ +/** + * GHASH routines supporting VMX instructions on the Power 8 + * + * Copyright (C) 2015 International Business Machines Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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. + * + * Author: Marcelo Henrique Cerri + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IN_INTERRUPT in_interrupt() + +#define GHASH_BLOCK_SIZE (16) +#define GHASH_DIGEST_SIZE (16) +#define GHASH_KEY_LEN (16) + +void gcm_init_p8(u128 htable[16], const u64 Xi[2]); +void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]); +void gcm_ghash_p8(u64 Xi[2], const u128 htable[16], + const u8 *in,size_t len); + +struct p8_ghash_ctx { + u128 htable[16]; + struct crypto_shash *fallback; +}; + +struct p8_ghash_desc_ctx { + u64 shash[2]; + u8 buffer[GHASH_DIGEST_SIZE]; + int bytes; + struct shash_desc fallback_desc; +}; + +static int p8_ghash_init_tfm(struct crypto_tfm *tfm) +{ + const char *alg; + struct crypto_shash *fallback; + struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm); + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!(alg = crypto_tfm_alg_name(tfm))) { + printk(KERN_ERR "Failed to get algorithm name.\n"); + return -ENOENT; + } + + fallback = crypto_alloc_shash(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(fallback)) { + printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", + alg, PTR_ERR(fallback)); + return PTR_ERR(fallback); + } + printk(KERN_INFO "Using '%s' as fallback implementation.\n", + crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback))); + + crypto_shash_set_flags(fallback, + crypto_shash_get_flags((struct crypto_shash *) tfm)); + ctx->fallback = fallback; + + shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx) + + crypto_shash_descsize(fallback); + + return 0; +} + +static void p8_ghash_exit_tfm(struct crypto_tfm *tfm) +{ + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm); + + if (ctx->fallback) { + crypto_free_shash(ctx->fallback); + ctx->fallback = NULL; + } +} + +static int p8_ghash_init(struct shash_desc *desc) +{ + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm)); + struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + dctx->bytes = 0; + memset(dctx->shash, 0, GHASH_DIGEST_SIZE); + dctx->fallback_desc.tfm = ctx->fallback; + dctx->fallback_desc.flags = desc->flags; + return crypto_shash_init(&dctx->fallback_desc); +} + +static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm)); + + if (keylen != GHASH_KEY_LEN) + return -EINVAL; + + pagefault_disable(); + enable_kernel_altivec(); + enable_kernel_fp(); + gcm_init_p8(ctx->htable, (const u64 *) key); + pagefault_enable(); + return crypto_shash_setkey(ctx->fallback, key, keylen); +} + +static int p8_ghash_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + unsigned int len; + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm)); + struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + if (IN_INTERRUPT) { + return crypto_shash_update(&dctx->fallback_desc, src, srclen); + } else { + if (dctx->bytes) { + if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) { + memcpy(dctx->buffer + dctx->bytes, src, srclen); + dctx->bytes += srclen; + return 0; + } + memcpy(dctx->buffer + dctx->bytes, src, + GHASH_DIGEST_SIZE - dctx->bytes); + pagefault_disable(); + enable_kernel_altivec(); + enable_kernel_fp(); + gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer, + GHASH_DIGEST_SIZE); + pagefault_enable(); + src += GHASH_DIGEST_SIZE - dctx->bytes; + srclen -= GHASH_DIGEST_SIZE - dctx->bytes; + dctx->bytes = 0; + } + len = srclen & ~(GHASH_DIGEST_SIZE - 1); + if (len) { + pagefault_disable(); + enable_kernel_altivec(); + enable_kernel_fp(); + gcm_ghash_p8(dctx->shash, ctx->htable, src, len); + pagefault_enable(); + src += len; + srclen -= len; + } + if (srclen) { + memcpy(dctx->buffer, src, srclen); + dctx->bytes = srclen; + } + return 0; + } +} + +static int p8_ghash_final(struct shash_desc *desc, u8 *out) +{ + int i; + struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm)); + struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + if (IN_INTERRUPT) { + return crypto_shash_final(&dctx->fallback_desc, out); + } else { + if (dctx->bytes) { + for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++) + dctx->buffer[i] = 0; + pagefault_disable(); + enable_kernel_altivec(); + enable_kernel_fp(); + gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer, + GHASH_DIGEST_SIZE); + pagefault_enable(); + dctx->bytes = 0; + } + memcpy(out, dctx->shash, GHASH_DIGEST_SIZE); + return 0; + } +} + +struct shash_alg p8_ghash_alg = { + .digestsize = GHASH_DIGEST_SIZE, + .init = p8_ghash_init, + .update = p8_ghash_update, + .final = p8_ghash_final, + .setkey = p8_ghash_setkey, + .descsize = sizeof(struct p8_ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "p8_ghash", + .cra_priority = 1000, + .cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct p8_ghash_ctx), + .cra_module = THIS_MODULE, + .cra_init = p8_ghash_init_tfm, + .cra_exit = p8_ghash_exit_tfm, + }, +}; -- GitLab From 5c380d623ed30b71a2441fb4f2e053a4e1a50794 Mon Sep 17 00:00:00 2001 From: "Leonidas S. Barbosa" Date: Fri, 6 Feb 2015 14:59:35 -0200 Subject: [PATCH 0102/1910] crypto: vmx - Add support for VMS instructions by ASM OpenSSL implements optimized ASM algorithms which support VMX instructions on Power 8 CPU. These scripts generate an endian-agnostic ASM implementation in order to support both big and little-endian. - aesp8-ppc.pl: implements suport for AES instructions implemented by POWER8 processor. - ghashp8-ppc.pl: implements support for GHASH for Power8. - ppc-xlate.pl: ppc assembler distiller. These code has been adopted from OpenSSL project in collaboration with the original author (Andy Polyakov ). Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aesp8-ppc.pl | 1940 +++++++++++++++++++++++++++++ drivers/crypto/vmx/ghashp8-ppc.pl | 234 ++++ drivers/crypto/vmx/ppc-xlate.pl | 226 ++++ 3 files changed, 2400 insertions(+) create mode 100755 drivers/crypto/vmx/aesp8-ppc.pl create mode 100755 drivers/crypto/vmx/ghashp8-ppc.pl create mode 100755 drivers/crypto/vmx/ppc-xlate.pl diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl new file mode 100755 index 000000000000..3ee8979e7625 --- /dev/null +++ b/drivers/crypto/vmx/aesp8-ppc.pl @@ -0,0 +1,1940 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for AES instructions as per PowerISA +# specification version 2.07, first implemented by POWER8 processor. +# The module is endian-agnostic in sense that it supports both big- +# and little-endian cases. Data alignment in parallelizable modes is +# handled with VSX loads and stores, which implies MSR.VSX flag being +# set. It should also be noted that ISA specification doesn't prohibit +# alignment exceptions for these instructions on page boundaries. +# Initially alignment was handled in pure AltiVec/VMX way [when data +# is aligned programmatically, which in turn guarantees exception- +# free execution], but it turned to hamper performance when vcipher +# instructions are interleaved. It's reckoned that eventual +# misalignment penalties at page boundaries are in average lower +# than additional overhead in pure AltiVec approach. + +$flavour = shift; + +if ($flavour =~ /64/) { + $SIZE_T =8; + $LRSAVE =2*$SIZE_T; + $STU ="stdu"; + $POP ="ld"; + $PUSH ="std"; + $UCMP ="cmpld"; + $SHL ="sldi"; +} elsif ($flavour =~ /32/) { + $SIZE_T =4; + $LRSAVE =$SIZE_T; + $STU ="stwu"; + $POP ="lwz"; + $PUSH ="stw"; + $UCMP ="cmplw"; + $SHL ="slwi"; +} else { die "nonsense $flavour"; } + +$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or +die "can't locate ppc-xlate.pl"; + +open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!"; + +$FRAME=8*$SIZE_T; +$prefix="aes_p8"; + +$sp="r1"; +$vrsave="r12"; + +######################################################################### +{{{ # Key setup procedures # +my ($inp,$bits,$out,$ptr,$cnt,$rounds)=map("r$_",(3..8)); +my ($zero,$in0,$in1,$key,$rcon,$mask,$tmp)=map("v$_",(0..6)); +my ($stage,$outperm,$outmask,$outhead,$outtail)=map("v$_",(7..11)); + +$code.=<<___; +.machine "any" + +.text + +.align 7 +rcon: +.long 0x01000000, 0x01000000, 0x01000000, 0x01000000 ?rev +.long 0x1b000000, 0x1b000000, 0x1b000000, 0x1b000000 ?rev +.long 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c ?rev +.long 0,0,0,0 ?asis +Lconsts: + mflr r0 + bcl 20,31,\$+4 + mflr $ptr #vvvvv "distance between . and rcon + addi $ptr,$ptr,-0x48 + mtlr r0 + blr + .long 0 + .byte 0,12,0x14,0,0,0,0,0 +.asciz "AES for PowerISA 2.07, CRYPTOGAMS by " + +.globl .${prefix}_set_encrypt_key +.align 5 +.${prefix}_set_encrypt_key: +Lset_encrypt_key: + mflr r11 + $PUSH r11,$LRSAVE($sp) + + li $ptr,-1 + ${UCMP}i $inp,0 + beq- Lenc_key_abort # if ($inp==0) return -1; + ${UCMP}i $out,0 + beq- Lenc_key_abort # if ($out==0) return -1; + li $ptr,-2 + cmpwi $bits,128 + blt- Lenc_key_abort + cmpwi $bits,256 + bgt- Lenc_key_abort + andi. r0,$bits,0x3f + bne- Lenc_key_abort + + lis r0,0xfff0 + mfspr $vrsave,256 + mtspr 256,r0 + + bl Lconsts + mtlr r11 + + neg r9,$inp + lvx $in0,0,$inp + addi $inp,$inp,15 # 15 is not typo + lvsr $key,0,r9 # borrow $key + li r8,0x20 + cmpwi $bits,192 + lvx $in1,0,$inp + le?vspltisb $mask,0x0f # borrow $mask + lvx $rcon,0,$ptr + le?vxor $key,$key,$mask # adjust for byte swap + lvx $mask,r8,$ptr + addi $ptr,$ptr,0x10 + vperm $in0,$in0,$in1,$key # align [and byte swap in LE] + li $cnt,8 + vxor $zero,$zero,$zero + mtctr $cnt + + ?lvsr $outperm,0,$out + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$zero,$outmask,$outperm + + blt Loop128 + addi $inp,$inp,8 + beq L192 + addi $inp,$inp,8 + b L256 + +.align 4 +Loop128: + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + bdnz Loop128 + + lvx $rcon,0,$ptr # last two round keys + + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vxor $in0,$in0,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + + addi $inp,$out,15 # 15 is not typo + addi $out,$out,0x50 + + li $rounds,10 + b Ldone + +.align 4 +L192: + lvx $tmp,0,$inp + li $cnt,4 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $out,$out,16 + vperm $in1,$in1,$tmp,$key # align [and byte swap in LE] + vspltisb $key,8 # borrow $key + mtctr $cnt + vsububm $mask,$mask,$key # adjust the mask + +Loop192: + vperm $key,$in1,$in1,$mask # roate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vcipherlast $key,$key,$rcon + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + + vsldoi $stage,$zero,$in1,8 + vspltw $tmp,$in0,3 + vxor $tmp,$tmp,$in1 + vsldoi $in1,$zero,$in1,12 # >>32 + vadduwm $rcon,$rcon,$rcon + vxor $in1,$in1,$tmp + vxor $in0,$in0,$key + vxor $in1,$in1,$key + vsldoi $stage,$stage,$in0,8 + + vperm $key,$in1,$in1,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$stage,$stage,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vsldoi $stage,$in0,$in1,8 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vperm $outtail,$stage,$stage,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + stvx $stage,0,$out + addi $out,$out,16 + + vspltw $tmp,$in0,3 + vxor $tmp,$tmp,$in1 + vsldoi $in1,$zero,$in1,12 # >>32 + vadduwm $rcon,$rcon,$rcon + vxor $in1,$in1,$tmp + vxor $in0,$in0,$key + vxor $in1,$in1,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $inp,$out,15 # 15 is not typo + addi $out,$out,16 + bdnz Loop192 + + li $rounds,12 + addi $out,$out,0x20 + b Ldone + +.align 4 +L256: + lvx $tmp,0,$inp + li $cnt,7 + li $rounds,14 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $out,$out,16 + vperm $in1,$in1,$tmp,$key # align [and byte swap in LE] + mtctr $cnt + +Loop256: + vperm $key,$in1,$in1,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in1,$in1,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $inp,$out,15 # 15 is not typo + addi $out,$out,16 + bdz Ldone + + vspltw $key,$in0,3 # just splat + vsldoi $tmp,$zero,$in1,12 # >>32 + vsbox $key,$key + + vxor $in1,$in1,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in1,$in1,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in1,$in1,$tmp + + vxor $in1,$in1,$key + b Loop256 + +.align 4 +Ldone: + lvx $in1,0,$inp # redundant in aligned case + vsel $in1,$outhead,$in1,$outmask + stvx $in1,0,$inp + li $ptr,0 + mtspr 256,$vrsave + stw $rounds,0($out) + +Lenc_key_abort: + mr r3,$ptr + blr + .long 0 + .byte 0,12,0x14,1,0,0,3,0 + .long 0 +.size .${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key + +.globl .${prefix}_set_decrypt_key +.align 5 +.${prefix}_set_decrypt_key: + $STU $sp,-$FRAME($sp) + mflr r10 + $PUSH r10,$FRAME+$LRSAVE($sp) + bl Lset_encrypt_key + mtlr r10 + + cmpwi r3,0 + bne- Ldec_key_abort + + slwi $cnt,$rounds,4 + subi $inp,$out,240 # first round key + srwi $rounds,$rounds,1 + add $out,$inp,$cnt # last round key + mtctr $rounds + +Ldeckey: + lwz r0, 0($inp) + lwz r6, 4($inp) + lwz r7, 8($inp) + lwz r8, 12($inp) + addi $inp,$inp,16 + lwz r9, 0($out) + lwz r10,4($out) + lwz r11,8($out) + lwz r12,12($out) + stw r0, 0($out) + stw r6, 4($out) + stw r7, 8($out) + stw r8, 12($out) + subi $out,$out,16 + stw r9, -16($inp) + stw r10,-12($inp) + stw r11,-8($inp) + stw r12,-4($inp) + bdnz Ldeckey + + xor r3,r3,r3 # return value +Ldec_key_abort: + addi $sp,$sp,$FRAME + blr + .long 0 + .byte 0,12,4,1,0x80,0,3,0 + .long 0 +.size .${prefix}_set_decrypt_key,.-.${prefix}_set_decrypt_key +___ +}}} +######################################################################### +{{{ # Single block en- and decrypt procedures # +sub gen_block () { +my $dir = shift; +my $n = $dir eq "de" ? "n" : ""; +my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7)); + +$code.=<<___; +.globl .${prefix}_${dir}crypt +.align 5 +.${prefix}_${dir}crypt: + lwz $rounds,240($key) + lis r0,0xfc00 + mfspr $vrsave,256 + li $idx,15 # 15 is not typo + mtspr 256,r0 + + lvx v0,0,$inp + neg r11,$out + lvx v1,$idx,$inp + lvsl v2,0,$inp # inpperm + le?vspltisb v4,0x0f + ?lvsl v3,0,r11 # outperm + le?vxor v2,v2,v4 + li $idx,16 + vperm v0,v0,v1,v2 # align [and byte swap in LE] + lvx v1,0,$key + ?lvsl v5,0,$key # keyperm + srwi $rounds,$rounds,1 + lvx v2,$idx,$key + addi $idx,$idx,16 + subi $rounds,$rounds,1 + ?vperm v1,v1,v2,v5 # align round key + + vxor v0,v0,v1 + lvx v1,$idx,$key + addi $idx,$idx,16 + mtctr $rounds + +Loop_${dir}c: + ?vperm v2,v2,v1,v5 + v${n}cipher v0,v0,v2 + lvx v2,$idx,$key + addi $idx,$idx,16 + ?vperm v1,v1,v2,v5 + v${n}cipher v0,v0,v1 + lvx v1,$idx,$key + addi $idx,$idx,16 + bdnz Loop_${dir}c + + ?vperm v2,v2,v1,v5 + v${n}cipher v0,v0,v2 + lvx v2,$idx,$key + ?vperm v1,v1,v2,v5 + v${n}cipherlast v0,v0,v1 + + vspltisb v2,-1 + vxor v1,v1,v1 + li $idx,15 # 15 is not typo + ?vperm v2,v1,v2,v3 # outmask + le?vxor v3,v3,v4 + lvx v1,0,$out # outhead + vperm v0,v0,v0,v3 # rotate [and byte swap in LE] + vsel v1,v1,v0,v2 + lvx v4,$idx,$out + stvx v1,0,$out + vsel v0,v0,v4,v2 + stvx v0,$idx,$out + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,3,0 + .long 0 +.size .${prefix}_${dir}crypt,.-.${prefix}_${dir}crypt +___ +} +&gen_block("en"); +&gen_block("de"); +}}} +######################################################################### +{{{ # CBC en- and decrypt procedures # +my ($inp,$out,$len,$key,$ivp,$enc,$rounds,$idx)=map("r$_",(3..10)); +my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3)); +my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)= + map("v$_",(4..10)); +$code.=<<___; +.globl .${prefix}_cbc_encrypt +.align 5 +.${prefix}_cbc_encrypt: + ${UCMP}i $len,16 + bltlr- + + cmpwi $enc,0 # test direction + lis r0,0xffe0 + mfspr $vrsave,256 + mtspr 256,r0 + + li $idx,15 + vxor $rndkey0,$rndkey0,$rndkey0 + le?vspltisb $tmp,0x0f + + lvx $ivec,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + le?vxor $inpperm,$inpperm,$tmp + vperm $ivec,$ivec,$inptail,$inpperm + + neg r11,$inp + ?lvsl $keyperm,0,$key # prepare for unaligned key + lwz $rounds,240($key) + + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inptail,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + ?lvsr $outperm,0,$out # prepare for unaligned store + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + + srwi $rounds,$rounds,1 + li $idx,16 + subi $rounds,$rounds,1 + beq Lcbc_dec + +Lcbc_enc: + vmr $inout,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + mtctr $rounds + subi $len,$len,16 # len-=16 + + lvx $rndkey0,0,$key + vperm $inout,$inout,$inptail,$inpperm + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + vxor $inout,$inout,$ivec + +Loop_cbc_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_cbc_enc + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipherlast $ivec,$inout,$rndkey0 + ${UCMP}i $len,16 + + vperm $tmp,$ivec,$ivec,$outperm + vsel $inout,$outhead,$tmp,$outmask + vmr $outhead,$tmp + stvx $inout,0,$out + addi $out,$out,16 + bge Lcbc_enc + + b Lcbc_done + +.align 4 +Lcbc_dec: + ${UCMP}i $len,128 + bge _aesp8_cbc_decrypt8x + vmr $tmp,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + mtctr $rounds + subi $len,$len,16 # len-=16 + + lvx $rndkey0,0,$key + vperm $tmp,$tmp,$inptail,$inpperm + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$tmp,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + +Loop_cbc_dec: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_cbc_dec + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipherlast $inout,$inout,$rndkey0 + ${UCMP}i $len,16 + + vxor $inout,$inout,$ivec + vmr $ivec,$tmp + vperm $tmp,$inout,$inout,$outperm + vsel $inout,$outhead,$tmp,$outmask + vmr $outhead,$tmp + stvx $inout,0,$out + addi $out,$out,16 + bge Lcbc_dec + +Lcbc_done: + addi $out,$out,-1 + lvx $inout,0,$out # redundant in aligned case + vsel $inout,$outhead,$inout,$outmask + stvx $inout,0,$out + + neg $enc,$ivp # write [unaligned] iv + li $idx,15 # 15 is not typo + vxor $rndkey0,$rndkey0,$rndkey0 + vspltisb $outmask,-1 + le?vspltisb $tmp,0x0f + ?lvsl $outperm,0,$enc + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + lvx $outhead,0,$ivp + vperm $ivec,$ivec,$ivec,$outperm + vsel $inout,$outhead,$ivec,$outmask + lvx $inptail,$idx,$ivp + stvx $inout,0,$ivp + vsel $inout,$ivec,$inptail,$outmask + stvx $inout,$idx,$ivp + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,6,0 + .long 0 +___ +######################################################################### +{{ # Optimized CBC decrypt procedure # +my $key_="r11"; +my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31)); +my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10..13)); +my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(14..21)); +my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys + # v26-v31 last 6 round keys +my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment + +$code.=<<___; +.align 5 +_aesp8_cbc_decrypt8x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + li r10,`$FRAME+8*16+15` + li r11,`$FRAME+8*16+31` + stvx v20,r10,$sp # ABI says so + addi r10,r10,32 + stvx v21,r11,$sp + addi r11,r11,32 + stvx v22,r10,$sp + addi r10,r10,32 + stvx v23,r11,$sp + addi r11,r11,32 + stvx v24,r10,$sp + addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 + stvx v26,r10,$sp + addi r10,r10,32 + stvx v27,r11,$sp + addi r11,r11,32 + stvx v28,r10,$sp + addi r10,r10,32 + stvx v29,r11,$sp + addi r11,r11,32 + stvx v30,r10,$sp + stvx v31,r11,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + subi $len,$len,128 # bias + + lvx $rndkey0,$x00,$key # load key schedule + lvx v30,$x10,$key + addi $key,$key,0x20 + lvx v31,$x00,$key + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_cbc_dec_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key + addi $key,$key,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_cbc_dec_key + + lvx v26,$x10,$key + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key + ?vperm v29,v29,v30,$keyperm + lvx $out0,$x70,$key # borrow $out0 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$out0,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + #lvx $inptail,0,$inp # "caller" already did this + #addi $inp,$inp,15 # 15 is not typo + subi $inp,$inp,15 # undo "caller" + + le?li $idx,8 + lvx_u $in0,$x00,$inp # load first 8 "words" + le?lvsl $inpperm,0,$idx + le?vspltisb $tmp,0x0f + lvx_u $in1,$x10,$inp + le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u + lvx_u $in2,$x20,$inp + le?vperm $in0,$in0,$in0,$inpperm + lvx_u $in3,$x30,$inp + le?vperm $in1,$in1,$in1,$inpperm + lvx_u $in4,$x40,$inp + le?vperm $in2,$in2,$in2,$inpperm + vxor $out0,$in0,$rndkey0 + lvx_u $in5,$x50,$inp + le?vperm $in3,$in3,$in3,$inpperm + vxor $out1,$in1,$rndkey0 + lvx_u $in6,$x60,$inp + le?vperm $in4,$in4,$in4,$inpperm + vxor $out2,$in2,$rndkey0 + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + le?vperm $in5,$in5,$in5,$inpperm + vxor $out3,$in3,$rndkey0 + le?vperm $in6,$in6,$in6,$inpperm + vxor $out4,$in4,$rndkey0 + le?vperm $in7,$in7,$in7,$inpperm + vxor $out5,$in5,$rndkey0 + vxor $out6,$in6,$rndkey0 + vxor $out7,$in7,$rndkey0 + + mtctr $rounds + b Loop_cbc_dec8x +.align 5 +Loop_cbc_dec8x: + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_cbc_dec8x + + subic $len,$len,128 # $len-=128 + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + + subfe. r0,r0,r0 # borrow?-1:0 + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + + and r0,r0,$len + vncipher $out0,$out0,v26 + vncipher $out1,$out1,v26 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vncipher $out4,$out4,v26 + vncipher $out5,$out5,v26 + vncipher $out6,$out6,v26 + vncipher $out7,$out7,v26 + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in7 are loaded + # with last "words" + vncipher $out0,$out0,v27 + vncipher $out1,$out1,v27 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vncipher $out4,$out4,v27 + vncipher $out5,$out5,v27 + vncipher $out6,$out6,v27 + vncipher $out7,$out7,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vncipher $out0,$out0,v28 + vncipher $out1,$out1,v28 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vncipher $out4,$out4,v28 + vncipher $out5,$out5,v28 + vncipher $out6,$out6,v28 + vncipher $out7,$out7,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + + vncipher $out0,$out0,v29 + vncipher $out1,$out1,v29 + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vncipher $out4,$out4,v29 + vncipher $out5,$out5,v29 + vncipher $out6,$out6,v29 + vncipher $out7,$out7,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + + vncipher $out0,$out0,v30 + vxor $ivec,$ivec,v31 # xor with last round key + vncipher $out1,$out1,v30 + vxor $in0,$in0,v31 + vncipher $out2,$out2,v30 + vxor $in1,$in1,v31 + vncipher $out3,$out3,v30 + vxor $in2,$in2,v31 + vncipher $out4,$out4,v30 + vxor $in3,$in3,v31 + vncipher $out5,$out5,v30 + vxor $in4,$in4,v31 + vncipher $out6,$out6,v30 + vxor $in5,$in5,v31 + vncipher $out7,$out7,v30 + vxor $in6,$in6,v31 + + vncipherlast $out0,$out0,$ivec + vncipherlast $out1,$out1,$in0 + lvx_u $in0,$x00,$inp # load next input block + vncipherlast $out2,$out2,$in1 + lvx_u $in1,$x10,$inp + vncipherlast $out3,$out3,$in2 + le?vperm $in0,$in0,$in0,$inpperm + lvx_u $in2,$x20,$inp + vncipherlast $out4,$out4,$in3 + le?vperm $in1,$in1,$in1,$inpperm + lvx_u $in3,$x30,$inp + vncipherlast $out5,$out5,$in4 + le?vperm $in2,$in2,$in2,$inpperm + lvx_u $in4,$x40,$inp + vncipherlast $out6,$out6,$in5 + le?vperm $in3,$in3,$in3,$inpperm + lvx_u $in5,$x50,$inp + vncipherlast $out7,$out7,$in6 + le?vperm $in4,$in4,$in4,$inpperm + lvx_u $in6,$x60,$inp + vmr $ivec,$in7 + le?vperm $in5,$in5,$in5,$inpperm + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $in6,$in6,$in6,$inpperm + vxor $out0,$in0,$rndkey0 + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $in7,$in7,$in7,$inpperm + vxor $out1,$in1,$rndkey0 + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + vxor $out2,$in2,$rndkey0 + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + vxor $out3,$in3,$rndkey0 + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + vxor $out4,$in4,$rndkey0 + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + vxor $out5,$in5,$rndkey0 + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x60,$out + vxor $out6,$in6,$rndkey0 + stvx_u $out7,$x70,$out + addi $out,$out,0x80 + vxor $out7,$in7,$rndkey0 + + mtctr $rounds + beq Loop_cbc_dec8x # did $len-=128 borrow? + + addic. $len,$len,128 + beq Lcbc_dec8x_done + nop + nop + +Loop_cbc_dec8x_tail: # up to 7 "words" tail... + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_cbc_dec8x_tail + + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + + vncipher $out1,$out1,v26 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vncipher $out4,$out4,v26 + vncipher $out5,$out5,v26 + vncipher $out6,$out6,v26 + vncipher $out7,$out7,v26 + + vncipher $out1,$out1,v27 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vncipher $out4,$out4,v27 + vncipher $out5,$out5,v27 + vncipher $out6,$out6,v27 + vncipher $out7,$out7,v27 + + vncipher $out1,$out1,v28 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vncipher $out4,$out4,v28 + vncipher $out5,$out5,v28 + vncipher $out6,$out6,v28 + vncipher $out7,$out7,v28 + + vncipher $out1,$out1,v29 + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vncipher $out4,$out4,v29 + vncipher $out5,$out5,v29 + vncipher $out6,$out6,v29 + vncipher $out7,$out7,v29 + + vncipher $out1,$out1,v30 + vxor $ivec,$ivec,v31 # last round key + vncipher $out2,$out2,v30 + vxor $in1,$in1,v31 + vncipher $out3,$out3,v30 + vxor $in2,$in2,v31 + vncipher $out4,$out4,v30 + vxor $in3,$in3,v31 + vncipher $out5,$out5,v30 + vxor $in4,$in4,v31 + vncipher $out6,$out6,v30 + vxor $in5,$in5,v31 + vncipher $out7,$out7,v30 + vxor $in6,$in6,v31 + + cmplwi $len,32 # switch($len) + blt Lcbc_dec8x_one + nop + beq Lcbc_dec8x_two + cmplwi $len,64 + blt Lcbc_dec8x_three + nop + beq Lcbc_dec8x_four + cmplwi $len,96 + blt Lcbc_dec8x_five + nop + beq Lcbc_dec8x_six + +Lcbc_dec8x_seven: + vncipherlast $out1,$out1,$ivec + vncipherlast $out2,$out2,$in1 + vncipherlast $out3,$out3,$in2 + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out1,$out1,$out1,$inpperm + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x00,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x10,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x20,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x30,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x40,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x50,$out + stvx_u $out7,$x60,$out + addi $out,$out,0x70 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_six: + vncipherlast $out2,$out2,$ivec + vncipherlast $out3,$out3,$in2 + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out2,$out2,$out2,$inpperm + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x00,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x10,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x20,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x30,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x40,$out + stvx_u $out7,$x50,$out + addi $out,$out,0x60 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_five: + vncipherlast $out3,$out3,$ivec + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out3,$out3,$out3,$inpperm + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x00,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x10,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x20,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x30,$out + stvx_u $out7,$x40,$out + addi $out,$out,0x50 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_four: + vncipherlast $out4,$out4,$ivec + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out4,$out4,$out4,$inpperm + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x00,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x10,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x20,$out + stvx_u $out7,$x30,$out + addi $out,$out,0x40 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_three: + vncipherlast $out5,$out5,$ivec + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out5,$out5,$out5,$inpperm + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x00,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x10,$out + stvx_u $out7,$x20,$out + addi $out,$out,0x30 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_two: + vncipherlast $out6,$out6,$ivec + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out6,$out6,$out6,$inpperm + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x00,$out + stvx_u $out7,$x10,$out + addi $out,$out,0x20 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_one: + vncipherlast $out7,$out7,$ivec + vmr $ivec,$in7 + + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out7,0,$out + addi $out,$out,0x10 + +Lcbc_dec8x_done: + le?vperm $ivec,$ivec,$ivec,$inpperm + stvx_u $ivec,0,$ivp # write [unaligned] iv + + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $inpperm,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x14,0,0x80,6,6,0 + .long 0 +.size .${prefix}_cbc_encrypt,.-.${prefix}_cbc_encrypt +___ +}} }}} + +######################################################################### +{{{ # CTR procedure[s] # +my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10)); +my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3)); +my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)= + map("v$_",(4..11)); +my $dat=$tmp; + +$code.=<<___; +.globl .${prefix}_ctr32_encrypt_blocks +.align 5 +.${prefix}_ctr32_encrypt_blocks: + ${UCMP}i $len,1 + bltlr- + + lis r0,0xfff0 + mfspr $vrsave,256 + mtspr 256,r0 + + li $idx,15 + vxor $rndkey0,$rndkey0,$rndkey0 + le?vspltisb $tmp,0x0f + + lvx $ivec,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + vspltisb $one,1 + le?vxor $inpperm,$inpperm,$tmp + vperm $ivec,$ivec,$inptail,$inpperm + vsldoi $one,$rndkey0,$one,1 + + neg r11,$inp + ?lvsl $keyperm,0,$key # prepare for unaligned key + lwz $rounds,240($key) + + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inptail,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + srwi $rounds,$rounds,1 + li $idx,16 + subi $rounds,$rounds,1 + + ${UCMP}i $len,8 + bge _aesp8_ctr32_encrypt8x + + ?lvsr $outperm,0,$out # prepare for unaligned store + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + + lvx $rndkey0,0,$key + mtctr $rounds + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$ivec,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + b Loop_ctr32_enc + +.align 5 +Loop_ctr32_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_ctr32_enc + + vadduwm $ivec,$ivec,$one + vmr $dat,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + subic. $len,$len,1 # blocks-- + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + vperm $dat,$dat,$inptail,$inpperm + li $idx,16 + ?vperm $rndkey1,$rndkey0,$rndkey1,$keyperm + lvx $rndkey0,0,$key + vxor $dat,$dat,$rndkey1 # last round key + vcipherlast $inout,$inout,$dat + + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + vperm $inout,$inout,$inout,$outperm + vsel $dat,$outhead,$inout,$outmask + mtctr $rounds + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vmr $outhead,$inout + vxor $inout,$ivec,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + stvx $dat,0,$out + addi $out,$out,16 + bne Loop_ctr32_enc + + addi $out,$out,-1 + lvx $inout,0,$out # redundant in aligned case + vsel $inout,$outhead,$inout,$outmask + stvx $inout,0,$out + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,6,0 + .long 0 +___ +######################################################################### +{{ # Optimized CTR procedure # +my $key_="r11"; +my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31)); +my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10,12..14)); +my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(15..22)); +my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys + # v26-v31 last 6 round keys +my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment +my ($two,$three,$four)=($outhead,$outperm,$outmask); + +$code.=<<___; +.align 5 +_aesp8_ctr32_encrypt8x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + li r10,`$FRAME+8*16+15` + li r11,`$FRAME+8*16+31` + stvx v20,r10,$sp # ABI says so + addi r10,r10,32 + stvx v21,r11,$sp + addi r11,r11,32 + stvx v22,r10,$sp + addi r10,r10,32 + stvx v23,r11,$sp + addi r11,r11,32 + stvx v24,r10,$sp + addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 + stvx v26,r10,$sp + addi r10,r10,32 + stvx v27,r11,$sp + addi r11,r11,32 + stvx v28,r10,$sp + addi r10,r10,32 + stvx v29,r11,$sp + addi r11,r11,32 + stvx v30,r10,$sp + stvx v31,r11,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + + lvx $rndkey0,$x00,$key # load key schedule + lvx v30,$x10,$key + addi $key,$key,0x20 + lvx v31,$x00,$key + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_ctr32_enc_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key + addi $key,$key,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_ctr32_enc_key + + lvx v26,$x10,$key + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key + ?vperm v29,v29,v30,$keyperm + lvx $out0,$x70,$key # borrow $out0 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$out0,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + vadduwm $two,$one,$one + subi $inp,$inp,15 # undo "caller" + $SHL $len,$len,4 + + vadduwm $out1,$ivec,$one # counter values ... + vadduwm $out2,$ivec,$two + vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0] + le?li $idx,8 + vadduwm $out3,$out1,$two + vxor $out1,$out1,$rndkey0 + le?lvsl $inpperm,0,$idx + vadduwm $out4,$out2,$two + vxor $out2,$out2,$rndkey0 + le?vspltisb $tmp,0x0f + vadduwm $out5,$out3,$two + vxor $out3,$out3,$rndkey0 + le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u + vadduwm $out6,$out4,$two + vxor $out4,$out4,$rndkey0 + vadduwm $out7,$out5,$two + vxor $out5,$out5,$rndkey0 + vadduwm $ivec,$out6,$two # next counter value + vxor $out6,$out6,$rndkey0 + vxor $out7,$out7,$rndkey0 + + mtctr $rounds + b Loop_ctr32_enc8x +.align 5 +Loop_ctr32_enc8x: + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + vcipher $out6,$out6,v24 + vcipher $out7,$out7,v24 +Loop_ctr32_enc8x_middle: + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + vcipher $out6,$out6,v25 + vcipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_ctr32_enc8x + + subic r11,$len,256 # $len-256, borrow $key_ + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + vcipher $out6,$out6,v24 + vcipher $out7,$out7,v24 + + subfe r0,r0,r0 # borrow?-1:0 + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + vcipher $out6,$out6,v25 + vcipher $out7,$out7,v25 + + and r0,r0,r11 + addi $key_,$sp,$FRAME+15 # rewind $key_ + vcipher $out0,$out0,v26 + vcipher $out1,$out1,v26 + vcipher $out2,$out2,v26 + vcipher $out3,$out3,v26 + vcipher $out4,$out4,v26 + vcipher $out5,$out5,v26 + vcipher $out6,$out6,v26 + vcipher $out7,$out7,v26 + lvx v24,$x00,$key_ # re-pre-load round[1] + + subic $len,$len,129 # $len-=129 + vcipher $out0,$out0,v27 + addi $len,$len,1 # $len-=128 really + vcipher $out1,$out1,v27 + vcipher $out2,$out2,v27 + vcipher $out3,$out3,v27 + vcipher $out4,$out4,v27 + vcipher $out5,$out5,v27 + vcipher $out6,$out6,v27 + vcipher $out7,$out7,v27 + lvx v25,$x10,$key_ # re-pre-load round[2] + + vcipher $out0,$out0,v28 + lvx_u $in0,$x00,$inp # load input + vcipher $out1,$out1,v28 + lvx_u $in1,$x10,$inp + vcipher $out2,$out2,v28 + lvx_u $in2,$x20,$inp + vcipher $out3,$out3,v28 + lvx_u $in3,$x30,$inp + vcipher $out4,$out4,v28 + lvx_u $in4,$x40,$inp + vcipher $out5,$out5,v28 + lvx_u $in5,$x50,$inp + vcipher $out6,$out6,v28 + lvx_u $in6,$x60,$inp + vcipher $out7,$out7,v28 + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + + vcipher $out0,$out0,v29 + le?vperm $in0,$in0,$in0,$inpperm + vcipher $out1,$out1,v29 + le?vperm $in1,$in1,$in1,$inpperm + vcipher $out2,$out2,v29 + le?vperm $in2,$in2,$in2,$inpperm + vcipher $out3,$out3,v29 + le?vperm $in3,$in3,$in3,$inpperm + vcipher $out4,$out4,v29 + le?vperm $in4,$in4,$in4,$inpperm + vcipher $out5,$out5,v29 + le?vperm $in5,$in5,$in5,$inpperm + vcipher $out6,$out6,v29 + le?vperm $in6,$in6,$in6,$inpperm + vcipher $out7,$out7,v29 + le?vperm $in7,$in7,$in7,$inpperm + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in7 are loaded + # with last "words" + subfe. r0,r0,r0 # borrow?-1:0 + vcipher $out0,$out0,v30 + vxor $in0,$in0,v31 # xor with last round key + vcipher $out1,$out1,v30 + vxor $in1,$in1,v31 + vcipher $out2,$out2,v30 + vxor $in2,$in2,v31 + vcipher $out3,$out3,v30 + vxor $in3,$in3,v31 + vcipher $out4,$out4,v30 + vxor $in4,$in4,v31 + vcipher $out5,$out5,v30 + vxor $in5,$in5,v31 + vcipher $out6,$out6,v30 + vxor $in6,$in6,v31 + vcipher $out7,$out7,v30 + vxor $in7,$in7,v31 + + bne Lctr32_enc8x_break # did $len-129 borrow? + + vcipherlast $in0,$out0,$in0 + vcipherlast $in1,$out1,$in1 + vadduwm $out1,$ivec,$one # counter values ... + vcipherlast $in2,$out2,$in2 + vadduwm $out2,$ivec,$two + vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0] + vcipherlast $in3,$out3,$in3 + vadduwm $out3,$out1,$two + vxor $out1,$out1,$rndkey0 + vcipherlast $in4,$out4,$in4 + vadduwm $out4,$out2,$two + vxor $out2,$out2,$rndkey0 + vcipherlast $in5,$out5,$in5 + vadduwm $out5,$out3,$two + vxor $out3,$out3,$rndkey0 + vcipherlast $in6,$out6,$in6 + vadduwm $out6,$out4,$two + vxor $out4,$out4,$rndkey0 + vcipherlast $in7,$out7,$in7 + vadduwm $out7,$out5,$two + vxor $out5,$out5,$rndkey0 + le?vperm $in0,$in0,$in0,$inpperm + vadduwm $ivec,$out6,$two # next counter value + vxor $out6,$out6,$rndkey0 + le?vperm $in1,$in1,$in1,$inpperm + vxor $out7,$out7,$rndkey0 + mtctr $rounds + + vcipher $out0,$out0,v24 + stvx_u $in0,$x00,$out + le?vperm $in2,$in2,$in2,$inpperm + vcipher $out1,$out1,v24 + stvx_u $in1,$x10,$out + le?vperm $in3,$in3,$in3,$inpperm + vcipher $out2,$out2,v24 + stvx_u $in2,$x20,$out + le?vperm $in4,$in4,$in4,$inpperm + vcipher $out3,$out3,v24 + stvx_u $in3,$x30,$out + le?vperm $in5,$in5,$in5,$inpperm + vcipher $out4,$out4,v24 + stvx_u $in4,$x40,$out + le?vperm $in6,$in6,$in6,$inpperm + vcipher $out5,$out5,v24 + stvx_u $in5,$x50,$out + le?vperm $in7,$in7,$in7,$inpperm + vcipher $out6,$out6,v24 + stvx_u $in6,$x60,$out + vcipher $out7,$out7,v24 + stvx_u $in7,$x70,$out + addi $out,$out,0x80 + + b Loop_ctr32_enc8x_middle + +.align 5 +Lctr32_enc8x_break: + cmpwi $len,-0x60 + blt Lctr32_enc8x_one + nop + beq Lctr32_enc8x_two + cmpwi $len,-0x40 + blt Lctr32_enc8x_three + nop + beq Lctr32_enc8x_four + cmpwi $len,-0x20 + blt Lctr32_enc8x_five + nop + beq Lctr32_enc8x_six + cmpwi $len,0x00 + blt Lctr32_enc8x_seven + +Lctr32_enc8x_eight: + vcipherlast $out0,$out0,$in0 + vcipherlast $out1,$out1,$in1 + vcipherlast $out2,$out2,$in2 + vcipherlast $out3,$out3,$in3 + vcipherlast $out4,$out4,$in4 + vcipherlast $out5,$out5,$in5 + vcipherlast $out6,$out6,$in6 + vcipherlast $out7,$out7,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x60,$out + stvx_u $out7,$x70,$out + addi $out,$out,0x80 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_seven: + vcipherlast $out0,$out0,$in1 + vcipherlast $out1,$out1,$in2 + vcipherlast $out2,$out2,$in3 + vcipherlast $out3,$out3,$in4 + vcipherlast $out4,$out4,$in5 + vcipherlast $out5,$out5,$in6 + vcipherlast $out6,$out6,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + stvx_u $out6,$x60,$out + addi $out,$out,0x70 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_six: + vcipherlast $out0,$out0,$in2 + vcipherlast $out1,$out1,$in3 + vcipherlast $out2,$out2,$in4 + vcipherlast $out3,$out3,$in5 + vcipherlast $out4,$out4,$in6 + vcipherlast $out5,$out5,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + stvx_u $out5,$x50,$out + addi $out,$out,0x60 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_five: + vcipherlast $out0,$out0,$in3 + vcipherlast $out1,$out1,$in4 + vcipherlast $out2,$out2,$in5 + vcipherlast $out3,$out3,$in6 + vcipherlast $out4,$out4,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + stvx_u $out4,$x40,$out + addi $out,$out,0x50 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_four: + vcipherlast $out0,$out0,$in4 + vcipherlast $out1,$out1,$in5 + vcipherlast $out2,$out2,$in6 + vcipherlast $out3,$out3,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + stvx_u $out3,$x30,$out + addi $out,$out,0x40 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_three: + vcipherlast $out0,$out0,$in5 + vcipherlast $out1,$out1,$in6 + vcipherlast $out2,$out2,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + stvx_u $out2,$x20,$out + addi $out,$out,0x30 + b Lcbc_dec8x_done + +.align 5 +Lctr32_enc8x_two: + vcipherlast $out0,$out0,$in6 + vcipherlast $out1,$out1,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + stvx_u $out1,$x10,$out + addi $out,$out,0x20 + b Lcbc_dec8x_done + +.align 5 +Lctr32_enc8x_one: + vcipherlast $out0,$out0,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + stvx_u $out0,0,$out + addi $out,$out,0x10 + +Lctr32_enc8x_done: + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $inpperm,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x14,0,0x80,6,6,0 + .long 0 +.size .${prefix}_ctr32_encrypt_blocks,.-.${prefix}_ctr32_encrypt_blocks +___ +}} }}} + +my $consts=1; +foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + # constants table endian-specific conversion + if ($consts && m/\.(long|byte)\s+(.+)\s+(\?[a-z]*)$/o) { + my $conv=$3; + my @bytes=(); + + # convert to endian-agnostic format + if ($1 eq "long") { + foreach (split(/,\s*/,$2)) { + my $l = /^0/?oct:int; + push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff; + } + } else { + @bytes = map(/^0/?oct:int,split(/,\s*/,$2)); + } + + # little-endian conversion + if ($flavour =~ /le$/o) { + SWITCH: for($conv) { + /\?inv/ && do { @bytes=map($_^0xf,@bytes); last; }; + /\?rev/ && do { @bytes=reverse(@bytes); last; }; + } + } + + #emit + print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n"; + next; + } + $consts=0 if (m/Lconsts:/o); # end of table + + # instructions prefixed with '?' are endian-specific and need + # to be adjusted accordingly... + if ($flavour =~ /le$/o) { # little-endian + s/le\?//o or + s/be\?/#be#/o or + s/\?lvsr/lvsl/o or + s/\?lvsl/lvsr/o or + s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or + s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or + s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o; + } else { # big-endian + s/le\?/#le#/o or + s/be\?//o or + s/\?([a-z]+)/$1/o; + } + + print $_,"\n"; +} + +close STDOUT; diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/drivers/crypto/vmx/ghashp8-ppc.pl new file mode 100755 index 000000000000..e76a58c343c1 --- /dev/null +++ b/drivers/crypto/vmx/ghashp8-ppc.pl @@ -0,0 +1,234 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# GHASH for for PowerISA v2.07. +# +# July 2014 +# +# Accurate performance measurements are problematic, because it's +# always virtualized setup with possibly throttled processor. +# Relative comparison is therefore more informative. This initial +# version is ~2.1x slower than hardware-assisted AES-128-CTR, ~12x +# faster than "4-bit" integer-only compiler-generated 64-bit code. +# "Initial version" means that there is room for futher improvement. + +$flavour=shift; +$output =shift; + +if ($flavour =~ /64/) { + $SIZE_T=8; + $LRSAVE=2*$SIZE_T; + $STU="stdu"; + $POP="ld"; + $PUSH="std"; +} elsif ($flavour =~ /32/) { + $SIZE_T=4; + $LRSAVE=$SIZE_T; + $STU="stwu"; + $POP="lwz"; + $PUSH="stw"; +} else { die "nonsense $flavour"; } + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or +die "can't locate ppc-xlate.pl"; + +open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!"; + +my ($Xip,$Htbl,$inp,$len)=map("r$_",(3..6)); # argument block + +my ($Xl,$Xm,$Xh,$IN)=map("v$_",(0..3)); +my ($zero,$t0,$t1,$t2,$xC2,$H,$Hh,$Hl,$lemask)=map("v$_",(4..12)); +my $vrsave="r12"; + +$code=<<___; +.machine "any" + +.text + +.globl .gcm_init_p8 +.align 5 +.gcm_init_p8: + lis r0,0xfff0 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $H,0,r4 # load H + + vspltisb $xC2,-16 # 0xf0 + vspltisb $t0,1 # one + vaddubm $xC2,$xC2,$xC2 # 0xe0 + vxor $zero,$zero,$zero + vor $xC2,$xC2,$t0 # 0xe1 + vsldoi $xC2,$xC2,$zero,15 # 0xe1... + vsldoi $t1,$zero,$t0,1 # ...1 + vaddubm $xC2,$xC2,$xC2 # 0xc2... + vspltisb $t2,7 + vor $xC2,$xC2,$t1 # 0xc2....01 + vspltb $t1,$H,0 # most significant byte + vsl $H,$H,$t0 # H<<=1 + vsrab $t1,$t1,$t2 # broadcast carry bit + vand $t1,$t1,$xC2 + vxor $H,$H,$t1 # twisted H + + vsldoi $H,$H,$H,8 # twist even more ... + vsldoi $xC2,$zero,$xC2,8 # 0xc2.0 + vsldoi $Hl,$zero,$H,8 # ... and split + vsldoi $Hh,$H,$zero,8 + + stvx_u $xC2,0,r3 # save pre-computed table + stvx_u $Hl,r8,r3 + stvx_u $H, r9,r3 + stvx_u $Hh,r10,r3 + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,2,0 + .long 0 +.size .gcm_init_p8,.-.gcm_init_p8 + +.globl .gcm_gmult_p8 +.align 5 +.gcm_gmult_p8: + lis r0,0xfff8 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $IN,0,$Xip # load Xi + + lvx_u $Hl,r8,$Htbl # load pre-computed table + le?lvsl $lemask,r0,r0 + lvx_u $H, r9,$Htbl + le?vspltisb $t0,0x07 + lvx_u $Hh,r10,$Htbl + le?vxor $lemask,$lemask,$t0 + lvx_u $xC2,0,$Htbl + le?vperm $IN,$IN,$IN,$lemask + vxor $zero,$zero,$zero + + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + + vpmsumd $t2,$Xl,$xC2 # 1st phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd phase + vpmsumd $Xl,$Xl,$xC2 + vxor $t1,$t1,$Xh + vxor $Xl,$Xl,$t1 + + le?vperm $Xl,$Xl,$Xl,$lemask + stvx_u $Xl,0,$Xip # write out Xi + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,2,0 + .long 0 +.size .gcm_gmult_p8,.-.gcm_gmult_p8 + +.globl .gcm_ghash_p8 +.align 5 +.gcm_ghash_p8: + lis r0,0xfff8 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $Xl,0,$Xip # load Xi + + lvx_u $Hl,r8,$Htbl # load pre-computed table + le?lvsl $lemask,r0,r0 + lvx_u $H, r9,$Htbl + le?vspltisb $t0,0x07 + lvx_u $Hh,r10,$Htbl + le?vxor $lemask,$lemask,$t0 + lvx_u $xC2,0,$Htbl + le?vperm $Xl,$Xl,$Xl,$lemask + vxor $zero,$zero,$zero + + lvx_u $IN,0,$inp + addi $inp,$inp,16 + subi $len,$len,16 + le?vperm $IN,$IN,$IN,$lemask + vxor $IN,$IN,$Xl + b Loop + +.align 5 +Loop: + subic $len,$len,16 + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + subfe. r0,r0,r0 # borrow?-1:0 + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + and r0,r0,$len + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + add $inp,$inp,r0 + + vpmsumd $t2,$Xl,$xC2 # 1st phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + lvx_u $IN,0,$inp + addi $inp,$inp,16 + + vsldoi $t1,$Xl,$Xl,8 # 2nd phase + vpmsumd $Xl,$Xl,$xC2 + le?vperm $IN,$IN,$IN,$lemask + vxor $t1,$t1,$Xh + vxor $IN,$IN,$t1 + vxor $IN,$IN,$Xl + beq Loop # did $len-=16 borrow? + + vxor $Xl,$Xl,$t1 + le?vperm $Xl,$Xl,$Xl,$lemask + stvx_u $Xl,0,$Xip # write out Xi + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,4,0 + .long 0 +.size .gcm_ghash_p8,.-.gcm_ghash_p8 + +.asciz "GHASH for PowerISA 2.07, CRYPTOGAMS by " +.align 2 +___ + +foreach (split("\n",$code)) { + if ($flavour =~ /le$/o) { # little-endian + s/le\?//o or + s/be\?/#be#/o; + } else { + s/le\?/#le#/o or + s/be\?//o; + } + print $_,"\n"; +} + +close STDOUT; # enforce flush diff --git a/drivers/crypto/vmx/ppc-xlate.pl b/drivers/crypto/vmx/ppc-xlate.pl new file mode 100755 index 000000000000..f89e81429931 --- /dev/null +++ b/drivers/crypto/vmx/ppc-xlate.pl @@ -0,0 +1,226 @@ +#!/usr/bin/env perl + +# PowerPC assembler distiller by . + +my $flavour = shift; +my $output = shift; +open STDOUT,">$output" || die "can't open $output: $!"; + +my %GLOBALS; +my $dotinlocallabels=($flavour=~/linux/)?1:0; + +################################################################ +# directives which need special treatment on different platforms +################################################################ +my $globl = sub { + my $junk = shift; + my $name = shift; + my $global = \$GLOBALS{$name}; + my $ret; + + $name =~ s|^[\.\_]||; + + SWITCH: for ($flavour) { + /aix/ && do { $name = ".$name"; + last; + }; + /osx/ && do { $name = "_$name"; + last; + }; + /linux.*(32|64le)/ + && do { $ret .= ".globl $name\n"; + $ret .= ".type $name,\@function"; + last; + }; + /linux.*64/ && do { $ret .= ".globl $name\n"; + $ret .= ".type $name,\@function\n"; + $ret .= ".section \".opd\",\"aw\"\n"; + $ret .= ".align 3\n"; + $ret .= "$name:\n"; + $ret .= ".quad .$name,.TOC.\@tocbase,0\n"; + $ret .= ".previous\n"; + + $name = ".$name"; + last; + }; + } + + $ret = ".globl $name" if (!$ret); + $$global = $name; + $ret; +}; +my $text = sub { + my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; + $ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64le/); + $ret; +}; +my $machine = sub { + my $junk = shift; + my $arch = shift; + if ($flavour =~ /osx/) + { $arch =~ s/\"//g; + $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); + } + ".machine $arch"; +}; +my $size = sub { + if ($flavour =~ /linux/) + { shift; + my $name = shift; $name =~ s|^[\.\_]||; + my $ret = ".size $name,.-".($flavour=~/64$/?".":"").$name; + $ret .= "\n.size .$name,.-.$name" if ($flavour=~/64$/); + $ret; + } + else + { ""; } +}; +my $asciz = sub { + shift; + my $line = join(",",@_); + if ($line =~ /^"(.*)"$/) + { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } + else + { ""; } +}; +my $quad = sub { + shift; + my @ret; + my ($hi,$lo); + for (@_) { + if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) + { $hi=$1?"0x$1":"0"; $lo="0x$2"; } + elsif (/^([0-9]+)$/o) + { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl + else + { $hi=undef; $lo=$_; } + + if (defined($hi)) + { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } + else + { push(@ret,".quad $lo"); } + } + join("\n",@ret); +}; + +################################################################ +# simplified mnemonics not handled by at least one assembler +################################################################ +my $cmplw = sub { + my $f = shift; + my $cr = 0; $cr = shift if ($#_>1); + # Some out-of-date 32-bit GNU assembler just can't handle cmplw... + ($flavour =~ /linux.*32/) ? + " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : + " cmplw ".join(',',$cr,@_); +}; +my $bdnz = sub { + my $f = shift; + my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint + " bc $bo,0,".shift; +} if ($flavour!~/linux/); +my $bltlr = sub { + my $f = shift; + my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : + " bclr $bo,0"; +}; +my $bnelr = sub { + my $f = shift; + my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : + " bclr $bo,2"; +}; +my $beqlr = sub { + my $f = shift; + my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : + " bclr $bo,2"; +}; +# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two +# arguments is 64, with "operand out of range" error. +my $extrdi = sub { + my ($f,$ra,$rs,$n,$b) = @_; + $b = ($b+$n)&63; $n = 64-$n; + " rldicl $ra,$rs,$b,$n"; +}; +my $vmr = sub { + my ($f,$vx,$vy) = @_; + " vor $vx,$vy,$vy"; +}; + +# PowerISA 2.06 stuff +sub vsxmem_op { + my ($f, $vrt, $ra, $rb, $op) = @_; + " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); +} +# made-up unaligned memory reference AltiVec/VMX instructions +my $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x +my $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x +my $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx +my $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx +my $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x +my $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x + +# PowerISA 2.07 stuff +sub vcrypto_op { + my ($f, $vrt, $vra, $vrb, $op) = @_; + " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; +} +my $vcipher = sub { vcrypto_op(@_, 1288); }; +my $vcipherlast = sub { vcrypto_op(@_, 1289); }; +my $vncipher = sub { vcrypto_op(@_, 1352); }; +my $vncipherlast= sub { vcrypto_op(@_, 1353); }; +my $vsbox = sub { vcrypto_op(@_, 0, 1480); }; +my $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; +my $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; +my $vpmsumb = sub { vcrypto_op(@_, 1032); }; +my $vpmsumd = sub { vcrypto_op(@_, 1224); }; +my $vpmsubh = sub { vcrypto_op(@_, 1096); }; +my $vpmsumw = sub { vcrypto_op(@_, 1160); }; +my $vaddudm = sub { vcrypto_op(@_, 192); }; + +my $mtsle = sub { + my ($f, $arg) = @_; + " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); +}; + +while($line=<>) { + + $line =~ s|[#!;].*$||; # get rid of asm-style comments... + $line =~ s|/\*.*\*/||; # ... and C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning... + $line =~ s|\s+$||; # ... and at the end + + { + $line =~ s|\b\.L(\w+)|L$1|g; # common denominator for Locallabel + $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); + } + + { + $line =~ s|(^[\.\w]+)\:\s*||; + my $label = $1; + if ($label) { + printf "%s:",($GLOBALS{$label} or $label); + printf "\n.localentry\t$GLOBALS{$label},0" if ($GLOBALS{$label} && $flavour =~ /linux.*64le/); + } + } + + { + $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; + my $c = $1; $c = "\t" if ($c eq ""); + my $mnemonic = $2; + my $f = $3; + my $opcode = eval("\$$mnemonic"); + $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); + if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } + elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } + } + + print $line if ($line); + print "\n"; +} + +close STDOUT; -- GitLab From d2e3ae6f3abad839214f7b05c34075a1a7c82470 Mon Sep 17 00:00:00 2001 From: "Leonidas S. Barbosa" Date: Fri, 6 Feb 2015 14:59:48 -0200 Subject: [PATCH 0103/1910] crypto: vmx - Enabling VMX module for PPC64 This patch enables VMX module in PPC64. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 9 +++++++++ drivers/crypto/Makefile | 1 + drivers/crypto/vmx/Kconfig | 8 ++++++++ drivers/crypto/vmx/Makefile | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 drivers/crypto/vmx/Kconfig create mode 100644 drivers/crypto/vmx/Makefile diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 7e94413da6e3..9dd34bc3f541 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -436,4 +436,13 @@ config CRYPTO_DEV_QCE hardware. To compile this driver as a module, choose M here. The module will be called qcrypto. +config CRYPTO_DEV_VMX + bool "Support for VMX cryptographic acceleration instructions" + depends on PPC64 + default n + help + Support for VMX cryptographic acceleration instructions. + +source "drivers/crypto/vmx/Kconfig" + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 3924f93d5774..20a71273369a 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/ +obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig new file mode 100644 index 000000000000..771babf16aa0 --- /dev/null +++ b/drivers/crypto/vmx/Kconfig @@ -0,0 +1,8 @@ +config CRYPTO_DEV_VMX_ENCRYPT + tristate "Encryption acceleration support on P8 CPU" + depends on PPC64 && CRYPTO_DEV_VMX + default y + help + Support for VMX cryptographic acceleration instructions on Power8 CPU. + This module supports acceleration for AES and GHASH in hardware. If you + choose 'M' here, this module will be called vmx-crypto. diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile new file mode 100644 index 000000000000..c699c6e6c82e --- /dev/null +++ b/drivers/crypto/vmx/Makefile @@ -0,0 +1,19 @@ +obj-$(CONFIG_CRYPTO_DEV_VMX_ENCRYPT) += vmx-crypto.o +vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o ghash.o + +ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) +TARGET := linux-ppc64le +else +TARGET := linux-pcc64 +endif + +quiet_cmd_perl = PERL $@ + cmd_perl = $(PERL) $(<) $(TARGET) > $(@) + +$(src)/aesp8-ppc.S: $(src)/aesp8-ppc.pl + $(call cmd,perl) + +$(src)/ghashp8-ppc.S: $(src)/ghashp8-ppc.pl + $(call cmd,perl) + +.PRECIOUS: $(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S -- GitLab From 81e397d937a8e9f46f024a9f876cf14d8e2b45a7 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 6 Feb 2015 10:25:20 -0800 Subject: [PATCH 0104/1910] crypto: aesni - make driver-gcm-aes-aesni helper a proper aead alg Changed the __driver-gcm-aes-aesni to be a proper aead algorithm. This required a valid setkey and setauthsize functions to be added and also some changes to make sure that math context is not corrupted when the alg is used directly. Note that the __driver-gcm-aes-aesni should not be used directly by modules that can use it in interrupt context as we don't have a good fallback mechanism in this case. Signed-off-by: Adrian Hoban Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- arch/x86/crypto/aesni-intel_glue.c | 164 +++++++++++++++++++---------- 1 file changed, 110 insertions(+), 54 deletions(-) diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 947c6bf52c33..6893f4947583 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -890,15 +890,12 @@ rfc4106_set_hash_subkey(u8 *hash_subkey, const u8 *key, unsigned int key_len) return ret; } -static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key, - unsigned int key_len) +static int common_rfc4106_set_key(struct crypto_aead *aead, const u8 *key, + unsigned int key_len) { int ret = 0; - struct crypto_tfm *tfm = crypto_aead_tfm(parent); - struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(parent); - struct crypto_aead *cryptd_child = cryptd_aead_child(ctx->cryptd_tfm); - struct aesni_rfc4106_gcm_ctx *child_ctx = - aesni_rfc4106_gcm_ctx_get(cryptd_child); + struct crypto_tfm *tfm = crypto_aead_tfm(aead); + struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(aead); u8 *new_key_align, *new_key_mem = NULL; if (key_len < 4) { @@ -943,20 +940,31 @@ static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key, goto exit; } ret = rfc4106_set_hash_subkey(ctx->hash_subkey, key, key_len); - memcpy(child_ctx, ctx, sizeof(*ctx)); exit: kfree(new_key_mem); return ret; } -/* This is the Integrity Check Value (aka the authentication tag length and can - * be 8, 12 or 16 bytes long. */ -static int rfc4106_set_authsize(struct crypto_aead *parent, - unsigned int authsize) +static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key, + unsigned int key_len) { struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(parent); - struct crypto_aead *cryptd_child = cryptd_aead_child(ctx->cryptd_tfm); + struct crypto_aead *child = cryptd_aead_child(ctx->cryptd_tfm); + struct aesni_rfc4106_gcm_ctx *c_ctx = aesni_rfc4106_gcm_ctx_get(child); + struct cryptd_aead *cryptd_tfm = ctx->cryptd_tfm; + int ret; + ret = crypto_aead_setkey(child, key, key_len); + if (!ret) { + memcpy(ctx, c_ctx, sizeof(*ctx)); + ctx->cryptd_tfm = cryptd_tfm; + } + return ret; +} + +static int common_rfc4106_set_authsize(struct crypto_aead *aead, + unsigned int authsize) +{ switch (authsize) { case 8: case 12: @@ -965,51 +973,23 @@ static int rfc4106_set_authsize(struct crypto_aead *parent, default: return -EINVAL; } - crypto_aead_crt(parent)->authsize = authsize; - crypto_aead_crt(cryptd_child)->authsize = authsize; + crypto_aead_crt(aead)->authsize = authsize; return 0; } -static int rfc4106_encrypt(struct aead_request *req) -{ - int ret; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm); - - if (!irq_fpu_usable()) { - struct aead_request *cryptd_req = - (struct aead_request *) aead_request_ctx(req); - memcpy(cryptd_req, req, sizeof(*req)); - aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); - return crypto_aead_encrypt(cryptd_req); - } else { - struct crypto_aead *cryptd_child = cryptd_aead_child(ctx->cryptd_tfm); - kernel_fpu_begin(); - ret = cryptd_child->base.crt_aead.encrypt(req); - kernel_fpu_end(); - return ret; - } -} - -static int rfc4106_decrypt(struct aead_request *req) +/* This is the Integrity Check Value (aka the authentication tag length and can + * be 8, 12 or 16 bytes long. */ +static int rfc4106_set_authsize(struct crypto_aead *parent, + unsigned int authsize) { + struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(parent); + struct crypto_aead *child = cryptd_aead_child(ctx->cryptd_tfm); int ret; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm); - if (!irq_fpu_usable()) { - struct aead_request *cryptd_req = - (struct aead_request *) aead_request_ctx(req); - memcpy(cryptd_req, req, sizeof(*req)); - aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); - return crypto_aead_decrypt(cryptd_req); - } else { - struct crypto_aead *cryptd_child = cryptd_aead_child(ctx->cryptd_tfm); - kernel_fpu_begin(); - ret = cryptd_child->base.crt_aead.decrypt(req); - kernel_fpu_end(); - return ret; - } + ret = crypto_aead_setauthsize(child, authsize); + if (!ret) + crypto_aead_crt(parent)->authsize = authsize; + return ret; } static int __driver_rfc4106_encrypt(struct aead_request *req) @@ -1185,6 +1165,78 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) } return retval; } + +static int rfc4106_encrypt(struct aead_request *req) +{ + int ret; + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm); + + if (!irq_fpu_usable()) { + struct aead_request *cryptd_req = + (struct aead_request *) aead_request_ctx(req); + + memcpy(cryptd_req, req, sizeof(*req)); + aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); + ret = crypto_aead_encrypt(cryptd_req); + } else { + kernel_fpu_begin(); + ret = __driver_rfc4106_encrypt(req); + kernel_fpu_end(); + } + return ret; +} + +static int rfc4106_decrypt(struct aead_request *req) +{ + int ret; + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm); + + if (!irq_fpu_usable()) { + struct aead_request *cryptd_req = + (struct aead_request *) aead_request_ctx(req); + + memcpy(cryptd_req, req, sizeof(*req)); + aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); + ret = crypto_aead_decrypt(cryptd_req); + } else { + kernel_fpu_begin(); + ret = __driver_rfc4106_decrypt(req); + kernel_fpu_end(); + } + return ret; +} + +static int helper_rfc4106_encrypt(struct aead_request *req) +{ + int ret; + + if (unlikely(!irq_fpu_usable())) { + WARN_ONCE(1, "__gcm-aes-aesni alg used in invalid context"); + ret = -EINVAL; + } else { + kernel_fpu_begin(); + ret = __driver_rfc4106_encrypt(req); + kernel_fpu_end(); + } + return ret; +} + +static int helper_rfc4106_decrypt(struct aead_request *req) +{ + int ret; + + if (unlikely(!irq_fpu_usable())) { + WARN_ONCE(1, "__gcm-aes-aesni alg used in invalid context"); + ret = -EINVAL; + } else { + kernel_fpu_begin(); + ret = __driver_rfc4106_decrypt(req); + kernel_fpu_end(); + } + return ret; +} #endif static struct crypto_alg aesni_algs[] = { { @@ -1366,8 +1418,12 @@ static struct crypto_alg aesni_algs[] = { { .cra_module = THIS_MODULE, .cra_u = { .aead = { - .encrypt = __driver_rfc4106_encrypt, - .decrypt = __driver_rfc4106_decrypt, + .setkey = common_rfc4106_set_key, + .setauthsize = common_rfc4106_set_authsize, + .encrypt = helper_rfc4106_encrypt, + .decrypt = helper_rfc4106_decrypt, + .ivsize = 8, + .maxauthsize = 16, }, }, }, { -- GitLab From dd0fff8db627e08272af98d9480ae8d892d8f440 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 7 Feb 2015 03:09:41 -0500 Subject: [PATCH 0105/1910] crypto: mxs-dcp - fix type of ret for wait_for_completion_timeout return type of wait_for_completion_timeout is unsigned long not int, this patch changes the type of ret from int to unsigned long. Signed-off-by: Nicholas Mc Guire Signed-off-by: Herbert Xu --- drivers/crypto/mxs-dcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 829d6394fb33..59ed54e464a9 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -153,7 +153,7 @@ static int mxs_dcp_start_dma(struct dcp_async_ctx *actx) struct dcp *sdcp = global_sdcp; const int chan = actx->chan; uint32_t stat; - int ret; + unsigned long ret; struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; dma_addr_t desc_phys = dma_map_single(sdcp->dev, desc, sizeof(*desc), -- GitLab From 58ed798b8291f1d63c00d6dfe077587494a6790a Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 7 Feb 2015 06:17:13 -0500 Subject: [PATCH 0106/1910] crypto: sahara - fix type of ret for wait_for_completion_timeout return type of wait_for_completion_timeout is unsigned long not int, this patch adds appropriate variables of type unsigned long. Signed-off-by: Nicholas Mc Guire Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 290a7f0a681f..b65e2a5ab46f 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -576,6 +576,7 @@ static int sahara_aes_process(struct ablkcipher_request *req) struct sahara_ctx *ctx; struct sahara_aes_reqctx *rctx; int ret; + unsigned long timeout; /* Request is ready to be dispatched by the device */ dev_dbg(dev->device, @@ -602,9 +603,9 @@ static int sahara_aes_process(struct ablkcipher_request *req) ret = sahara_hw_descriptor_create(dev); - ret = wait_for_completion_timeout(&dev->dma_completion, + timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); - if (!ret) { + if (!timeout) { dev_err(dev->device, "AES timeout\n"); return -ETIMEDOUT; } @@ -1045,6 +1046,7 @@ static int sahara_sha_process(struct ahash_request *req) struct sahara_dev *dev = dev_ptr; struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); int ret = -EINPROGRESS; + unsigned long timeout; ret = sahara_sha_prepare_request(req); if (!ret) @@ -1070,9 +1072,9 @@ static int sahara_sha_process(struct ahash_request *req) sahara_write(dev, dev->hw_phys_desc[0], SAHARA_REG_DAR); - ret = wait_for_completion_timeout(&dev->dma_completion, + timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); - if (!ret) { + if (!timeout) { dev_err(dev->device, "SHA timeout\n"); return -ETIMEDOUT; } -- GitLab From 6cf02fcab1f6158c224fb00619f21556d8e5c4ea Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 7 Feb 2015 06:27:45 -0500 Subject: [PATCH 0107/1910] crypto: sahara - pass on error condition A failure of sahara_hw_descriptor_create() with -EINVAL due to scatter list out of bounds/invalid would not be reported back. This patch just passes on the -EINVAL so it is visible in sahara_queue_manage(). Signed-off-by: Nicholas Mc Guire Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index b65e2a5ab46f..822978d823aa 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -602,6 +602,8 @@ static int sahara_aes_process(struct ablkcipher_request *req) reinit_completion(&dev->dma_completion); ret = sahara_hw_descriptor_create(dev); + if (ret) + return -EINVAL; timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); -- GitLab From df586cbb6be97aaf55b9a01e1d0ab01bc03d70d1 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 7 Feb 2015 06:16:46 -0500 Subject: [PATCH 0108/1910] crypto: sahara - drop unnecessary default assignment All possible code-paths will assign ret to suitable values so this default value is not needed. Signed-off-by: Nicholas Mc Guire Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 822978d823aa..c38553ed792c 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1047,7 +1047,7 @@ static int sahara_sha_process(struct ahash_request *req) { struct sahara_dev *dev = dev_ptr; struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); - int ret = -EINPROGRESS; + int ret; unsigned long timeout; ret = sahara_sha_prepare_request(req); -- GitLab From f7591faec6f66bcd91bca25f91192c787f63d365 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 16 Feb 2015 18:09:13 -0800 Subject: [PATCH 0109/1910] hwrng: bcm63xx - drop bcm_{readl,writel} macros bcm_{readl,writel} macros expand to __raw_{readl,writel}, use these directly such that we do not rely on the platform to provide these for us. As a result, we no longer use bcm63xx_io.h, so remove that inclusion too. Signed-off-by: Florian Fainelli Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm63xx-rng.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index ba6a65ac023b..ed9b28b35a39 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -13,7 +13,6 @@ #include #include -#include #include struct bcm63xx_rng_priv { @@ -28,9 +27,9 @@ static int bcm63xx_rng_init(struct hwrng *rng) struct bcm63xx_rng_priv *priv = to_rng_priv(rng); u32 val; - val = bcm_readl(priv->regs + RNG_CTRL); + val = __raw_readl(priv->regs + RNG_CTRL); val |= RNG_EN; - bcm_writel(val, priv->regs + RNG_CTRL); + __raw_writel(val, priv->regs + RNG_CTRL); return 0; } @@ -40,23 +39,23 @@ static void bcm63xx_rng_cleanup(struct hwrng *rng) struct bcm63xx_rng_priv *priv = to_rng_priv(rng); u32 val; - val = bcm_readl(priv->regs + RNG_CTRL); + val = __raw_readl(priv->regs + RNG_CTRL); val &= ~RNG_EN; - bcm_writel(val, priv->regs + RNG_CTRL); + __raw_writel(val, priv->regs + RNG_CTRL); } static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) { struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; + return __raw_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; } static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data) { struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - *data = bcm_readl(priv->regs + RNG_DATA); + *data = __raw_readl(priv->regs + RNG_DATA); return 4; } -- GitLab From b515e0f989124ee7a13df45a318273f51081d58f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 16 Feb 2015 18:09:14 -0800 Subject: [PATCH 0110/1910] hwrng: bcm63xx - move register definitions to driver arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h contains the register definitions for this random number generator block, incorporate these register definitions directly into the bcm63xx-rng driver so we do not rely on this header to be provided. Signed-off-by: Florian Fainelli Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm63xx-rng.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index ed9b28b35a39..c7f3af852599 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -13,7 +13,15 @@ #include #include -#include +#define RNG_CTRL 0x00 +#define RNG_EN (1 << 0) + +#define RNG_STAT 0x04 +#define RNG_AVAIL_MASK (0xff000000) + +#define RNG_DATA 0x08 +#define RNG_THRES 0x0c +#define RNG_MASK 0x10 struct bcm63xx_rng_priv { struct clk *clk; -- GitLab From aeb9624f96581732b1ffd21af967375839ba227d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 16 Feb 2015 18:09:15 -0800 Subject: [PATCH 0111/1910] MIPS: BCM63xx: remove RSET_RNG register definitions Now that these definitions have been moved to drivers/char/hw_random/bcm63xx-rng.c where they belong to make the driver standalone, we can safely remove these definitions from bcm63xx_regs.h. Signed-off-by: Florian Fainelli Signed-off-by: Herbert Xu --- arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 4794067cb5a7..5035f09c5427 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -1258,20 +1258,6 @@ #define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14) #define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18) -/************************************************************************* - * _REG relative to RSET_RNG - *************************************************************************/ - -#define RNG_CTRL 0x00 -#define RNG_EN (1 << 0) - -#define RNG_STAT 0x04 -#define RNG_AVAIL_MASK (0xff000000) - -#define RNG_DATA 0x08 -#define RNG_THRES 0x0c -#define RNG_MASK 0x10 - /************************************************************************* * _REG relative to RSET_SPI *************************************************************************/ -- GitLab From 0052a65413f006663e0d7fbfc886ea5bbd8f197f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 16 Feb 2015 18:09:16 -0800 Subject: [PATCH 0112/1910] hwrng: bcm63xx - use devm_* helpers Simplify the driver's probe function and error handling by using the device managed allocators, while at it, drop the redundant "out of memory" messages since these are already printed by the allocator. Signed-off-by: Florian Fainelli Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm63xx-rng.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index c7f3af852599..27da00f68c8f 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -83,18 +83,16 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) goto out; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { - dev_err(&pdev->dev, "no memory for private structure\n"); ret = -ENOMEM; goto out; } - rng = kzalloc(sizeof(*rng), GFP_KERNEL); + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); if (!rng) { - dev_err(&pdev->dev, "no memory for rng structure\n"); ret = -ENOMEM; - goto out_free_priv; + goto out; } platform_set_drvdata(pdev, rng); @@ -109,7 +107,7 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) if (IS_ERR(clk)) { dev_err(&pdev->dev, "no clock for device\n"); ret = PTR_ERR(clk); - goto out_free_rng; + goto out; } priv->clk = clk; @@ -118,7 +116,7 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) resource_size(r), pdev->name)) { dev_err(&pdev->dev, "request mem failed"); ret = -ENOMEM; - goto out_free_rng; + goto out; } priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, @@ -126,7 +124,7 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) if (!priv->regs) { dev_err(&pdev->dev, "ioremap failed"); ret = -ENOMEM; - goto out_free_rng; + goto out; } clk_enable(clk); @@ -143,10 +141,6 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) out_clk_disable: clk_disable(clk); -out_free_rng: - kfree(rng); -out_free_priv: - kfree(priv); out: return ret; } @@ -158,8 +152,6 @@ static int bcm63xx_rng_remove(struct platform_device *pdev) hwrng_unregister(rng); clk_disable(priv->clk); - kfree(priv); - kfree(rng); return 0; } -- GitLab From 74f2dc2041d3d66689984cdb987f3224caffaedd Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 09:59:38 +0100 Subject: [PATCH 0113/1910] crypto: powerpc/aes - register defines Define some register aliases for better readability. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-spe-regs.h | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 arch/powerpc/crypto/aes-spe-regs.h diff --git a/arch/powerpc/crypto/aes-spe-regs.h b/arch/powerpc/crypto/aes-spe-regs.h new file mode 100644 index 000000000000..30d217b399c3 --- /dev/null +++ b/arch/powerpc/crypto/aes-spe-regs.h @@ -0,0 +1,42 @@ +/* + * Common registers for PPC AES implementation + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#define rKS r0 /* copy of en-/decryption key pointer */ +#define rDP r3 /* destination pointer */ +#define rSP r4 /* source pointer */ +#define rKP r5 /* pointer to en-/decryption key pointer */ +#define rRR r6 /* en-/decryption rounds */ +#define rLN r7 /* length of data to be processed */ +#define rIP r8 /* potiner to IV (CBC/CTR/XTS modes) */ +#define rKT r9 /* pointer to tweak key (XTS mode) */ +#define rT0 r11 /* pointers to en-/decrpytion tables */ +#define rT1 r10 +#define rD0 r9 /* data */ +#define rD1 r14 +#define rD2 r12 +#define rD3 r15 +#define rW0 r16 /* working registers */ +#define rW1 r17 +#define rW2 r18 +#define rW3 r19 +#define rW4 r20 +#define rW5 r21 +#define rW6 r22 +#define rW7 r23 +#define rI0 r24 /* IV */ +#define rI1 r25 +#define rI2 r26 +#define rI3 r27 +#define rG0 r28 /* endian reversed tweak (XTS mode) */ +#define rG1 r29 +#define rG2 r30 +#define rG3 r31 -- GitLab From 0c5f9aea2e9c1f4a60321127064d03a0331add99 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 09:59:43 +0100 Subject: [PATCH 0114/1910] crypto: powerpc/aes - aes tables 4K AES tables for big endian. To reduce the possiblity of timing attacks, the size has been cut to 8KB + 256 bytes in contrast to 16KB in the generic implementation. That is not perfect but at least a good tradeoff for CPU limited router devices. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-tab-4k.S | 331 +++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 arch/powerpc/crypto/aes-tab-4k.S diff --git a/arch/powerpc/crypto/aes-tab-4k.S b/arch/powerpc/crypto/aes-tab-4k.S new file mode 100644 index 000000000000..701e60240dc3 --- /dev/null +++ b/arch/powerpc/crypto/aes-tab-4k.S @@ -0,0 +1,331 @@ +/* + * 4K AES tables for PPC AES implementation + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +/* + * These big endian AES encryption/decryption tables have been taken from + * crypto/aes_generic.c and are designed to be simply accessed by a combination + * of rlwimi/lwz instructions with a minimum of table registers (usually only + * one required). Thus they are aligned to 4K. The locality of rotated values + * is derived from the reduced offsets that are available in the SPE load + * instructions. E.g. evldw, evlwwsplat, ... + * + * For the safety-conscious it has to be noted that they might be vulnerable + * to cache timing attacks because of their size. Nevertheless in contrast to + * the generic tables they have been reduced from 16KB to 8KB + 256 bytes. + * This is a quite good tradeoff for low power devices (e.g. routers) without + * dedicated encryption hardware where we usually have no multiuser + * environment. + * + */ + +#define R(a, b, c, d) \ + 0x##a##b##c##d, 0x##d##a##b##c, 0x##c##d##a##b, 0x##b##c##d##a + +.data +.align 12 +.globl PPC_AES_4K_ENCTAB +PPC_AES_4K_ENCTAB: +/* encryption table, same as crypto_ft_tab in crypto/aes-generic.c */ + .long R(c6, 63, 63, a5), R(f8, 7c, 7c, 84) + .long R(ee, 77, 77, 99), R(f6, 7b, 7b, 8d) + .long R(ff, f2, f2, 0d), R(d6, 6b, 6b, bd) + .long R(de, 6f, 6f, b1), R(91, c5, c5, 54) + .long R(60, 30, 30, 50), R(02, 01, 01, 03) + .long R(ce, 67, 67, a9), R(56, 2b, 2b, 7d) + .long R(e7, fe, fe, 19), R(b5, d7, d7, 62) + .long R(4d, ab, ab, e6), R(ec, 76, 76, 9a) + .long R(8f, ca, ca, 45), R(1f, 82, 82, 9d) + .long R(89, c9, c9, 40), R(fa, 7d, 7d, 87) + .long R(ef, fa, fa, 15), R(b2, 59, 59, eb) + .long R(8e, 47, 47, c9), R(fb, f0, f0, 0b) + .long R(41, ad, ad, ec), R(b3, d4, d4, 67) + .long R(5f, a2, a2, fd), R(45, af, af, ea) + .long R(23, 9c, 9c, bf), R(53, a4, a4, f7) + .long R(e4, 72, 72, 96), R(9b, c0, c0, 5b) + .long R(75, b7, b7, c2), R(e1, fd, fd, 1c) + .long R(3d, 93, 93, ae), R(4c, 26, 26, 6a) + .long R(6c, 36, 36, 5a), R(7e, 3f, 3f, 41) + .long R(f5, f7, f7, 02), R(83, cc, cc, 4f) + .long R(68, 34, 34, 5c), R(51, a5, a5, f4) + .long R(d1, e5, e5, 34), R(f9, f1, f1, 08) + .long R(e2, 71, 71, 93), R(ab, d8, d8, 73) + .long R(62, 31, 31, 53), R(2a, 15, 15, 3f) + .long R(08, 04, 04, 0c), R(95, c7, c7, 52) + .long R(46, 23, 23, 65), R(9d, c3, c3, 5e) + .long R(30, 18, 18, 28), R(37, 96, 96, a1) + .long R(0a, 05, 05, 0f), R(2f, 9a, 9a, b5) + .long R(0e, 07, 07, 09), R(24, 12, 12, 36) + .long R(1b, 80, 80, 9b), R(df, e2, e2, 3d) + .long R(cd, eb, eb, 26), R(4e, 27, 27, 69) + .long R(7f, b2, b2, cd), R(ea, 75, 75, 9f) + .long R(12, 09, 09, 1b), R(1d, 83, 83, 9e) + .long R(58, 2c, 2c, 74), R(34, 1a, 1a, 2e) + .long R(36, 1b, 1b, 2d), R(dc, 6e, 6e, b2) + .long R(b4, 5a, 5a, ee), R(5b, a0, a0, fb) + .long R(a4, 52, 52, f6), R(76, 3b, 3b, 4d) + .long R(b7, d6, d6, 61), R(7d, b3, b3, ce) + .long R(52, 29, 29, 7b), R(dd, e3, e3, 3e) + .long R(5e, 2f, 2f, 71), R(13, 84, 84, 97) + .long R(a6, 53, 53, f5), R(b9, d1, d1, 68) + .long R(00, 00, 00, 00), R(c1, ed, ed, 2c) + .long R(40, 20, 20, 60), R(e3, fc, fc, 1f) + .long R(79, b1, b1, c8), R(b6, 5b, 5b, ed) + .long R(d4, 6a, 6a, be), R(8d, cb, cb, 46) + .long R(67, be, be, d9), R(72, 39, 39, 4b) + .long R(94, 4a, 4a, de), R(98, 4c, 4c, d4) + .long R(b0, 58, 58, e8), R(85, cf, cf, 4a) + .long R(bb, d0, d0, 6b), R(c5, ef, ef, 2a) + .long R(4f, aa, aa, e5), R(ed, fb, fb, 16) + .long R(86, 43, 43, c5), R(9a, 4d, 4d, d7) + .long R(66, 33, 33, 55), R(11, 85, 85, 94) + .long R(8a, 45, 45, cf), R(e9, f9, f9, 10) + .long R(04, 02, 02, 06), R(fe, 7f, 7f, 81) + .long R(a0, 50, 50, f0), R(78, 3c, 3c, 44) + .long R(25, 9f, 9f, ba), R(4b, a8, a8, e3) + .long R(a2, 51, 51, f3), R(5d, a3, a3, fe) + .long R(80, 40, 40, c0), R(05, 8f, 8f, 8a) + .long R(3f, 92, 92, ad), R(21, 9d, 9d, bc) + .long R(70, 38, 38, 48), R(f1, f5, f5, 04) + .long R(63, bc, bc, df), R(77, b6, b6, c1) + .long R(af, da, da, 75), R(42, 21, 21, 63) + .long R(20, 10, 10, 30), R(e5, ff, ff, 1a) + .long R(fd, f3, f3, 0e), R(bf, d2, d2, 6d) + .long R(81, cd, cd, 4c), R(18, 0c, 0c, 14) + .long R(26, 13, 13, 35), R(c3, ec, ec, 2f) + .long R(be, 5f, 5f, e1), R(35, 97, 97, a2) + .long R(88, 44, 44, cc), R(2e, 17, 17, 39) + .long R(93, c4, c4, 57), R(55, a7, a7, f2) + .long R(fc, 7e, 7e, 82), R(7a, 3d, 3d, 47) + .long R(c8, 64, 64, ac), R(ba, 5d, 5d, e7) + .long R(32, 19, 19, 2b), R(e6, 73, 73, 95) + .long R(c0, 60, 60, a0), R(19, 81, 81, 98) + .long R(9e, 4f, 4f, d1), R(a3, dc, dc, 7f) + .long R(44, 22, 22, 66), R(54, 2a, 2a, 7e) + .long R(3b, 90, 90, ab), R(0b, 88, 88, 83) + .long R(8c, 46, 46, ca), R(c7, ee, ee, 29) + .long R(6b, b8, b8, d3), R(28, 14, 14, 3c) + .long R(a7, de, de, 79), R(bc, 5e, 5e, e2) + .long R(16, 0b, 0b, 1d), R(ad, db, db, 76) + .long R(db, e0, e0, 3b), R(64, 32, 32, 56) + .long R(74, 3a, 3a, 4e), R(14, 0a, 0a, 1e) + .long R(92, 49, 49, db), R(0c, 06, 06, 0a) + .long R(48, 24, 24, 6c), R(b8, 5c, 5c, e4) + .long R(9f, c2, c2, 5d), R(bd, d3, d3, 6e) + .long R(43, ac, ac, ef), R(c4, 62, 62, a6) + .long R(39, 91, 91, a8), R(31, 95, 95, a4) + .long R(d3, e4, e4, 37), R(f2, 79, 79, 8b) + .long R(d5, e7, e7, 32), R(8b, c8, c8, 43) + .long R(6e, 37, 37, 59), R(da, 6d, 6d, b7) + .long R(01, 8d, 8d, 8c), R(b1, d5, d5, 64) + .long R(9c, 4e, 4e, d2), R(49, a9, a9, e0) + .long R(d8, 6c, 6c, b4), R(ac, 56, 56, fa) + .long R(f3, f4, f4, 07), R(cf, ea, ea, 25) + .long R(ca, 65, 65, af), R(f4, 7a, 7a, 8e) + .long R(47, ae, ae, e9), R(10, 08, 08, 18) + .long R(6f, ba, ba, d5), R(f0, 78, 78, 88) + .long R(4a, 25, 25, 6f), R(5c, 2e, 2e, 72) + .long R(38, 1c, 1c, 24), R(57, a6, a6, f1) + .long R(73, b4, b4, c7), R(97, c6, c6, 51) + .long R(cb, e8, e8, 23), R(a1, dd, dd, 7c) + .long R(e8, 74, 74, 9c), R(3e, 1f, 1f, 21) + .long R(96, 4b, 4b, dd), R(61, bd, bd, dc) + .long R(0d, 8b, 8b, 86), R(0f, 8a, 8a, 85) + .long R(e0, 70, 70, 90), R(7c, 3e, 3e, 42) + .long R(71, b5, b5, c4), R(cc, 66, 66, aa) + .long R(90, 48, 48, d8), R(06, 03, 03, 05) + .long R(f7, f6, f6, 01), R(1c, 0e, 0e, 12) + .long R(c2, 61, 61, a3), R(6a, 35, 35, 5f) + .long R(ae, 57, 57, f9), R(69, b9, b9, d0) + .long R(17, 86, 86, 91), R(99, c1, c1, 58) + .long R(3a, 1d, 1d, 27), R(27, 9e, 9e, b9) + .long R(d9, e1, e1, 38), R(eb, f8, f8, 13) + .long R(2b, 98, 98, b3), R(22, 11, 11, 33) + .long R(d2, 69, 69, bb), R(a9, d9, d9, 70) + .long R(07, 8e, 8e, 89), R(33, 94, 94, a7) + .long R(2d, 9b, 9b, b6), R(3c, 1e, 1e, 22) + .long R(15, 87, 87, 92), R(c9, e9, e9, 20) + .long R(87, ce, ce, 49), R(aa, 55, 55, ff) + .long R(50, 28, 28, 78), R(a5, df, df, 7a) + .long R(03, 8c, 8c, 8f), R(59, a1, a1, f8) + .long R(09, 89, 89, 80), R(1a, 0d, 0d, 17) + .long R(65, bf, bf, da), R(d7, e6, e6, 31) + .long R(84, 42, 42, c6), R(d0, 68, 68, b8) + .long R(82, 41, 41, c3), R(29, 99, 99, b0) + .long R(5a, 2d, 2d, 77), R(1e, 0f, 0f, 11) + .long R(7b, b0, b0, cb), R(a8, 54, 54, fc) + .long R(6d, bb, bb, d6), R(2c, 16, 16, 3a) +.globl PPC_AES_4K_DECTAB +PPC_AES_4K_DECTAB: +/* decryption table, same as crypto_it_tab in crypto/aes-generic.c */ + .long R(51, f4, a7, 50), R(7e, 41, 65, 53) + .long R(1a, 17, a4, c3), R(3a, 27, 5e, 96) + .long R(3b, ab, 6b, cb), R(1f, 9d, 45, f1) + .long R(ac, fa, 58, ab), R(4b, e3, 03, 93) + .long R(20, 30, fa, 55), R(ad, 76, 6d, f6) + .long R(88, cc, 76, 91), R(f5, 02, 4c, 25) + .long R(4f, e5, d7, fc), R(c5, 2a, cb, d7) + .long R(26, 35, 44, 80), R(b5, 62, a3, 8f) + .long R(de, b1, 5a, 49), R(25, ba, 1b, 67) + .long R(45, ea, 0e, 98), R(5d, fe, c0, e1) + .long R(c3, 2f, 75, 02), R(81, 4c, f0, 12) + .long R(8d, 46, 97, a3), R(6b, d3, f9, c6) + .long R(03, 8f, 5f, e7), R(15, 92, 9c, 95) + .long R(bf, 6d, 7a, eb), R(95, 52, 59, da) + .long R(d4, be, 83, 2d), R(58, 74, 21, d3) + .long R(49, e0, 69, 29), R(8e, c9, c8, 44) + .long R(75, c2, 89, 6a), R(f4, 8e, 79, 78) + .long R(99, 58, 3e, 6b), R(27, b9, 71, dd) + .long R(be, e1, 4f, b6), R(f0, 88, ad, 17) + .long R(c9, 20, ac, 66), R(7d, ce, 3a, b4) + .long R(63, df, 4a, 18), R(e5, 1a, 31, 82) + .long R(97, 51, 33, 60), R(62, 53, 7f, 45) + .long R(b1, 64, 77, e0), R(bb, 6b, ae, 84) + .long R(fe, 81, a0, 1c), R(f9, 08, 2b, 94) + .long R(70, 48, 68, 58), R(8f, 45, fd, 19) + .long R(94, de, 6c, 87), R(52, 7b, f8, b7) + .long R(ab, 73, d3, 23), R(72, 4b, 02, e2) + .long R(e3, 1f, 8f, 57), R(66, 55, ab, 2a) + .long R(b2, eb, 28, 07), R(2f, b5, c2, 03) + .long R(86, c5, 7b, 9a), R(d3, 37, 08, a5) + .long R(30, 28, 87, f2), R(23, bf, a5, b2) + .long R(02, 03, 6a, ba), R(ed, 16, 82, 5c) + .long R(8a, cf, 1c, 2b), R(a7, 79, b4, 92) + .long R(f3, 07, f2, f0), R(4e, 69, e2, a1) + .long R(65, da, f4, cd), R(06, 05, be, d5) + .long R(d1, 34, 62, 1f), R(c4, a6, fe, 8a) + .long R(34, 2e, 53, 9d), R(a2, f3, 55, a0) + .long R(05, 8a, e1, 32), R(a4, f6, eb, 75) + .long R(0b, 83, ec, 39), R(40, 60, ef, aa) + .long R(5e, 71, 9f, 06), R(bd, 6e, 10, 51) + .long R(3e, 21, 8a, f9), R(96, dd, 06, 3d) + .long R(dd, 3e, 05, ae), R(4d, e6, bd, 46) + .long R(91, 54, 8d, b5), R(71, c4, 5d, 05) + .long R(04, 06, d4, 6f), R(60, 50, 15, ff) + .long R(19, 98, fb, 24), R(d6, bd, e9, 97) + .long R(89, 40, 43, cc), R(67, d9, 9e, 77) + .long R(b0, e8, 42, bd), R(07, 89, 8b, 88) + .long R(e7, 19, 5b, 38), R(79, c8, ee, db) + .long R(a1, 7c, 0a, 47), R(7c, 42, 0f, e9) + .long R(f8, 84, 1e, c9), R(00, 00, 00, 00) + .long R(09, 80, 86, 83), R(32, 2b, ed, 48) + .long R(1e, 11, 70, ac), R(6c, 5a, 72, 4e) + .long R(fd, 0e, ff, fb), R(0f, 85, 38, 56) + .long R(3d, ae, d5, 1e), R(36, 2d, 39, 27) + .long R(0a, 0f, d9, 64), R(68, 5c, a6, 21) + .long R(9b, 5b, 54, d1), R(24, 36, 2e, 3a) + .long R(0c, 0a, 67, b1), R(93, 57, e7, 0f) + .long R(b4, ee, 96, d2), R(1b, 9b, 91, 9e) + .long R(80, c0, c5, 4f), R(61, dc, 20, a2) + .long R(5a, 77, 4b, 69), R(1c, 12, 1a, 16) + .long R(e2, 93, ba, 0a), R(c0, a0, 2a, e5) + .long R(3c, 22, e0, 43), R(12, 1b, 17, 1d) + .long R(0e, 09, 0d, 0b), R(f2, 8b, c7, ad) + .long R(2d, b6, a8, b9), R(14, 1e, a9, c8) + .long R(57, f1, 19, 85), R(af, 75, 07, 4c) + .long R(ee, 99, dd, bb), R(a3, 7f, 60, fd) + .long R(f7, 01, 26, 9f), R(5c, 72, f5, bc) + .long R(44, 66, 3b, c5), R(5b, fb, 7e, 34) + .long R(8b, 43, 29, 76), R(cb, 23, c6, dc) + .long R(b6, ed, fc, 68), R(b8, e4, f1, 63) + .long R(d7, 31, dc, ca), R(42, 63, 85, 10) + .long R(13, 97, 22, 40), R(84, c6, 11, 20) + .long R(85, 4a, 24, 7d), R(d2, bb, 3d, f8) + .long R(ae, f9, 32, 11), R(c7, 29, a1, 6d) + .long R(1d, 9e, 2f, 4b), R(dc, b2, 30, f3) + .long R(0d, 86, 52, ec), R(77, c1, e3, d0) + .long R(2b, b3, 16, 6c), R(a9, 70, b9, 99) + .long R(11, 94, 48, fa), R(47, e9, 64, 22) + .long R(a8, fc, 8c, c4), R(a0, f0, 3f, 1a) + .long R(56, 7d, 2c, d8), R(22, 33, 90, ef) + .long R(87, 49, 4e, c7), R(d9, 38, d1, c1) + .long R(8c, ca, a2, fe), R(98, d4, 0b, 36) + .long R(a6, f5, 81, cf), R(a5, 7a, de, 28) + .long R(da, b7, 8e, 26), R(3f, ad, bf, a4) + .long R(2c, 3a, 9d, e4), R(50, 78, 92, 0d) + .long R(6a, 5f, cc, 9b), R(54, 7e, 46, 62) + .long R(f6, 8d, 13, c2), R(90, d8, b8, e8) + .long R(2e, 39, f7, 5e), R(82, c3, af, f5) + .long R(9f, 5d, 80, be), R(69, d0, 93, 7c) + .long R(6f, d5, 2d, a9), R(cf, 25, 12, b3) + .long R(c8, ac, 99, 3b), R(10, 18, 7d, a7) + .long R(e8, 9c, 63, 6e), R(db, 3b, bb, 7b) + .long R(cd, 26, 78, 09), R(6e, 59, 18, f4) + .long R(ec, 9a, b7, 01), R(83, 4f, 9a, a8) + .long R(e6, 95, 6e, 65), R(aa, ff, e6, 7e) + .long R(21, bc, cf, 08), R(ef, 15, e8, e6) + .long R(ba, e7, 9b, d9), R(4a, 6f, 36, ce) + .long R(ea, 9f, 09, d4), R(29, b0, 7c, d6) + .long R(31, a4, b2, af), R(2a, 3f, 23, 31) + .long R(c6, a5, 94, 30), R(35, a2, 66, c0) + .long R(74, 4e, bc, 37), R(fc, 82, ca, a6) + .long R(e0, 90, d0, b0), R(33, a7, d8, 15) + .long R(f1, 04, 98, 4a), R(41, ec, da, f7) + .long R(7f, cd, 50, 0e), R(17, 91, f6, 2f) + .long R(76, 4d, d6, 8d), R(43, ef, b0, 4d) + .long R(cc, aa, 4d, 54), R(e4, 96, 04, df) + .long R(9e, d1, b5, e3), R(4c, 6a, 88, 1b) + .long R(c1, 2c, 1f, b8), R(46, 65, 51, 7f) + .long R(9d, 5e, ea, 04), R(01, 8c, 35, 5d) + .long R(fa, 87, 74, 73), R(fb, 0b, 41, 2e) + .long R(b3, 67, 1d, 5a), R(92, db, d2, 52) + .long R(e9, 10, 56, 33), R(6d, d6, 47, 13) + .long R(9a, d7, 61, 8c), R(37, a1, 0c, 7a) + .long R(59, f8, 14, 8e), R(eb, 13, 3c, 89) + .long R(ce, a9, 27, ee), R(b7, 61, c9, 35) + .long R(e1, 1c, e5, ed), R(7a, 47, b1, 3c) + .long R(9c, d2, df, 59), R(55, f2, 73, 3f) + .long R(18, 14, ce, 79), R(73, c7, 37, bf) + .long R(53, f7, cd, ea), R(5f, fd, aa, 5b) + .long R(df, 3d, 6f, 14), R(78, 44, db, 86) + .long R(ca, af, f3, 81), R(b9, 68, c4, 3e) + .long R(38, 24, 34, 2c), R(c2, a3, 40, 5f) + .long R(16, 1d, c3, 72), R(bc, e2, 25, 0c) + .long R(28, 3c, 49, 8b), R(ff, 0d, 95, 41) + .long R(39, a8, 01, 71), R(08, 0c, b3, de) + .long R(d8, b4, e4, 9c), R(64, 56, c1, 90) + .long R(7b, cb, 84, 61), R(d5, 32, b6, 70) + .long R(48, 6c, 5c, 74), R(d0, b8, 57, 42) +.globl PPC_AES_4K_DECTAB2 +PPC_AES_4K_DECTAB2: +/* decryption table, same as crypto_il_tab in crypto/aes-generic.c */ + .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 + .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb + .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 + .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb + .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d + .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e + .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 + .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 + .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 + .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 + .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda + .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 + .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a + .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 + .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 + .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b + .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea + .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 + .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 + .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e + .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 + .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b + .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 + .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 + .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 + .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f + .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d + .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef + .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 + .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 + .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 + .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d -- GitLab From 1c201e6420729f0aca9c844bb941ee2dd2b6c3c0 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 09:59:49 +0100 Subject: [PATCH 0115/1910] crypto: powerpc/aes - assembler core The assembler AES encryption and decryption core routines. Implemented & optimized for big endian. Nevertheless they work on little endian too. For most efficient reuse in (higher level) block cipher routines they are implemented as "fast" call modules without any stack handling or register saving. The caller must take care of that part. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-spe-core.S | 351 +++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 arch/powerpc/crypto/aes-spe-core.S diff --git a/arch/powerpc/crypto/aes-spe-core.S b/arch/powerpc/crypto/aes-spe-core.S new file mode 100644 index 000000000000..5dc6bce90a77 --- /dev/null +++ b/arch/powerpc/crypto/aes-spe-core.S @@ -0,0 +1,351 @@ +/* + * Fast AES implementation for SPE instruction set (PPC) + * + * This code makes use of the SPE SIMD instruction set as defined in + * http://cache.freescale.com/files/32bit/doc/ref_manual/SPEPIM.pdf + * Implementation is based on optimization guide notes from + * http://cache.freescale.com/files/32bit/doc/app_note/AN2665.pdf + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include "aes-spe-regs.h" + +#define EAD(in, bpos) \ + rlwimi rT0,in,28-((bpos+3)%4)*8,20,27; + +#define DAD(in, bpos) \ + rlwimi rT1,in,24-((bpos+3)%4)*8,24,31; + +#define LWH(out, off) \ + evlwwsplat out,off(rT0); /* load word high */ + +#define LWL(out, off) \ + lwz out,off(rT0); /* load word low */ + +#define LBZ(out, tab, off) \ + lbz out,off(tab); /* load byte */ + +#define LAH(out, in, bpos, off) \ + EAD(in, bpos) /* calc addr + load word high */ \ + LWH(out, off) + +#define LAL(out, in, bpos, off) \ + EAD(in, bpos) /* calc addr + load word low */ \ + LWL(out, off) + +#define LAE(out, in, bpos) \ + EAD(in, bpos) /* calc addr + load enc byte */ \ + LBZ(out, rT0, 8) + +#define LBE(out) \ + LBZ(out, rT0, 8) /* load enc byte */ + +#define LAD(out, in, bpos) \ + DAD(in, bpos) /* calc addr + load dec byte */ \ + LBZ(out, rT1, 0) + +#define LBD(out) \ + LBZ(out, rT1, 0) + +/* + * ppc_encrypt_block: The central encryption function for a single 16 bytes + * block. It does no stack handling or register saving to support fast calls + * via bl/blr. It expects that caller has pre-xored input data with first + * 4 words of encryption key into rD0-rD3. Pointer/counter registers must + * have also been set up before (rT0, rKP, CTR). Output is stored in rD0-rD3 + * and rW0-rW3 and caller must execute a final xor on the ouput registers. + * All working registers rD0-rD3 & rW0-rW7 are overwritten during processing. + * + */ +_GLOBAL(ppc_encrypt_block) + LAH(rW4, rD1, 2, 4) + LAH(rW6, rD0, 3, 0) + LAH(rW3, rD0, 1, 8) +ppc_encrypt_block_loop: + LAH(rW0, rD3, 0, 12) + LAL(rW0, rD0, 0, 12) + LAH(rW1, rD1, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAL(rW3, rD1, 1, 8) + LAL(rW4, rD2, 2, 4) + LAL(rW6, rD1, 3, 0) + LAH(rW5, rD3, 2, 4) + LAL(rW5, rD0, 2, 4) + LAH(rW7, rD2, 3, 0) + evldw rD1,16(rKP) + EAD(rD3, 3) + evxor rW2,rW2,rW4 + LWL(rW7, 0) + evxor rW2,rW2,rW6 + EAD(rD2, 0) + evxor rD1,rD1,rW2 + LWL(rW1, 12) + evxor rD1,rD1,rW0 + evldw rD3,24(rKP) + evmergehi rD0,rD0,rD1 + EAD(rD1, 2) + evxor rW3,rW3,rW5 + LWH(rW4, 4) + evxor rW3,rW3,rW7 + EAD(rD0, 3) + evxor rD3,rD3,rW3 + LWH(rW6, 0) + evxor rD3,rD3,rW1 + EAD(rD0, 1) + evmergehi rD2,rD2,rD3 + LWH(rW3, 8) + LAH(rW0, rD3, 0, 12) + LAL(rW0, rD0, 0, 12) + LAH(rW1, rD1, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAL(rW3, rD1, 1, 8) + LAL(rW4, rD2, 2, 4) + LAL(rW6, rD1, 3, 0) + LAH(rW5, rD3, 2, 4) + LAL(rW5, rD0, 2, 4) + LAH(rW7, rD2, 3, 0) + evldw rD1,32(rKP) + EAD(rD3, 3) + evxor rW2,rW2,rW4 + LWL(rW7, 0) + evxor rW2,rW2,rW6 + EAD(rD2, 0) + evxor rD1,rD1,rW2 + LWL(rW1, 12) + evxor rD1,rD1,rW0 + evldw rD3,40(rKP) + evmergehi rD0,rD0,rD1 + EAD(rD1, 2) + evxor rW3,rW3,rW5 + LWH(rW4, 4) + evxor rW3,rW3,rW7 + EAD(rD0, 3) + evxor rD3,rD3,rW3 + LWH(rW6, 0) + evxor rD3,rD3,rW1 + EAD(rD0, 1) + evmergehi rD2,rD2,rD3 + LWH(rW3, 8) + addi rKP,rKP,32 + bdnz ppc_encrypt_block_loop + LAH(rW0, rD3, 0, 12) + LAL(rW0, rD0, 0, 12) + LAH(rW1, rD1, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAL(rW3, rD1, 1, 8) + LAL(rW4, rD2, 2, 4) + LAH(rW5, rD3, 2, 4) + LAL(rW6, rD1, 3, 0) + LAL(rW5, rD0, 2, 4) + LAH(rW7, rD2, 3, 0) + evldw rD1,16(rKP) + EAD(rD3, 3) + evxor rW2,rW2,rW4 + LWL(rW7, 0) + evxor rW2,rW2,rW6 + EAD(rD2, 0) + evxor rD1,rD1,rW2 + LWL(rW1, 12) + evxor rD1,rD1,rW0 + evldw rD3,24(rKP) + evmergehi rD0,rD0,rD1 + EAD(rD1, 0) + evxor rW3,rW3,rW5 + LBE(rW2) + evxor rW3,rW3,rW7 + EAD(rD0, 1) + evxor rD3,rD3,rW3 + LBE(rW6) + evxor rD3,rD3,rW1 + EAD(rD0, 0) + evmergehi rD2,rD2,rD3 + LBE(rW1) + LAE(rW0, rD3, 0) + LAE(rW1, rD0, 0) + LAE(rW4, rD2, 1) + LAE(rW5, rD3, 1) + LAE(rW3, rD2, 0) + LAE(rW7, rD1, 1) + rlwimi rW0,rW4,8,16,23 + rlwimi rW1,rW5,8,16,23 + LAE(rW4, rD1, 2) + LAE(rW5, rD2, 2) + rlwimi rW2,rW6,8,16,23 + rlwimi rW3,rW7,8,16,23 + LAE(rW6, rD3, 2) + LAE(rW7, rD0, 2) + rlwimi rW0,rW4,16,8,15 + rlwimi rW1,rW5,16,8,15 + LAE(rW4, rD0, 3) + LAE(rW5, rD1, 3) + rlwimi rW2,rW6,16,8,15 + lwz rD0,32(rKP) + rlwimi rW3,rW7,16,8,15 + lwz rD1,36(rKP) + LAE(rW6, rD2, 3) + LAE(rW7, rD3, 3) + rlwimi rW0,rW4,24,0,7 + lwz rD2,40(rKP) + rlwimi rW1,rW5,24,0,7 + lwz rD3,44(rKP) + rlwimi rW2,rW6,24,0,7 + rlwimi rW3,rW7,24,0,7 + blr + +/* + * ppc_decrypt_block: The central decryption function for a single 16 bytes + * block. It does no stack handling or register saving to support fast calls + * via bl/blr. It expects that caller has pre-xored input data with first + * 4 words of encryption key into rD0-rD3. Pointer/counter registers must + * have also been set up before (rT0, rKP, CTR). Output is stored in rD0-rD3 + * and rW0-rW3 and caller must execute a final xor on the ouput registers. + * All working registers rD0-rD3 & rW0-rW7 are overwritten during processing. + * + */ +_GLOBAL(ppc_decrypt_block) + LAH(rW0, rD1, 0, 12) + LAH(rW6, rD0, 3, 0) + LAH(rW3, rD0, 1, 8) +ppc_decrypt_block_loop: + LAH(rW1, rD3, 0, 12) + LAL(rW0, rD2, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAH(rW4, rD3, 2, 4) + LAL(rW4, rD0, 2, 4) + LAL(rW6, rD1, 3, 0) + LAH(rW5, rD1, 2, 4) + LAH(rW7, rD2, 3, 0) + LAL(rW7, rD3, 3, 0) + LAL(rW3, rD1, 1, 8) + evldw rD1,16(rKP) + EAD(rD0, 0) + evxor rW4,rW4,rW6 + LWL(rW1, 12) + evxor rW0,rW0,rW4 + EAD(rD2, 2) + evxor rW0,rW0,rW2 + LWL(rW5, 4) + evxor rD1,rD1,rW0 + evldw rD3,24(rKP) + evmergehi rD0,rD0,rD1 + EAD(rD1, 0) + evxor rW3,rW3,rW7 + LWH(rW0, 12) + evxor rW3,rW3,rW1 + EAD(rD0, 3) + evxor rD3,rD3,rW3 + LWH(rW6, 0) + evxor rD3,rD3,rW5 + EAD(rD0, 1) + evmergehi rD2,rD2,rD3 + LWH(rW3, 8) + LAH(rW1, rD3, 0, 12) + LAL(rW0, rD2, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAH(rW4, rD3, 2, 4) + LAL(rW4, rD0, 2, 4) + LAL(rW6, rD1, 3, 0) + LAH(rW5, rD1, 2, 4) + LAH(rW7, rD2, 3, 0) + LAL(rW7, rD3, 3, 0) + LAL(rW3, rD1, 1, 8) + evldw rD1,32(rKP) + EAD(rD0, 0) + evxor rW4,rW4,rW6 + LWL(rW1, 12) + evxor rW0,rW0,rW4 + EAD(rD2, 2) + evxor rW0,rW0,rW2 + LWL(rW5, 4) + evxor rD1,rD1,rW0 + evldw rD3,40(rKP) + evmergehi rD0,rD0,rD1 + EAD(rD1, 0) + evxor rW3,rW3,rW7 + LWH(rW0, 12) + evxor rW3,rW3,rW1 + EAD(rD0, 3) + evxor rD3,rD3,rW3 + LWH(rW6, 0) + evxor rD3,rD3,rW5 + EAD(rD0, 1) + evmergehi rD2,rD2,rD3 + LWH(rW3, 8) + addi rKP,rKP,32 + bdnz ppc_decrypt_block_loop + LAH(rW1, rD3, 0, 12) + LAL(rW0, rD2, 0, 12) + LAH(rW2, rD2, 1, 8) + LAL(rW2, rD3, 1, 8) + LAH(rW4, rD3, 2, 4) + LAL(rW4, rD0, 2, 4) + LAL(rW6, rD1, 3, 0) + LAH(rW5, rD1, 2, 4) + LAH(rW7, rD2, 3, 0) + LAL(rW7, rD3, 3, 0) + LAL(rW3, rD1, 1, 8) + evldw rD1,16(rKP) + EAD(rD0, 0) + evxor rW4,rW4,rW6 + LWL(rW1, 12) + evxor rW0,rW0,rW4 + EAD(rD2, 2) + evxor rW0,rW0,rW2 + LWL(rW5, 4) + evxor rD1,rD1,rW0 + evldw rD3,24(rKP) + evmergehi rD0,rD0,rD1 + DAD(rD1, 0) + evxor rW3,rW3,rW7 + LBD(rW0) + evxor rW3,rW3,rW1 + DAD(rD0, 1) + evxor rD3,rD3,rW3 + LBD(rW6) + evxor rD3,rD3,rW5 + DAD(rD0, 0) + evmergehi rD2,rD2,rD3 + LBD(rW3) + LAD(rW2, rD3, 0) + LAD(rW1, rD2, 0) + LAD(rW4, rD2, 1) + LAD(rW5, rD3, 1) + LAD(rW7, rD1, 1) + rlwimi rW0,rW4,8,16,23 + rlwimi rW1,rW5,8,16,23 + LAD(rW4, rD3, 2) + LAD(rW5, rD0, 2) + rlwimi rW2,rW6,8,16,23 + rlwimi rW3,rW7,8,16,23 + LAD(rW6, rD1, 2) + LAD(rW7, rD2, 2) + rlwimi rW0,rW4,16,8,15 + rlwimi rW1,rW5,16,8,15 + LAD(rW4, rD0, 3) + LAD(rW5, rD1, 3) + rlwimi rW2,rW6,16,8,15 + lwz rD0,32(rKP) + rlwimi rW3,rW7,16,8,15 + lwz rD1,36(rKP) + LAD(rW6, rD2, 3) + LAD(rW7, rD3, 3) + rlwimi rW0,rW4,24,0,7 + lwz rD2,40(rKP) + rlwimi rW1,rW5,24,0,7 + lwz rD3,44(rKP) + rlwimi rW2,rW6,24,0,7 + rlwimi rW3,rW7,24,0,7 + blr -- GitLab From f98992af419e3b69696e9c418eda664bd5d7ceb2 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 09:59:54 +0100 Subject: [PATCH 0116/1910] crypto: powerpc/aes - key handling Key generation for big endian core routines. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-spe-keys.S | 283 +++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 arch/powerpc/crypto/aes-spe-keys.S diff --git a/arch/powerpc/crypto/aes-spe-keys.S b/arch/powerpc/crypto/aes-spe-keys.S new file mode 100644 index 000000000000..be8090f3d700 --- /dev/null +++ b/arch/powerpc/crypto/aes-spe-keys.S @@ -0,0 +1,283 @@ +/* + * Key handling functions for PPC AES implementation + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include + +#ifdef __BIG_ENDIAN__ +#define LOAD_KEY(d, s, off) \ + lwz d,off(s); +#else +#define LOAD_KEY(d, s, off) \ + li r0,off; \ + lwbrx d,s,r0; +#endif + +#define INITIALIZE_KEY \ + stwu r1,-32(r1); /* create stack frame */ \ + stw r14,8(r1); /* save registers */ \ + stw r15,12(r1); \ + stw r16,16(r1); + +#define FINALIZE_KEY \ + lwz r14,8(r1); /* restore registers */ \ + lwz r15,12(r1); \ + lwz r16,16(r1); \ + xor r5,r5,r5; /* clear sensitive data */ \ + xor r6,r6,r6; \ + xor r7,r7,r7; \ + xor r8,r8,r8; \ + xor r9,r9,r9; \ + xor r10,r10,r10; \ + xor r11,r11,r11; \ + xor r12,r12,r12; \ + addi r1,r1,32; /* cleanup stack */ + +#define LS_BOX(r, t1, t2) \ + lis t2,PPC_AES_4K_ENCTAB@h; \ + ori t2,t2,PPC_AES_4K_ENCTAB@l; \ + rlwimi t2,r,4,20,27; \ + lbz t1,8(t2); \ + rlwimi r,t1,0,24,31; \ + rlwimi t2,r,28,20,27; \ + lbz t1,8(t2); \ + rlwimi r,t1,8,16,23; \ + rlwimi t2,r,20,20,27; \ + lbz t1,8(t2); \ + rlwimi r,t1,16,8,15; \ + rlwimi t2,r,12,20,27; \ + lbz t1,8(t2); \ + rlwimi r,t1,24,0,7; + +#define GF8_MUL(out, in, t1, t2) \ + lis t1,0x8080; /* multiplication in GF8 */ \ + ori t1,t1,0x8080; \ + and t1,t1,in; \ + srwi t1,t1,7; \ + mulli t1,t1,0x1b; \ + lis t2,0x7f7f; \ + ori t2,t2,0x7f7f; \ + and t2,t2,in; \ + slwi t2,t2,1; \ + xor out,t1,t2; + +/* + * ppc_expand_key_128(u32 *key_enc, const u8 *key) + * + * Expand 128 bit key into 176 bytes encryption key. It consists of + * key itself plus 10 rounds with 16 bytes each + * + */ +_GLOBAL(ppc_expand_key_128) + INITIALIZE_KEY + LOAD_KEY(r5,r4,0) + LOAD_KEY(r6,r4,4) + LOAD_KEY(r7,r4,8) + LOAD_KEY(r8,r4,12) + stw r5,0(r3) /* key[0..3] = input data */ + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + li r16,10 /* 10 expansion rounds */ + lis r0,0x0100 /* RCO(1) */ +ppc_expand_128_loop: + addi r3,r3,16 + mr r14,r8 /* apply LS_BOX to 4th temp */ + rotlwi r14,r14,8 + LS_BOX(r14, r15, r4) + xor r14,r14,r0 + xor r5,r5,r14 /* xor next 4 keys */ + xor r6,r6,r5 + xor r7,r7,r6 + xor r8,r8,r7 + stw r5,0(r3) /* store next 4 keys */ + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + GF8_MUL(r0, r0, r4, r14) /* multiply RCO by 2 in GF */ + subi r16,r16,1 + cmpwi r16,0 + bt eq,ppc_expand_128_end + b ppc_expand_128_loop +ppc_expand_128_end: + FINALIZE_KEY + blr + +/* + * ppc_expand_key_192(u32 *key_enc, const u8 *key) + * + * Expand 192 bit key into 208 bytes encryption key. It consists of key + * itself plus 12 rounds with 16 bytes each + * + */ +_GLOBAL(ppc_expand_key_192) + INITIALIZE_KEY + LOAD_KEY(r5,r4,0) + LOAD_KEY(r6,r4,4) + LOAD_KEY(r7,r4,8) + LOAD_KEY(r8,r4,12) + LOAD_KEY(r9,r4,16) + LOAD_KEY(r10,r4,20) + stw r5,0(r3) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stw r9,16(r3) + stw r10,20(r3) + li r16,8 /* 8 expansion rounds */ + lis r0,0x0100 /* RCO(1) */ +ppc_expand_192_loop: + addi r3,r3,24 + mr r14,r10 /* apply LS_BOX to 6th temp */ + rotlwi r14,r14,8 + LS_BOX(r14, r15, r4) + xor r14,r14,r0 + xor r5,r5,r14 /* xor next 6 keys */ + xor r6,r6,r5 + xor r7,r7,r6 + xor r8,r8,r7 + xor r9,r9,r8 + xor r10,r10,r9 + stw r5,0(r3) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + subi r16,r16,1 + cmpwi r16,0 /* last round early kick out */ + bt eq,ppc_expand_192_end + stw r9,16(r3) + stw r10,20(r3) + GF8_MUL(r0, r0, r4, r14) /* multiply RCO GF8 */ + b ppc_expand_192_loop +ppc_expand_192_end: + FINALIZE_KEY + blr + +/* + * ppc_expand_key_256(u32 *key_enc, const u8 *key) + * + * Expand 256 bit key into 240 bytes encryption key. It consists of key + * itself plus 14 rounds with 16 bytes each + * + */ +_GLOBAL(ppc_expand_key_256) + INITIALIZE_KEY + LOAD_KEY(r5,r4,0) + LOAD_KEY(r6,r4,4) + LOAD_KEY(r7,r4,8) + LOAD_KEY(r8,r4,12) + LOAD_KEY(r9,r4,16) + LOAD_KEY(r10,r4,20) + LOAD_KEY(r11,r4,24) + LOAD_KEY(r12,r4,28) + stw r5,0(r3) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stw r9,16(r3) + stw r10,20(r3) + stw r11,24(r3) + stw r12,28(r3) + li r16,7 /* 7 expansion rounds */ + lis r0,0x0100 /* RCO(1) */ +ppc_expand_256_loop: + addi r3,r3,32 + mr r14,r12 /* apply LS_BOX to 8th temp */ + rotlwi r14,r14,8 + LS_BOX(r14, r15, r4) + xor r14,r14,r0 + xor r5,r5,r14 /* xor 4 keys */ + xor r6,r6,r5 + xor r7,r7,r6 + xor r8,r8,r7 + mr r14,r8 + LS_BOX(r14, r15, r4) /* apply LS_BOX to 4th temp */ + xor r9,r9,r14 /* xor 4 keys */ + xor r10,r10,r9 + xor r11,r11,r10 + xor r12,r12,r11 + stw r5,0(r3) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + subi r16,r16,1 + cmpwi r16,0 /* last round early kick out */ + bt eq,ppc_expand_256_end + stw r9,16(r3) + stw r10,20(r3) + stw r11,24(r3) + stw r12,28(r3) + GF8_MUL(r0, r0, r4, r14) + b ppc_expand_256_loop +ppc_expand_256_end: + FINALIZE_KEY + blr + +/* + * ppc_generate_decrypt_key: derive decryption key from encryption key + * number of bytes to handle are calculated from length of key (16/24/32) + * + */ +_GLOBAL(ppc_generate_decrypt_key) + addi r6,r5,24 + slwi r6,r6,2 + lwzx r7,r4,r6 /* first/last 4 words are same */ + stw r7,0(r3) + lwz r7,0(r4) + stwx r7,r3,r6 + addi r6,r6,4 + lwzx r7,r4,r6 + stw r7,4(r3) + lwz r7,4(r4) + stwx r7,r3,r6 + addi r6,r6,4 + lwzx r7,r4,r6 + stw r7,8(r3) + lwz r7,8(r4) + stwx r7,r3,r6 + addi r6,r6,4 + lwzx r7,r4,r6 + stw r7,12(r3) + lwz r7,12(r4) + stwx r7,r3,r6 + addi r3,r3,16 + add r4,r4,r6 + subi r4,r4,28 + addi r5,r5,20 + srwi r5,r5,2 +ppc_generate_decrypt_block: + li r6,4 + mtctr r6 +ppc_generate_decrypt_word: + lwz r6,0(r4) + GF8_MUL(r7, r6, r0, r7) + GF8_MUL(r8, r7, r0, r8) + GF8_MUL(r9, r8, r0, r9) + xor r10,r9,r6 + xor r11,r7,r8 + xor r11,r11,r9 + xor r12,r7,r10 + rotrwi r12,r12,24 + xor r11,r11,r12 + xor r12,r8,r10 + rotrwi r12,r12,16 + xor r11,r11,r12 + rotrwi r12,r10,8 + xor r11,r11,r12 + stw r11,0(r3) + addi r3,r3,4 + addi r4,r4,4 + bdnz ppc_generate_decrypt_word + subi r4,r4,32 + subi r5,r5,1 + cmpwi r5,0 + bt gt,ppc_generate_decrypt_block + blr -- GitLab From f2e2ad2e1bfae66f087f4a33cd14da6d5ffcb79f Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 10:00:00 +0100 Subject: [PATCH 0117/1910] crypto: powerpc/aes - ECB/CBC/CTR/XTS modes The assembler block cipher module that controls the core AES functions. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes-spe-modes.S | 630 ++++++++++++++++++++++++++++ 1 file changed, 630 insertions(+) create mode 100644 arch/powerpc/crypto/aes-spe-modes.S diff --git a/arch/powerpc/crypto/aes-spe-modes.S b/arch/powerpc/crypto/aes-spe-modes.S new file mode 100644 index 000000000000..ad48032ca8e0 --- /dev/null +++ b/arch/powerpc/crypto/aes-spe-modes.S @@ -0,0 +1,630 @@ +/* + * AES modes (ECB/CBC/CTR/XTS) for PPC AES implementation + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include "aes-spe-regs.h" + +#ifdef __BIG_ENDIAN__ /* Macros for big endian builds */ + +#define LOAD_DATA(reg, off) \ + lwz reg,off(rSP); /* load with offset */ +#define SAVE_DATA(reg, off) \ + stw reg,off(rDP); /* save with offset */ +#define NEXT_BLOCK \ + addi rSP,rSP,16; /* increment pointers per bloc */ \ + addi rDP,rDP,16; +#define LOAD_IV(reg, off) \ + lwz reg,off(rIP); /* IV loading with offset */ +#define SAVE_IV(reg, off) \ + stw reg,off(rIP); /* IV saving with offset */ +#define START_IV /* nothing to reset */ +#define CBC_DEC 16 /* CBC decrement per block */ +#define CTR_DEC 1 /* CTR decrement one byte */ + +#else /* Macros for little endian */ + +#define LOAD_DATA(reg, off) \ + lwbrx reg,0,rSP; /* load reversed */ \ + addi rSP,rSP,4; /* and increment pointer */ +#define SAVE_DATA(reg, off) \ + stwbrx reg,0,rDP; /* save reversed */ \ + addi rDP,rDP,4; /* and increment pointer */ +#define NEXT_BLOCK /* nothing todo */ +#define LOAD_IV(reg, off) \ + lwbrx reg,0,rIP; /* load reversed */ \ + addi rIP,rIP,4; /* and increment pointer */ +#define SAVE_IV(reg, off) \ + stwbrx reg,0,rIP; /* load reversed */ \ + addi rIP,rIP,4; /* and increment pointer */ +#define START_IV \ + subi rIP,rIP,16; /* must reset pointer */ +#define CBC_DEC 32 /* 2 blocks because of incs */ +#define CTR_DEC 17 /* 1 block because of incs */ + +#endif + +#define SAVE_0_REGS +#define LOAD_0_REGS + +#define SAVE_4_REGS \ + stw rI0,96(r1); /* save 32 bit registers */ \ + stw rI1,100(r1); \ + stw rI2,104(r1); \ + stw rI3,108(r1); + +#define LOAD_4_REGS \ + lwz rI0,96(r1); /* restore 32 bit registers */ \ + lwz rI1,100(r1); \ + lwz rI2,104(r1); \ + lwz rI3,108(r1); + +#define SAVE_8_REGS \ + SAVE_4_REGS \ + stw rG0,112(r1); /* save 32 bit registers */ \ + stw rG1,116(r1); \ + stw rG2,120(r1); \ + stw rG3,124(r1); + +#define LOAD_8_REGS \ + LOAD_4_REGS \ + lwz rG0,112(r1); /* restore 32 bit registers */ \ + lwz rG1,116(r1); \ + lwz rG2,120(r1); \ + lwz rG3,124(r1); + +#define INITIALIZE_CRYPT(tab,nr32bitregs) \ + mflr r0; \ + stwu r1,-160(r1); /* create stack frame */ \ + lis rT0,tab@h; /* en-/decryption table pointer */ \ + stw r0,8(r1); /* save link register */ \ + ori rT0,rT0,tab@l; \ + evstdw r14,16(r1); \ + mr rKS,rKP; \ + evstdw r15,24(r1); /* We must save non volatile */ \ + evstdw r16,32(r1); /* registers. Take the chance */ \ + evstdw r17,40(r1); /* and save the SPE part too */ \ + evstdw r18,48(r1); \ + evstdw r19,56(r1); \ + evstdw r20,64(r1); \ + evstdw r21,72(r1); \ + evstdw r22,80(r1); \ + evstdw r23,88(r1); \ + SAVE_##nr32bitregs##_REGS + +#define FINALIZE_CRYPT(nr32bitregs) \ + lwz r0,8(r1); \ + evldw r14,16(r1); /* restore SPE registers */ \ + evldw r15,24(r1); \ + evldw r16,32(r1); \ + evldw r17,40(r1); \ + evldw r18,48(r1); \ + evldw r19,56(r1); \ + evldw r20,64(r1); \ + evldw r21,72(r1); \ + evldw r22,80(r1); \ + evldw r23,88(r1); \ + LOAD_##nr32bitregs##_REGS \ + mtlr r0; /* restore link register */ \ + xor r0,r0,r0; \ + stw r0,16(r1); /* delete sensitive data */ \ + stw r0,24(r1); /* that we might have pushed */ \ + stw r0,32(r1); /* from other context that runs */ \ + stw r0,40(r1); /* the same code */ \ + stw r0,48(r1); \ + stw r0,56(r1); \ + stw r0,64(r1); \ + stw r0,72(r1); \ + stw r0,80(r1); \ + stw r0,88(r1); \ + addi r1,r1,160; /* cleanup stack frame */ + +#define ENDIAN_SWAP(t0, t1, s0, s1) \ + rotrwi t0,s0,8; /* swap endianness for 2 GPRs */ \ + rotrwi t1,s1,8; \ + rlwimi t0,s0,8,8,15; \ + rlwimi t1,s1,8,8,15; \ + rlwimi t0,s0,8,24,31; \ + rlwimi t1,s1,8,24,31; + +#define GF128_MUL(d0, d1, d2, d3, t0) \ + li t0,0x87; /* multiplication in GF128 */ \ + cmpwi d3,-1; \ + iselgt t0,0,t0; \ + rlwimi d3,d2,0,0,0; /* propagate "carry" bits */ \ + rotlwi d3,d3,1; \ + rlwimi d2,d1,0,0,0; \ + rotlwi d2,d2,1; \ + rlwimi d1,d0,0,0,0; \ + slwi d0,d0,1; /* shift left 128 bit */ \ + rotlwi d1,d1,1; \ + xor d0,d0,t0; + +#define START_KEY(d0, d1, d2, d3) \ + lwz rW0,0(rKP); \ + mtctr rRR; \ + lwz rW1,4(rKP); \ + lwz rW2,8(rKP); \ + lwz rW3,12(rKP); \ + xor rD0,d0,rW0; \ + xor rD1,d1,rW1; \ + xor rD2,d2,rW2; \ + xor rD3,d3,rW3; + +/* + * ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc, + * u32 rounds) + * + * called from glue layer to encrypt a single 16 byte block + * round values are AES128 = 4, AES192 = 5, AES256 = 6 + * + */ +_GLOBAL(ppc_encrypt_aes) + INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 0) + LOAD_DATA(rD0, 0) + LOAD_DATA(rD1, 4) + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_encrypt_block + xor rD0,rD0,rW0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rW1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rW2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rW3 + SAVE_DATA(rD3, 12) + FINALIZE_CRYPT(0) + blr + +/* + * ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec, + * u32 rounds) + * + * called from glue layer to decrypt a single 16 byte block + * round values are AES128 = 4, AES192 = 5, AES256 = 6 + * + */ +_GLOBAL(ppc_decrypt_aes) + INITIALIZE_CRYPT(PPC_AES_4K_DECTAB,0) + LOAD_DATA(rD0, 0) + addi rT1,rT0,4096 + LOAD_DATA(rD1, 4) + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_decrypt_block + xor rD0,rD0,rW0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rW1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rW2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rW3 + SAVE_DATA(rD3, 12) + FINALIZE_CRYPT(0) + blr + +/* + * ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc, + * u32 rounds, u32 bytes); + * + * called from glue layer to encrypt multiple blocks via ECB + * Bytes must be larger or equal 16 and only whole blocks are + * processed. round values are AES128 = 4, AES192 = 5 and + * AES256 = 6 + * + */ +_GLOBAL(ppc_encrypt_ecb) + INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 0) +ppc_encrypt_ecb_loop: + LOAD_DATA(rD0, 0) + mr rKP,rKS + LOAD_DATA(rD1, 4) + subi rLN,rLN,16 + LOAD_DATA(rD2, 8) + cmpwi rLN,15 + LOAD_DATA(rD3, 12) + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_encrypt_block + xor rD0,rD0,rW0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rW1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rW2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rW3 + SAVE_DATA(rD3, 12) + NEXT_BLOCK + bt gt,ppc_encrypt_ecb_loop + FINALIZE_CRYPT(0) + blr + +/* + * ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec, + * u32 rounds, u32 bytes); + * + * called from glue layer to decrypt multiple blocks via ECB + * Bytes must be larger or equal 16 and only whole blocks are + * processed. round values are AES128 = 4, AES192 = 5 and + * AES256 = 6 + * + */ +_GLOBAL(ppc_decrypt_ecb) + INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 0) + addi rT1,rT0,4096 +ppc_decrypt_ecb_loop: + LOAD_DATA(rD0, 0) + mr rKP,rKS + LOAD_DATA(rD1, 4) + subi rLN,rLN,16 + LOAD_DATA(rD2, 8) + cmpwi rLN,15 + LOAD_DATA(rD3, 12) + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_decrypt_block + xor rD0,rD0,rW0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rW1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rW2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rW3 + SAVE_DATA(rD3, 12) + NEXT_BLOCK + bt gt,ppc_decrypt_ecb_loop + FINALIZE_CRYPT(0) + blr + +/* + * ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc, + * 32 rounds, u32 bytes, u8 *iv); + * + * called from glue layer to encrypt multiple blocks via CBC + * Bytes must be larger or equal 16 and only whole blocks are + * processed. round values are AES128 = 4, AES192 = 5 and + * AES256 = 6 + * + */ +_GLOBAL(ppc_encrypt_cbc) + INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 4) + LOAD_IV(rI0, 0) + LOAD_IV(rI1, 4) + LOAD_IV(rI2, 8) + LOAD_IV(rI3, 12) +ppc_encrypt_cbc_loop: + LOAD_DATA(rD0, 0) + mr rKP,rKS + LOAD_DATA(rD1, 4) + subi rLN,rLN,16 + LOAD_DATA(rD2, 8) + cmpwi rLN,15 + LOAD_DATA(rD3, 12) + xor rD0,rD0,rI0 + xor rD1,rD1,rI1 + xor rD2,rD2,rI2 + xor rD3,rD3,rI3 + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_encrypt_block + xor rI0,rD0,rW0 + SAVE_DATA(rI0, 0) + xor rI1,rD1,rW1 + SAVE_DATA(rI1, 4) + xor rI2,rD2,rW2 + SAVE_DATA(rI2, 8) + xor rI3,rD3,rW3 + SAVE_DATA(rI3, 12) + NEXT_BLOCK + bt gt,ppc_encrypt_cbc_loop + START_IV + SAVE_IV(rI0, 0) + SAVE_IV(rI1, 4) + SAVE_IV(rI2, 8) + SAVE_IV(rI3, 12) + FINALIZE_CRYPT(4) + blr + +/* + * ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec, + * u32 rounds, u32 bytes, u8 *iv); + * + * called from glue layer to decrypt multiple blocks via CBC + * round values are AES128 = 4, AES192 = 5, AES256 = 6 + * + */ +_GLOBAL(ppc_decrypt_cbc) + INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 4) + li rT1,15 + LOAD_IV(rI0, 0) + andc rLN,rLN,rT1 + LOAD_IV(rI1, 4) + subi rLN,rLN,16 + LOAD_IV(rI2, 8) + add rSP,rSP,rLN /* reverse processing */ + LOAD_IV(rI3, 12) + add rDP,rDP,rLN + LOAD_DATA(rD0, 0) + addi rT1,rT0,4096 + LOAD_DATA(rD1, 4) + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + START_IV + SAVE_IV(rD0, 0) + SAVE_IV(rD1, 4) + SAVE_IV(rD2, 8) + cmpwi rLN,16 + SAVE_IV(rD3, 12) + bt lt,ppc_decrypt_cbc_end +ppc_decrypt_cbc_loop: + mr rKP,rKS + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_decrypt_block + subi rLN,rLN,16 + subi rSP,rSP,CBC_DEC + xor rW0,rD0,rW0 + LOAD_DATA(rD0, 0) + xor rW1,rD1,rW1 + LOAD_DATA(rD1, 4) + xor rW2,rD2,rW2 + LOAD_DATA(rD2, 8) + xor rW3,rD3,rW3 + LOAD_DATA(rD3, 12) + xor rW0,rW0,rD0 + SAVE_DATA(rW0, 0) + xor rW1,rW1,rD1 + SAVE_DATA(rW1, 4) + xor rW2,rW2,rD2 + SAVE_DATA(rW2, 8) + xor rW3,rW3,rD3 + SAVE_DATA(rW3, 12) + cmpwi rLN,15 + subi rDP,rDP,CBC_DEC + bt gt,ppc_decrypt_cbc_loop +ppc_decrypt_cbc_end: + mr rKP,rKS + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_decrypt_block + xor rW0,rW0,rD0 + xor rW1,rW1,rD1 + xor rW2,rW2,rD2 + xor rW3,rW3,rD3 + xor rW0,rW0,rI0 /* decrypt with initial IV */ + SAVE_DATA(rW0, 0) + xor rW1,rW1,rI1 + SAVE_DATA(rW1, 4) + xor rW2,rW2,rI2 + SAVE_DATA(rW2, 8) + xor rW3,rW3,rI3 + SAVE_DATA(rW3, 12) + FINALIZE_CRYPT(4) + blr + +/* + * ppc_crypt_ctr(u8 *out, const u8 *in, u32 *key_enc, + * u32 rounds, u32 bytes, u8 *iv); + * + * called from glue layer to encrypt/decrypt multiple blocks + * via CTR. Number of bytes does not need to be a multiple of + * 16. Round values are AES128 = 4, AES192 = 5, AES256 = 6 + * + */ +_GLOBAL(ppc_crypt_ctr) + INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 4) + LOAD_IV(rI0, 0) + LOAD_IV(rI1, 4) + LOAD_IV(rI2, 8) + cmpwi rLN,16 + LOAD_IV(rI3, 12) + START_IV + bt lt,ppc_crypt_ctr_partial +ppc_crypt_ctr_loop: + mr rKP,rKS + START_KEY(rI0, rI1, rI2, rI3) + bl ppc_encrypt_block + xor rW0,rD0,rW0 + xor rW1,rD1,rW1 + xor rW2,rD2,rW2 + xor rW3,rD3,rW3 + LOAD_DATA(rD0, 0) + subi rLN,rLN,16 + LOAD_DATA(rD1, 4) + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + xor rD0,rD0,rW0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rW1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rW2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rW3 + SAVE_DATA(rD3, 12) + addic rI3,rI3,1 /* increase counter */ + addze rI2,rI2 + addze rI1,rI1 + addze rI0,rI0 + NEXT_BLOCK + cmpwi rLN,15 + bt gt,ppc_crypt_ctr_loop +ppc_crypt_ctr_partial: + cmpwi rLN,0 + bt eq,ppc_crypt_ctr_end + mr rKP,rKS + START_KEY(rI0, rI1, rI2, rI3) + bl ppc_encrypt_block + xor rW0,rD0,rW0 + SAVE_IV(rW0, 0) + xor rW1,rD1,rW1 + SAVE_IV(rW1, 4) + xor rW2,rD2,rW2 + SAVE_IV(rW2, 8) + xor rW3,rD3,rW3 + SAVE_IV(rW3, 12) + mtctr rLN + subi rIP,rIP,CTR_DEC + subi rSP,rSP,1 + subi rDP,rDP,1 +ppc_crypt_ctr_xorbyte: + lbzu rW4,1(rIP) /* bytewise xor for partial block */ + lbzu rW5,1(rSP) + xor rW4,rW4,rW5 + stbu rW4,1(rDP) + bdnz ppc_crypt_ctr_xorbyte + subf rIP,rLN,rIP + addi rIP,rIP,1 + addic rI3,rI3,1 + addze rI2,rI2 + addze rI1,rI1 + addze rI0,rI0 +ppc_crypt_ctr_end: + SAVE_IV(rI0, 0) + SAVE_IV(rI1, 4) + SAVE_IV(rI2, 8) + SAVE_IV(rI3, 12) + FINALIZE_CRYPT(4) + blr + +/* + * ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc, + * u32 rounds, u32 bytes, u8 *iv, u32 *key_twk); + * + * called from glue layer to encrypt multiple blocks via XTS + * If key_twk is given, the initial IV encryption will be + * processed too. Round values are AES128 = 4, AES192 = 5, + * AES256 = 6 + * + */ +_GLOBAL(ppc_encrypt_xts) + INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 8) + LOAD_IV(rI0, 0) + LOAD_IV(rI1, 4) + LOAD_IV(rI2, 8) + cmpwi rKT,0 + LOAD_IV(rI3, 12) + bt eq,ppc_encrypt_xts_notweak + mr rKP,rKT + START_KEY(rI0, rI1, rI2, rI3) + bl ppc_encrypt_block + xor rI0,rD0,rW0 + xor rI1,rD1,rW1 + xor rI2,rD2,rW2 + xor rI3,rD3,rW3 +ppc_encrypt_xts_notweak: + ENDIAN_SWAP(rG0, rG1, rI0, rI1) + ENDIAN_SWAP(rG2, rG3, rI2, rI3) +ppc_encrypt_xts_loop: + LOAD_DATA(rD0, 0) + mr rKP,rKS + LOAD_DATA(rD1, 4) + subi rLN,rLN,16 + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + xor rD0,rD0,rI0 + xor rD1,rD1,rI1 + xor rD2,rD2,rI2 + xor rD3,rD3,rI3 + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_encrypt_block + xor rD0,rD0,rW0 + xor rD1,rD1,rW1 + xor rD2,rD2,rW2 + xor rD3,rD3,rW3 + xor rD0,rD0,rI0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rI1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rI2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rI3 + SAVE_DATA(rD3, 12) + GF128_MUL(rG0, rG1, rG2, rG3, rW0) + ENDIAN_SWAP(rI0, rI1, rG0, rG1) + ENDIAN_SWAP(rI2, rI3, rG2, rG3) + cmpwi rLN,0 + NEXT_BLOCK + bt gt,ppc_encrypt_xts_loop + START_IV + SAVE_IV(rI0, 0) + SAVE_IV(rI1, 4) + SAVE_IV(rI2, 8) + SAVE_IV(rI3, 12) + FINALIZE_CRYPT(8) + blr + +/* + * ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec, + * u32 rounds, u32 blocks, u8 *iv, u32 *key_twk); + * + * called from glue layer to decrypt multiple blocks via XTS + * If key_twk is given, the initial IV encryption will be + * processed too. Round values are AES128 = 4, AES192 = 5, + * AES256 = 6 + * + */ +_GLOBAL(ppc_decrypt_xts) + INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 8) + LOAD_IV(rI0, 0) + addi rT1,rT0,4096 + LOAD_IV(rI1, 4) + LOAD_IV(rI2, 8) + cmpwi rKT,0 + LOAD_IV(rI3, 12) + bt eq,ppc_decrypt_xts_notweak + subi rT0,rT0,4096 + mr rKP,rKT + START_KEY(rI0, rI1, rI2, rI3) + bl ppc_encrypt_block + xor rI0,rD0,rW0 + xor rI1,rD1,rW1 + xor rI2,rD2,rW2 + xor rI3,rD3,rW3 + addi rT0,rT0,4096 +ppc_decrypt_xts_notweak: + ENDIAN_SWAP(rG0, rG1, rI0, rI1) + ENDIAN_SWAP(rG2, rG3, rI2, rI3) +ppc_decrypt_xts_loop: + LOAD_DATA(rD0, 0) + mr rKP,rKS + LOAD_DATA(rD1, 4) + subi rLN,rLN,16 + LOAD_DATA(rD2, 8) + LOAD_DATA(rD3, 12) + xor rD0,rD0,rI0 + xor rD1,rD1,rI1 + xor rD2,rD2,rI2 + xor rD3,rD3,rI3 + START_KEY(rD0, rD1, rD2, rD3) + bl ppc_decrypt_block + xor rD0,rD0,rW0 + xor rD1,rD1,rW1 + xor rD2,rD2,rW2 + xor rD3,rD3,rW3 + xor rD0,rD0,rI0 + SAVE_DATA(rD0, 0) + xor rD1,rD1,rI1 + SAVE_DATA(rD1, 4) + xor rD2,rD2,rI2 + SAVE_DATA(rD2, 8) + xor rD3,rD3,rI3 + SAVE_DATA(rD3, 12) + GF128_MUL(rG0, rG1, rG2, rG3, rW0) + ENDIAN_SWAP(rI0, rI1, rG0, rG1) + ENDIAN_SWAP(rI2, rI3, rG2, rG3) + cmpwi rLN,0 + NEXT_BLOCK + bt gt,ppc_decrypt_xts_loop + START_IV + SAVE_IV(rI0, 0) + SAVE_IV(rI1, 4) + SAVE_IV(rI2, 8) + SAVE_IV(rI3, 12) + FINALIZE_CRYPT(8) + blr -- GitLab From 8a28a1a89409289d9552757b95f85b50ffc26ac7 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 10:00:05 +0100 Subject: [PATCH 0118/1910] cyprot: powerpc/aes - glue code Integrate the assembler modules into the kernel crypto framework. Take care to avoid long intervals of disabled preemption. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/aes_spe_glue.c | 512 +++++++++++++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 arch/powerpc/crypto/aes_spe_glue.c diff --git a/arch/powerpc/crypto/aes_spe_glue.c b/arch/powerpc/crypto/aes_spe_glue.c new file mode 100644 index 000000000000..bd5e63f72ad4 --- /dev/null +++ b/arch/powerpc/crypto/aes_spe_glue.c @@ -0,0 +1,512 @@ +/* + * Glue code for AES implementation for SPE instructions (PPC) + * + * Based on generic implementation. The assembler module takes care + * about the SPE registers so it can run from interrupt context. + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MAX_BYTES defines the number of bytes that are allowed to be processed + * between preempt_disable() and preempt_enable(). e500 cores can issue two + * instructions per clock cycle using one 32/64 bit unit (SU1) and one 32 + * bit unit (SU2). One of these can be a memory access that is executed via + * a single load and store unit (LSU). XTS-AES-256 takes ~780 operations per + * 16 byte block block or 25 cycles per byte. Thus 768 bytes of input data + * will need an estimated maximum of 20,000 cycles. Headroom for cache misses + * included. Even with the low end model clocked at 667 MHz this equals to a + * critical time window of less than 30us. The value has been choosen to + * process a 512 byte disk block in one or a large 1400 bytes IPsec network + * packet in two runs. + * + */ +#define MAX_BYTES 768 + +struct ppc_aes_ctx { + u32 key_enc[AES_MAX_KEYLENGTH_U32]; + u32 key_dec[AES_MAX_KEYLENGTH_U32]; + u32 rounds; +}; + +struct ppc_xts_ctx { + u32 key_enc[AES_MAX_KEYLENGTH_U32]; + u32 key_dec[AES_MAX_KEYLENGTH_U32]; + u32 key_twk[AES_MAX_KEYLENGTH_U32]; + u32 rounds; +}; + +extern void ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc, u32 rounds); +extern void ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec, u32 rounds); +extern void ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, + u32 bytes); +extern void ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, + u32 bytes); +extern void ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, + u32 bytes, u8 *iv); +extern void ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, + u32 bytes, u8 *iv); +extern void ppc_crypt_ctr (u8 *out, const u8 *in, u32 *key_enc, u32 rounds, + u32 bytes, u8 *iv); +extern void ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, + u32 bytes, u8 *iv, u32 *key_twk); +extern void ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, + u32 bytes, u8 *iv, u32 *key_twk); + +extern void ppc_expand_key_128(u32 *key_enc, const u8 *key); +extern void ppc_expand_key_192(u32 *key_enc, const u8 *key); +extern void ppc_expand_key_256(u32 *key_enc, const u8 *key); + +extern void ppc_generate_decrypt_key(u32 *key_dec,u32 *key_enc, + unsigned int key_len); + +static void spe_begin(void) +{ + /* disable preemption and save users SPE registers if required */ + preempt_disable(); + enable_kernel_spe(); +} + +static void spe_end(void) +{ + /* reenable preemption */ + preempt_enable(); +} + +static int ppc_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + switch (key_len) { + case AES_KEYSIZE_128: + ctx->rounds = 4; + ppc_expand_key_128(ctx->key_enc, in_key); + break; + case AES_KEYSIZE_192: + ctx->rounds = 5; + ppc_expand_key_192(ctx->key_enc, in_key); + break; + case AES_KEYSIZE_256: + ctx->rounds = 6; + ppc_expand_key_256(ctx->key_enc, in_key); + break; + } + + ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); + + return 0; +} + +static int ppc_xts_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct ppc_xts_ctx *ctx = crypto_tfm_ctx(tfm); + + key_len >>= 1; + + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + switch (key_len) { + case AES_KEYSIZE_128: + ctx->rounds = 4; + ppc_expand_key_128(ctx->key_enc, in_key); + ppc_expand_key_128(ctx->key_twk, in_key + AES_KEYSIZE_128); + break; + case AES_KEYSIZE_192: + ctx->rounds = 5; + ppc_expand_key_192(ctx->key_enc, in_key); + ppc_expand_key_192(ctx->key_twk, in_key + AES_KEYSIZE_192); + break; + case AES_KEYSIZE_256: + ctx->rounds = 6; + ppc_expand_key_256(ctx->key_enc, in_key); + ppc_expand_key_256(ctx->key_twk, in_key + AES_KEYSIZE_256); + break; + } + + ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); + + return 0; +} + +static void ppc_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + spe_begin(); + ppc_encrypt_aes(out, in, ctx->key_enc, ctx->rounds); + spe_end(); +} + +static void ppc_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + spe_begin(); + ppc_decrypt_aes(out, in, ctx->key_dec, ctx->rounds); + spe_end(); +} + +static int ppc_ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_encrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, ctx->rounds, nbytes); + spe_end(); + + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_decrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, ctx->rounds, nbytes); + spe_end(); + + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_encrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, ctx->rounds, nbytes, walk.iv); + spe_end(); + + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_decrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, ctx->rounds, nbytes, walk.iv); + spe_end(); + + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int pbytes, ubytes; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); + + while ((pbytes = walk.nbytes)) { + pbytes = pbytes > MAX_BYTES ? MAX_BYTES : pbytes; + pbytes = pbytes == nbytes ? + nbytes : pbytes & ~(AES_BLOCK_SIZE - 1); + ubytes = walk.nbytes - pbytes; + + spe_begin(); + ppc_crypt_ctr(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, ctx->rounds, pbytes , walk.iv); + spe_end(); + + nbytes -= pbytes; + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + u32 *twk; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + twk = ctx->key_twk; + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_encrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_enc, ctx->rounds, nbytes, walk.iv, twk); + spe_end(); + + twk = NULL; + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +static int ppc_xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct ppc_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int ubytes; + int err; + u32 *twk; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + twk = ctx->key_twk; + + while ((nbytes = walk.nbytes)) { + ubytes = nbytes > MAX_BYTES ? + nbytes - MAX_BYTES : nbytes & (AES_BLOCK_SIZE - 1); + nbytes -= ubytes; + + spe_begin(); + ppc_decrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, + ctx->key_dec, ctx->rounds, nbytes, walk.iv, twk); + spe_end(); + + twk = NULL; + err = blkcipher_walk_done(desc, &walk, ubytes); + } + + return err; +} + +/* + * Algorithm definitions. Disabling alignment (cra_alignmask=0) was chosen + * because the e500 platform can handle unaligned reads/writes very efficently. + * This improves IPsec thoughput by another few percent. Additionally we assume + * that AES context is always aligned to at least 8 bytes because it is created + * with kmalloc() in the crypto infrastructure + * + */ +static struct crypto_alg aes_algs[] = { { + .cra_name = "aes", + .cra_driver_name = "aes-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ppc_aes_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = ppc_aes_setkey, + .cia_encrypt = ppc_aes_encrypt, + .cia_decrypt = ppc_aes_decrypt + } + } +}, { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ppc_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ppc_aes_setkey, + .encrypt = ppc_ecb_encrypt, + .decrypt = ppc_ecb_decrypt, + } + } +}, { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ppc_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ppc_aes_setkey, + .encrypt = ppc_cbc_encrypt, + .decrypt = ppc_cbc_decrypt, + } + } +}, { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct ppc_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ppc_aes_setkey, + .encrypt = ppc_ctr_crypt, + .decrypt = ppc_ctr_crypt, + } + } +}, { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ppc_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE * 2, + .max_keysize = AES_MAX_KEY_SIZE * 2, + .ivsize = AES_BLOCK_SIZE, + .setkey = ppc_xts_setkey, + .encrypt = ppc_xts_encrypt, + .decrypt = ppc_xts_decrypt, + } + } +} }; + +static int __init ppc_aes_mod_init(void) +{ + return crypto_register_algs(aes_algs, ARRAY_SIZE(aes_algs)); +} + +static void __exit ppc_aes_mod_fini(void) +{ + crypto_unregister_algs(aes_algs, ARRAY_SIZE(aes_algs)); +} + +module_init(ppc_aes_mod_init); +module_exit(ppc_aes_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS, SPE optimized"); + +MODULE_ALIAS_CRYPTO("aes"); +MODULE_ALIAS_CRYPTO("ecb(aes)"); +MODULE_ALIAS_CRYPTO("cbc(aes)"); +MODULE_ALIAS_CRYPTO("ctr(aes)"); +MODULE_ALIAS_CRYPTO("xts(aes)"); +MODULE_ALIAS_CRYPTO("aes-ppc-spe"); -- GitLab From 504c6143c53dfd140d42fe76d0faed1309c6d1b6 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 22 Feb 2015 10:00:10 +0100 Subject: [PATCH 0119/1910] crypto: powerpc/aes - kernel config Integrate the module into the kernel configuration Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Makefile | 2 ++ crypto/Kconfig | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index a07e763befb5..1698fb94b1ae 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -4,8 +4,10 @@ # Arch-specific CryptoAPI modules. # +obj-$(CONFIG_CRYPTO_AES_PPC_SPE) += aes-ppc-spe.o obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o obj-$(CONFIG_CRYPTO_SHA256_PPC_SPE) += sha256-ppc-spe.o +aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes_spe_glue.o sha1-powerpc-y := sha1-powerpc-asm.o sha1.o sha256-ppc-spe-y := sha256-spe-asm.o sha256_spe_glue.o diff --git a/crypto/Kconfig b/crypto/Kconfig index 2ca8d15e0b6f..14106b267c6f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -866,6 +866,19 @@ config CRYPTO_AES_ARM_BS This implementation does not rely on any lookup tables so it is believed to be invulnerable to cache timing attacks. +config CRYPTO_AES_PPC_SPE + tristate "AES cipher algorithms (PPC SPE)" + depends on PPC && SPE + help + AES cipher algorithms (FIPS-197). Additionally the acceleration + for popular block cipher modes ECB, CBC, CTR and XTS is supported. + This module should only be used for low power (router) devices + without hardware AES acceleration (e.g. caam crypto). It reduces the + size of the AES tables from 16KB to 8KB + 256 bytes and mitigates + timining attacks. Nevertheless it might be not as secure as other + architecture specific assembler implementations that work on 1KB + tables or 256 bytes S-boxes. + config CRYPTO_ANUBIS tristate "Anubis cipher algorithm" select CRYPTO_ALGAPI -- GitLab From 20f1b1f1f3bd594e05941fe9c7f50faab43ddbbf Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Tue, 24 Feb 2015 20:36:40 +0100 Subject: [PATCH 0120/1910] crypto: powerpc/sha1 - assembler This is the assembler code for SHA1 implementation with the SIMD SPE instruction set. With the enhanced instruction set we can operate on 2 32 bit words in parallel. That helps reducing the time to calculate W16-W79. For increasing performance even more the assembler function can compute hashes for more than one 64 byte input block. The state of the used SPE registers is preserved via the stack so we can run from interrupt context. There might be the case that we interrupt ourselves and push sensitive data from another context onto our stack. Clear this area in the stack afterwards to avoid information leakage. The code is endian independant. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/sha1-spe-asm.S | 299 ++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 arch/powerpc/sha1-spe-asm.S diff --git a/arch/powerpc/sha1-spe-asm.S b/arch/powerpc/sha1-spe-asm.S new file mode 100644 index 000000000000..fcb6cf002889 --- /dev/null +++ b/arch/powerpc/sha1-spe-asm.S @@ -0,0 +1,299 @@ +/* + * Fast SHA-1 implementation for SPE instruction set (PPC) + * + * This code makes use of the SPE SIMD instruction set as defined in + * http://cache.freescale.com/files/32bit/doc/ref_manual/SPEPIM.pdf + * Implementation is based on optimization guide notes from + * http://cache.freescale.com/files/32bit/doc/app_note/AN2665.pdf + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include + +#define rHP r3 /* pointer to hash value */ +#define rWP r4 /* pointer to input */ +#define rKP r5 /* pointer to constants */ + +#define rW0 r14 /* 64 bit round words */ +#define rW1 r15 +#define rW2 r16 +#define rW3 r17 +#define rW4 r18 +#define rW5 r19 +#define rW6 r20 +#define rW7 r21 + +#define rH0 r6 /* 32 bit hash values */ +#define rH1 r7 +#define rH2 r8 +#define rH3 r9 +#define rH4 r10 + +#define rT0 r22 /* 64 bit temporary */ +#define rT1 r0 /* 32 bit temporaries */ +#define rT2 r11 +#define rT3 r12 + +#define rK r23 /* 64 bit constant in volatile register */ + +#define LOAD_K01 + +#define LOAD_K11 \ + evlwwsplat rK,0(rKP); + +#define LOAD_K21 \ + evlwwsplat rK,4(rKP); + +#define LOAD_K31 \ + evlwwsplat rK,8(rKP); + +#define LOAD_K41 \ + evlwwsplat rK,12(rKP); + +#define INITIALIZE \ + stwu r1,-128(r1); /* create stack frame */ \ + evstdw r14,8(r1); /* We must save non volatile */ \ + evstdw r15,16(r1); /* registers. Take the chance */ \ + evstdw r16,24(r1); /* and save the SPE part too */ \ + evstdw r17,32(r1); \ + evstdw r18,40(r1); \ + evstdw r19,48(r1); \ + evstdw r20,56(r1); \ + evstdw r21,64(r1); \ + evstdw r22,72(r1); \ + evstdw r23,80(r1); + + +#define FINALIZE \ + evldw r14,8(r1); /* restore SPE registers */ \ + evldw r15,16(r1); \ + evldw r16,24(r1); \ + evldw r17,32(r1); \ + evldw r18,40(r1); \ + evldw r19,48(r1); \ + evldw r20,56(r1); \ + evldw r21,64(r1); \ + evldw r22,72(r1); \ + evldw r23,80(r1); \ + xor r0,r0,r0; \ + stw r0,8(r1); /* Delete sensitive data */ \ + stw r0,16(r1); /* that we might have pushed */ \ + stw r0,24(r1); /* from other context that runs */ \ + stw r0,32(r1); /* the same code. Assume that */ \ + stw r0,40(r1); /* the lower part of the GPRs */ \ + stw r0,48(r1); /* were already overwritten on */ \ + stw r0,56(r1); /* the way down to here */ \ + stw r0,64(r1); \ + stw r0,72(r1); \ + stw r0,80(r1); \ + addi r1,r1,128; /* cleanup stack frame */ + +#ifdef __BIG_ENDIAN__ +#define LOAD_DATA(reg, off) \ + lwz reg,off(rWP); /* load data */ +#define NEXT_BLOCK \ + addi rWP,rWP,64; /* increment per block */ +#else +#define LOAD_DATA(reg, off) \ + lwbrx reg,0,rWP; /* load data */ \ + addi rWP,rWP,4; /* increment per word */ +#define NEXT_BLOCK /* nothing to do */ +#endif + +#define R_00_15(a, b, c, d, e, w0, w1, k, off) \ + LOAD_DATA(w0, off) /* 1: W */ \ + and rT2,b,c; /* 1: F' = B and C */ \ + LOAD_K##k##1 \ + andc rT1,d,b; /* 1: F" = ~B and D */ \ + rotrwi rT0,a,27; /* 1: A' = A rotl 5 */ \ + or rT2,rT2,rT1; /* 1: F = F' or F" */ \ + add e,e,rT0; /* 1: E = E + A' */ \ + rotrwi b,b,2; /* 1: B = B rotl 30 */ \ + add e,e,w0; /* 1: E = E + W */ \ + LOAD_DATA(w1, off+4) /* 2: W */ \ + add e,e,rT2; /* 1: E = E + F */ \ + and rT1,a,b; /* 2: F' = B and C */ \ + add e,e,rK; /* 1: E = E + K */ \ + andc rT2,c,a; /* 2: F" = ~B and D */ \ + add d,d,rK; /* 2: E = E + K */ \ + or rT2,rT2,rT1; /* 2: F = F' or F" */ \ + rotrwi rT0,e,27; /* 2: A' = A rotl 5 */ \ + add d,d,w1; /* 2: E = E + W */ \ + rotrwi a,a,2; /* 2: B = B rotl 30 */ \ + add d,d,rT0; /* 2: E = E + A' */ \ + evmergelo w1,w1,w0; /* mix W[0]/W[1] */ \ + add d,d,rT2 /* 2: E = E + F */ + +#define R_16_19(a, b, c, d, e, w0, w1, w4, w6, w7, k) \ + and rT2,b,c; /* 1: F' = B and C */ \ + evmergelohi rT0,w7,w6; /* W[-3] */ \ + andc rT1,d,b; /* 1: F" = ~B and D */ \ + evxor w0,w0,rT0; /* W = W[-16] xor W[-3] */ \ + or rT1,rT1,rT2; /* 1: F = F' or F" */ \ + evxor w0,w0,w4; /* W = W xor W[-8] */ \ + add e,e,rT1; /* 1: E = E + F */ \ + evxor w0,w0,w1; /* W = W xor W[-14] */ \ + rotrwi rT2,a,27; /* 1: A' = A rotl 5 */ \ + evrlwi w0,w0,1; /* W = W rotl 1 */ \ + add e,e,rT2; /* 1: E = E + A' */ \ + evaddw rT0,w0,rK; /* WK = W + K */ \ + rotrwi b,b,2; /* 1: B = B rotl 30 */ \ + LOAD_K##k##1 \ + evmergehi rT1,rT1,rT0; /* WK1/WK2 */ \ + add e,e,rT0; /* 1: E = E + WK */ \ + add d,d,rT1; /* 2: E = E + WK */ \ + and rT2,a,b; /* 2: F' = B and C */ \ + andc rT1,c,a; /* 2: F" = ~B and D */ \ + rotrwi rT0,e,27; /* 2: A' = A rotl 5 */ \ + or rT1,rT1,rT2; /* 2: F = F' or F" */ \ + add d,d,rT0; /* 2: E = E + A' */ \ + rotrwi a,a,2; /* 2: B = B rotl 30 */ \ + add d,d,rT1 /* 2: E = E + F */ + +#define R_20_39(a, b, c, d, e, w0, w1, w4, w6, w7, k) \ + evmergelohi rT0,w7,w6; /* W[-3] */ \ + xor rT2,b,c; /* 1: F' = B xor C */ \ + evxor w0,w0,rT0; /* W = W[-16] xor W[-3] */ \ + xor rT2,rT2,d; /* 1: F = F' xor D */ \ + evxor w0,w0,w4; /* W = W xor W[-8] */ \ + add e,e,rT2; /* 1: E = E + F */ \ + evxor w0,w0,w1; /* W = W xor W[-14] */ \ + rotrwi rT2,a,27; /* 1: A' = A rotl 5 */ \ + evrlwi w0,w0,1; /* W = W rotl 1 */ \ + add e,e,rT2; /* 1: E = E + A' */ \ + evaddw rT0,w0,rK; /* WK = W + K */ \ + rotrwi b,b,2; /* 1: B = B rotl 30 */ \ + LOAD_K##k##1 \ + evmergehi rT1,rT1,rT0; /* WK1/WK2 */ \ + add e,e,rT0; /* 1: E = E + WK */ \ + xor rT2,a,b; /* 2: F' = B xor C */ \ + add d,d,rT1; /* 2: E = E + WK */ \ + xor rT2,rT2,c; /* 2: F = F' xor D */ \ + rotrwi rT0,e,27; /* 2: A' = A rotl 5 */ \ + add d,d,rT2; /* 2: E = E + F */ \ + rotrwi a,a,2; /* 2: B = B rotl 30 */ \ + add d,d,rT0 /* 2: E = E + A' */ + +#define R_40_59(a, b, c, d, e, w0, w1, w4, w6, w7, k) \ + and rT2,b,c; /* 1: F' = B and C */ \ + evmergelohi rT0,w7,w6; /* W[-3] */ \ + or rT1,b,c; /* 1: F" = B or C */ \ + evxor w0,w0,rT0; /* W = W[-16] xor W[-3] */ \ + and rT1,d,rT1; /* 1: F" = F" and D */ \ + evxor w0,w0,w4; /* W = W xor W[-8] */ \ + or rT2,rT2,rT1; /* 1: F = F' or F" */ \ + evxor w0,w0,w1; /* W = W xor W[-14] */ \ + add e,e,rT2; /* 1: E = E + F */ \ + evrlwi w0,w0,1; /* W = W rotl 1 */ \ + rotrwi rT2,a,27; /* 1: A' = A rotl 5 */ \ + evaddw rT0,w0,rK; /* WK = W + K */ \ + add e,e,rT2; /* 1: E = E + A' */ \ + LOAD_K##k##1 \ + evmergehi rT1,rT1,rT0; /* WK1/WK2 */ \ + rotrwi b,b,2; /* 1: B = B rotl 30 */ \ + add e,e,rT0; /* 1: E = E + WK */ \ + and rT2,a,b; /* 2: F' = B and C */ \ + or rT0,a,b; /* 2: F" = B or C */ \ + add d,d,rT1; /* 2: E = E + WK */ \ + and rT0,c,rT0; /* 2: F" = F" and D */ \ + rotrwi a,a,2; /* 2: B = B rotl 30 */ \ + or rT2,rT2,rT0; /* 2: F = F' or F" */ \ + rotrwi rT0,e,27; /* 2: A' = A rotl 5 */ \ + add d,d,rT2; /* 2: E = E + F */ \ + add d,d,rT0 /* 2: E = E + A' */ + +#define R_60_79(a, b, c, d, e, w0, w1, w4, w6, w7, k) \ + R_20_39(a, b, c, d, e, w0, w1, w4, w6, w7, k) + +_GLOBAL(ppc_spe_sha1_transform) + INITIALIZE + + lwz rH0,0(rHP) + lwz rH1,4(rHP) + mtctr r5 + lwz rH2,8(rHP) + lis rKP,PPC_SPE_SHA1_K@h + lwz rH3,12(rHP) + ori rKP,rKP,PPC_SPE_SHA1_K@l + lwz rH4,16(rHP) + +ppc_spe_sha1_main: + R_00_15(rH0, rH1, rH2, rH3, rH4, rW1, rW0, 1, 0) + R_00_15(rH3, rH4, rH0, rH1, rH2, rW2, rW1, 0, 8) + R_00_15(rH1, rH2, rH3, rH4, rH0, rW3, rW2, 0, 16) + R_00_15(rH4, rH0, rH1, rH2, rH3, rW4, rW3, 0, 24) + R_00_15(rH2, rH3, rH4, rH0, rH1, rW5, rW4, 0, 32) + R_00_15(rH0, rH1, rH2, rH3, rH4, rW6, rW5, 0, 40) + R_00_15(rH3, rH4, rH0, rH1, rH2, rT3, rW6, 0, 48) + R_00_15(rH1, rH2, rH3, rH4, rH0, rT3, rW7, 0, 56) + + R_16_19(rH4, rH0, rH1, rH2, rH3, rW0, rW1, rW4, rW6, rW7, 0) + R_16_19(rH2, rH3, rH4, rH0, rH1, rW1, rW2, rW5, rW7, rW0, 2) + + R_20_39(rH0, rH1, rH2, rH3, rH4, rW2, rW3, rW6, rW0, rW1, 0) + R_20_39(rH3, rH4, rH0, rH1, rH2, rW3, rW4, rW7, rW1, rW2, 0) + R_20_39(rH1, rH2, rH3, rH4, rH0, rW4, rW5, rW0, rW2, rW3, 0) + R_20_39(rH4, rH0, rH1, rH2, rH3, rW5, rW6, rW1, rW3, rW4, 0) + R_20_39(rH2, rH3, rH4, rH0, rH1, rW6, rW7, rW2, rW4, rW5, 0) + R_20_39(rH0, rH1, rH2, rH3, rH4, rW7, rW0, rW3, rW5, rW6, 0) + R_20_39(rH3, rH4, rH0, rH1, rH2, rW0, rW1, rW4, rW6, rW7, 0) + R_20_39(rH1, rH2, rH3, rH4, rH0, rW1, rW2, rW5, rW7, rW0, 0) + R_20_39(rH4, rH0, rH1, rH2, rH3, rW2, rW3, rW6, rW0, rW1, 0) + R_20_39(rH2, rH3, rH4, rH0, rH1, rW3, rW4, rW7, rW1, rW2, 3) + + R_40_59(rH0, rH1, rH2, rH3, rH4, rW4, rW5, rW0, rW2, rW3, 0) + R_40_59(rH3, rH4, rH0, rH1, rH2, rW5, rW6, rW1, rW3, rW4, 0) + R_40_59(rH1, rH2, rH3, rH4, rH0, rW6, rW7, rW2, rW4, rW5, 0) + R_40_59(rH4, rH0, rH1, rH2, rH3, rW7, rW0, rW3, rW5, rW6, 0) + R_40_59(rH2, rH3, rH4, rH0, rH1, rW0, rW1, rW4, rW6, rW7, 0) + R_40_59(rH0, rH1, rH2, rH3, rH4, rW1, rW2, rW5, rW7, rW0, 0) + R_40_59(rH3, rH4, rH0, rH1, rH2, rW2, rW3, rW6, rW0, rW1, 0) + R_40_59(rH1, rH2, rH3, rH4, rH0, rW3, rW4, rW7, rW1, rW2, 0) + R_40_59(rH4, rH0, rH1, rH2, rH3, rW4, rW5, rW0, rW2, rW3, 0) + R_40_59(rH2, rH3, rH4, rH0, rH1, rW5, rW6, rW1, rW3, rW4, 4) + + R_60_79(rH0, rH1, rH2, rH3, rH4, rW6, rW7, rW2, rW4, rW5, 0) + R_60_79(rH3, rH4, rH0, rH1, rH2, rW7, rW0, rW3, rW5, rW6, 0) + R_60_79(rH1, rH2, rH3, rH4, rH0, rW0, rW1, rW4, rW6, rW7, 0) + R_60_79(rH4, rH0, rH1, rH2, rH3, rW1, rW2, rW5, rW7, rW0, 0) + R_60_79(rH2, rH3, rH4, rH0, rH1, rW2, rW3, rW6, rW0, rW1, 0) + R_60_79(rH0, rH1, rH2, rH3, rH4, rW3, rW4, rW7, rW1, rW2, 0) + R_60_79(rH3, rH4, rH0, rH1, rH2, rW4, rW5, rW0, rW2, rW3, 0) + lwz rT3,0(rHP) + R_60_79(rH1, rH2, rH3, rH4, rH0, rW5, rW6, rW1, rW3, rW4, 0) + lwz rW1,4(rHP) + R_60_79(rH4, rH0, rH1, rH2, rH3, rW6, rW7, rW2, rW4, rW5, 0) + lwz rW2,8(rHP) + R_60_79(rH2, rH3, rH4, rH0, rH1, rW7, rW0, rW3, rW5, rW6, 0) + lwz rW3,12(rHP) + NEXT_BLOCK + lwz rW4,16(rHP) + + add rH0,rH0,rT3 + stw rH0,0(rHP) + add rH1,rH1,rW1 + stw rH1,4(rHP) + add rH2,rH2,rW2 + stw rH2,8(rHP) + add rH3,rH3,rW3 + stw rH3,12(rHP) + add rH4,rH4,rW4 + stw rH4,16(rHP) + + bdnz ppc_spe_sha1_main + + FINALIZE + blr + +.data +.align 4 +PPC_SPE_SHA1_K: + .long 0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6 -- GitLab From 50ba29aaa7b03a8a35ceba12c9fcf184148f4aeb Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Tue, 24 Feb 2015 20:36:45 +0100 Subject: [PATCH 0121/1910] crypto: powerpc/sha1 - glue Glue code for crypto infrastructure. Call the assembler code where required. Disable preemption during calculation and enable SPE instructions in the kernel prior to the call. Avoid to disable preemption for too long. Take a little care about small input data. Kick out early for input chunks < 64 bytes and replace memset for context cleanup with simple loop. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/sha1_spe_glue.c | 210 +++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 arch/powerpc/sha1_spe_glue.c diff --git a/arch/powerpc/sha1_spe_glue.c b/arch/powerpc/sha1_spe_glue.c new file mode 100644 index 000000000000..3e1d22212521 --- /dev/null +++ b/arch/powerpc/sha1_spe_glue.c @@ -0,0 +1,210 @@ +/* + * Glue code for SHA-1 implementation for SPE instructions (PPC) + * + * Based on generic implementation. + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MAX_BYTES defines the number of bytes that are allowed to be processed + * between preempt_disable() and preempt_enable(). SHA1 takes ~1000 + * operations per 64 bytes. e500 cores can issue two arithmetic instructions + * per clock cycle using one 32/64 bit unit (SU1) and one 32 bit unit (SU2). + * Thus 2KB of input data will need an estimated maximum of 18,000 cycles. + * Headroom for cache misses included. Even with the low end model clocked + * at 667 MHz this equals to a critical time window of less than 27us. + * + */ +#define MAX_BYTES 2048 + +extern void ppc_spe_sha1_transform(u32 *state, const u8 *src, u32 blocks); + +static void spe_begin(void) +{ + /* We just start SPE operations and will save SPE registers later. */ + preempt_disable(); + enable_kernel_spe(); +} + +static void spe_end(void) +{ + /* reenable preemption */ + preempt_enable(); +} + +static inline void ppc_sha1_clear_context(struct sha1_state *sctx) +{ + int count = sizeof(struct sha1_state) >> 2; + u32 *ptr = (u32 *)sctx; + + /* make sure we can clear the fast way */ + BUILD_BUG_ON(sizeof(struct sha1_state) % 4); + do { *ptr++ = 0; } while (--count); +} + +static int ppc_spe_sha1_init(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA1_H0; + sctx->state[1] = SHA1_H1; + sctx->state[2] = SHA1_H2; + sctx->state[3] = SHA1_H3; + sctx->state[4] = SHA1_H4; + sctx->count = 0; + + return 0; +} + +static int ppc_spe_sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->count & 0x3f; + const unsigned int avail = 64 - offset; + unsigned int bytes; + const u8 *src = data; + + if (avail > len) { + sctx->count += len; + memcpy((char *)sctx->buffer + offset, src, len); + return 0; + } + + sctx->count += len; + + if (offset) { + memcpy((char *)sctx->buffer + offset, src, avail); + + spe_begin(); + ppc_spe_sha1_transform(sctx->state, (const u8 *)sctx->buffer, 1); + spe_end(); + + len -= avail; + src += avail; + } + + while (len > 63) { + bytes = (len > MAX_BYTES) ? MAX_BYTES : len; + bytes = bytes & ~0x3f; + + spe_begin(); + ppc_spe_sha1_transform(sctx->state, src, bytes >> 6); + spe_end(); + + src += bytes; + len -= bytes; + }; + + memcpy((char *)sctx->buffer, src, len); + return 0; +} + +static int ppc_spe_sha1_final(struct shash_desc *desc, u8 *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->count & 0x3f; + char *p = (char *)sctx->buffer + offset; + int padlen; + __be64 *pbits = (__be64 *)(((char *)&sctx->buffer) + 56); + __be32 *dst = (__be32 *)out; + + padlen = 55 - offset; + *p++ = 0x80; + + spe_begin(); + + if (padlen < 0) { + memset(p, 0x00, padlen + sizeof (u64)); + ppc_spe_sha1_transform(sctx->state, sctx->buffer, 1); + p = (char *)sctx->buffer; + padlen = 56; + } + + memset(p, 0, padlen); + *pbits = cpu_to_be64(sctx->count << 3); + ppc_spe_sha1_transform(sctx->state, sctx->buffer, 1); + + spe_end(); + + dst[0] = cpu_to_be32(sctx->state[0]); + dst[1] = cpu_to_be32(sctx->state[1]); + dst[2] = cpu_to_be32(sctx->state[2]); + dst[3] = cpu_to_be32(sctx->state[3]); + dst[4] = cpu_to_be32(sctx->state[4]); + + ppc_sha1_clear_context(sctx); + return 0; +} + +static int ppc_spe_sha1_export(struct shash_desc *desc, void *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int ppc_spe_sha1_import(struct shash_desc *desc, const void *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = ppc_spe_sha1_init, + .update = ppc_spe_sha1_update, + .final = ppc_spe_sha1_final, + .export = ppc_spe_sha1_export, + .import = ppc_spe_sha1_import, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name= "sha1-ppc-spe", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init ppc_spe_sha1_mod_init(void) +{ + return crypto_register_shash(&alg); +} + +static void __exit ppc_spe_sha1_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(ppc_spe_sha1_mod_init); +module_exit(ppc_spe_sha1_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, SPE optimized"); + +MODULE_ALIAS_CRYPTO("sha1"); +MODULE_ALIAS_CRYPTO("sha1-ppc-spe"); -- GitLab From d9850fc529efc0c1b3b938aab6916698dcf31f01 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Tue, 24 Feb 2015 20:36:50 +0100 Subject: [PATCH 0122/1910] crypto: powerpc/sha1 - kernel config Integrate the module into the kernel config tree. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Makefile | 2 ++ crypto/Kconfig | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index 1698fb94b1ae..d400bf9e43c6 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -6,8 +6,10 @@ obj-$(CONFIG_CRYPTO_AES_PPC_SPE) += aes-ppc-spe.o obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o +obj-$(CONFIG_CRYPTO_SHA1_PPC_SPE) += sha1-ppc-spe.o obj-$(CONFIG_CRYPTO_SHA256_PPC_SPE) += sha256-ppc-spe.o aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes_spe_glue.o sha1-powerpc-y := sha1-powerpc-asm.o sha1.o +sha1-ppc-spe-y := sha1-spe-asm.o sha1_spe_glue.o sha256-ppc-spe-y := sha256-spe-asm.o sha256_spe_glue.o diff --git a/crypto/Kconfig b/crypto/Kconfig index 14106b267c6f..67275b7f176d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -582,6 +582,13 @@ config CRYPTO_SHA1_PPC This is the powerpc hardware accelerated implementation of the SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). +config CRYPTO_SHA1_PPC_SPE + tristate "SHA1 digest algorithm (PPC SPE)" + depends on PPC && SPE + help + SHA-1 secure hash standard (DFIPS 180-4) implemented + using powerpc SPE SIMD instruction set. + config CRYPTO_SHA1_MB tristate "SHA1 digest algorithm (x86_64 Multi-Buffer, Experimental)" depends on X86 && 64BIT -- GitLab From 223c055aa0eb7e606eb7132e339ce66bb8d7be0d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 18 Dec 2014 11:32:52 +0800 Subject: [PATCH 0123/1910] ASoC: rt5670: set platform data by dmi This patch set specific data according to dmi data. Signed-off-by: Jin, Yao Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8a0833de1665..cd47ef1f5561 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -2549,6 +2550,17 @@ static struct acpi_device_id rt5670_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); #endif +static const struct dmi_system_id dmi_platform_intel_braswell[] = { + { + .ident = "Intel Braswell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), + }, + }, + {} +}; + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2568,6 +2580,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (pdata) rt5670->pdata = *pdata; + if (dmi_check_system(dmi_platform_intel_braswell)) { + rt5670->pdata.dmic_en = true; + rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.jd_mode = 1; + } + rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); if (IS_ERR(rt5670->regmap)) { ret = PTR_ERR(rt5670->regmap); -- GitLab From 64e89e5f55484d289c8b326521e5a12291e2283e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 15 Dec 2014 15:42:33 +0800 Subject: [PATCH 0124/1910] ASoC: rt5670: Add runtime PM support This patch adds runtime PM support on rt5670 codec. Signed-off-by: Lin Mengdong Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index cd47ef1f5561..78d85de8af6f 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -2734,18 +2735,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } + pm_runtime_enable(&i2c->dev); + pm_request_idle(&i2c->dev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670, rt5670_dai, ARRAY_SIZE(rt5670_dai)); if (ret < 0) goto err; + pm_runtime_put(&i2c->dev); + return 0; err: + pm_runtime_disable(&i2c->dev); + return ret; } static int rt5670_i2c_remove(struct i2c_client *i2c) { + pm_runtime_disable(&i2c->dev); snd_soc_unregister_codec(&i2c->dev); return 0; -- GitLab From 77e3ea2801c8ca4700e6b17053b625b8a981ac77 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 15 Dec 2014 15:42:34 +0800 Subject: [PATCH 0125/1910] ASoC: rt5670: Keep sysclk on if JD func is used System clock is necessary for rt5670 JD function. We assume system clock source will be set in machine driver. So there are two things left we should do in codec driver. 1. Set sysclk to codec internal clock in probe since machine driver may not do that before JD function is registered. 2. Power up PLL once sysclk source is switched to PLL. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 78d85de8af6f..0a027bc94399 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2190,6 +2190,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) return 0; + if (rt5670->pdata.jd_mode) { + if (clk_id == RT5670_SCLK_S_PLL1) + snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); + else + snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); + snd_soc_dapm_sync(&codec->dapm); + } switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2628,6 +2635,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } if (rt5670->pdata.jd_mode) { + regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, + RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); + rt5670->sysclk = 0; + rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, RT5670_PWR_MB, RT5670_PWR_MB); regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, -- GitLab From 3aebec3a701e70d6fe2816891e5abea066492779 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 7 Jan 2015 10:19:06 +0800 Subject: [PATCH 0126/1910] ASoC: rt5670: redefine ASRC control registers 0x84 and 0x85 The previous definition of registers 0x84 and 0x85 doesn't match the datasheet. So this patch removes the wrong definition and writes a new one for the two registers. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.h | 65 +++++++++++++++------------------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 84857bdaa78b..82553b1726cd 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1023,50 +1023,33 @@ #define RT5670_DMIC_2_M_NOR (0x0 << 8) #define RT5670_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5670_CLK_SEL_SYS (0x0) +#define RT5670_CLK_SEL_I2S1_ASRC (0x1) +#define RT5670_CLK_SEL_I2S2_ASRC (0x2) +#define RT5670_CLK_SEL_I2S3_ASRC (0x3) +#define RT5670_CLK_SEL_SYS2 (0x5) +#define RT5670_CLK_SEL_SYS3 (0x6) + /* ASRC Control 2 (0x84) */ -#define RT5670_MDA_L_M_MASK (0x1 << 15) -#define RT5670_MDA_L_M_SFT 15 -#define RT5670_MDA_L_M_NOR (0x0 << 15) -#define RT5670_MDA_L_M_ASYN (0x1 << 15) -#define RT5670_MDA_R_M_MASK (0x1 << 14) -#define RT5670_MDA_R_M_SFT 14 -#define RT5670_MDA_R_M_NOR (0x0 << 14) -#define RT5670_MDA_R_M_ASYN (0x1 << 14) -#define RT5670_MAD_L_M_MASK (0x1 << 13) -#define RT5670_MAD_L_M_SFT 13 -#define RT5670_MAD_L_M_NOR (0x0 << 13) -#define RT5670_MAD_L_M_ASYN (0x1 << 13) -#define RT5670_MAD_R_M_MASK (0x1 << 12) -#define RT5670_MAD_R_M_SFT 12 -#define RT5670_MAD_R_M_NOR (0x0 << 12) -#define RT5670_MAD_R_M_ASYN (0x1 << 12) -#define RT5670_ADC_M_MASK (0x1 << 11) -#define RT5670_ADC_M_SFT 11 -#define RT5670_ADC_M_NOR (0x0 << 11) -#define RT5670_ADC_M_ASYN (0x1 << 11) -#define RT5670_STO_DAC_M_MASK (0x1 << 5) -#define RT5670_STO_DAC_M_SFT 5 -#define RT5670_STO_DAC_M_NOR (0x0 << 5) -#define RT5670_STO_DAC_M_ASYN (0x1 << 5) -#define RT5670_I2S1_R_D_MASK (0x1 << 4) -#define RT5670_I2S1_R_D_SFT 4 -#define RT5670_I2S1_R_D_DIS (0x0 << 4) -#define RT5670_I2S1_R_D_EN (0x1 << 4) -#define RT5670_I2S2_R_D_MASK (0x1 << 3) -#define RT5670_I2S2_R_D_SFT 3 -#define RT5670_I2S2_R_D_DIS (0x0 << 3) -#define RT5670_I2S2_R_D_EN (0x1 << 3) -#define RT5670_PRE_SCLK_MASK (0x3) -#define RT5670_PRE_SCLK_SFT 0 -#define RT5670_PRE_SCLK_512 (0x0) -#define RT5670_PRE_SCLK_1024 (0x1) -#define RT5670_PRE_SCLK_2048 (0x2) +#define RT5670_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5670_DA_STO_CLK_SEL_SFT 12 +#define RT5670_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5670_DA_MONOL_CLK_SEL_SFT 8 +#define RT5670_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5670_DA_MONOR_CLK_SEL_SFT 4 +#define RT5670_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5670_I2S1_RATE_MASK (0xf << 12) -#define RT5670_I2S1_RATE_SFT 12 -#define RT5670_I2S2_RATE_MASK (0xf << 8) -#define RT5670_I2S2_RATE_SFT 8 +#define RT5670_UP_CLK_SEL_MASK (0xf << 12) +#define RT5670_UP_CLK_SEL_SFT 12 +#define RT5670_DOWN_CLK_SEL_MASK (0xf << 8) +#define RT5670_DOWN_CLK_SEL_SFT 8 +#define RT5670_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5670_AD_MONOL_CLK_SEL_SFT 4 +#define RT5670_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5670_I2S1_PD_MASK (0x7 << 12) -- GitLab From ea232b3f7233f9242e5a1287377fedb6972dfea4 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 7 Jan 2015 10:19:12 +0800 Subject: [PATCH 0127/1910] ASoC: rt5670: add API to select ASRC clock source When codec is in slave mode, ASRC can suppress noise for asynchronous MCLK and LRCLK or special I2S format. This patch defines an API to select the clock source for specified filters. And the codec driver will turn on ASRC for these filters if ASRC is selected as their clock source. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 83 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5670.h | 15 +++++++ 2 files changed, 98 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0a027bc94399..0632b7458a53 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -590,6 +590,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, return 0; } + +/** + * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0, asrc2_value = 0; + unsigned int asrc3_mask = 0, asrc3_value = 0; + + if (clk_src > RT5670_CLK_SEL_SYS3) + return -EINVAL; + + if (filter_mask & RT5670_DA_STEREO_FILTER) { + asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5670_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_L_FILTER) { + asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_R_FILTER) { + asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_STEREO_FILTER) { + asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_L_FILTER) { + asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_R_FILTER) { + asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_UP_RATE_FILTER) { + asrc3_mask |= RT5670_UP_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK) + | (clk_src << RT5670_UP_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DOWN_RATE_FILTER) { + asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK) + | (clk_src << RT5670_DOWN_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5670_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5670_ASRC_3, + asrc3_mask, asrc3_value); + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 82553b1726cd..0a67adbcfbc3 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1969,6 +1969,21 @@ enum { RT5670_DMIC_DATA_GPIO5, }; +/* filter mask */ +enum { + RT5670_DA_STEREO_FILTER = 0x1, + RT5670_DA_MONO_L_FILTER = (0x1 << 1), + RT5670_DA_MONO_R_FILTER = (0x1 << 2), + RT5670_AD_STEREO_FILTER = (0x1 << 3), + RT5670_AD_MONO_L_FILTER = (0x1 << 4), + RT5670_AD_MONO_R_FILTER = (0x1 << 5), + RT5670_UP_RATE_FILTER = (0x1 << 6), + RT5670_DOWN_RATE_FILTER = (0x1 << 7), +}; + +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; -- GitLab From ab1f70952f61504f60805f13660c8740adcbe14f Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 11 Feb 2015 19:18:51 +0800 Subject: [PATCH 0128/1910] ASoC: rt5677: Add the chip type to distinguish the setting of the clock source There is only one clock source in the rt5676, so the chip type is added to distinguish the setting of the clock source in the VAD function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 28 ++++++++++++++++++++++------ sound/soc/codecs/rt5677.h | 6 ++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 5d0bb8748dd1..ab62777dbd33 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -718,11 +718,24 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) RT5677_LDO1_SEL_MASK, 0x0); regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, RT5677_PWR_LDO1, RT5677_PWR_LDO1); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, - RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); - regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, - RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK, - RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS); + switch (rt5677->type) { + case RT5677: + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, + RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_PLL2_PR_SRC_MASK | + RT5677_DSP_CLK_SRC_MASK, + RT5677_PLL2_PR_SRC_MCLK2 | + RT5677_DSP_CLK_SRC_BYPASS); + break; + case RT5676: + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_DSP_CLK_SRC_MASK, + RT5677_DSP_CLK_SRC_BYPASS); + break; + default: + break; + } regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); rt5677_set_dsp_mode(codec, true); @@ -4733,7 +4746,8 @@ static const struct regmap_config rt5677_regmap = { }; static const struct i2c_device_id rt5677_i2c_id[] = { - { "rt5677", 0 }, + { "rt5677", RT5677 }, + { "rt5676", RT5676 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); @@ -4850,6 +4864,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5677); + rt5677->type = id->driver_data; + if (pdata) rt5677->pdata = *pdata; diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index c0a625f290cc..07df96b43f59 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1665,6 +1665,11 @@ enum { RT5677_IRQ_JD3, }; +enum rt5677_type { + RT5677, + RT5676, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1681,6 +1686,7 @@ struct rt5677_priv { int pll_in; int pll_out; int pow_ldo2; /* POW_LDO2 pin */ + enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif -- GitLab From cbca4076d156c93cedadabb0e463ba0db16bb166 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 25 Feb 2015 17:36:14 +0800 Subject: [PATCH 0129/1910] ASoC: rt5677: Keep the LDO2 powered while used in the suspend mode The patch keeps the ldo2 power while the DSP function of "Voice Wake Up" used in the suspend mode. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ab62777dbd33..5ff7ffaec5cc 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4513,10 +4513,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec) if (!rt5677->dsp_vad_en) { regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - } - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); + if (gpio_is_valid(rt5677->pow_ldo2)) + gpio_set_value_cansleep(rt5677->pow_ldo2, 0); + } return 0; } @@ -4525,12 +4525,12 @@ static int rt5677_resume(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - if (gpio_is_valid(rt5677->pow_ldo2)) { - gpio_set_value_cansleep(rt5677->pow_ldo2, 1); - msleep(10); - } - if (!rt5677->dsp_vad_en) { + if (gpio_is_valid(rt5677->pow_ldo2)) { + gpio_set_value_cansleep(rt5677->pow_ldo2, 1); + msleep(10); + } + regcache_cache_only(rt5677->regmap, false); regcache_sync(rt5677->regmap); } -- GitLab From a0cf43e2f0f391dad7882febbf04423e73e3ff99 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 12 Feb 2015 09:41:55 +0100 Subject: [PATCH 0130/1910] ASoC: tegra: Expose Headphones pin to userspace So userspace can enable or disable it based on the current policy. Signed-off-by: Tomeu Vizoso Acked-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_max98090.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index af3fb997b752..8df71a436f11 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -136,6 +136,7 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { }; static const struct snd_kcontrol_new tegra_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), }; -- GitLab From 3a4562f756617b4b210fc487bfe23853a450d3c1 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 12 Feb 2015 09:41:56 +0100 Subject: [PATCH 0131/1910] ASoC: tegra: Add sink for the internal mic to tegra_max98090 Also adds a control for the pin of the internal mic, so userspace can apply policy when the state of the external mic jack changes. Signed-off-by: Tomeu Vizoso Acked-by: Stephen Warren Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt | 1 + sound/soc/tegra/tegra_max98090.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt index c949abc2992f..c3495beba358 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt @@ -18,6 +18,7 @@ Required properties: * Headphones * Speakers * Mic Jack + * Int Mic - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's connected to the CODEC. diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 8df71a436f11..29ea87cd852e 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -133,11 +133,13 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), }; static const struct snd_kcontrol_new tegra_max98090_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Int Mic"), }; static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) -- GitLab From dd3001490834e10615d9eb229b3e9bbcc0070541 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 12 Feb 2015 09:41:57 +0100 Subject: [PATCH 0132/1910] ASoC: tegra: Add control for the Mic Jack pin So userspace can enable and disable the external microphone. Signed-off-by: Tomeu Vizoso Acked-by: Stephen Warren Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_max98090.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 29ea87cd852e..1f20c2c40a5a 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -139,6 +139,7 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { static const struct snd_kcontrol_new tegra_max98090_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), SOC_DAPM_PIN_SWITCH("Int Mic"), }; -- GitLab From 0cd1b0c3adaac2f9e8b5d2e739bf63a42fbf7ff2 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 21 Jan 2015 13:33:47 -0800 Subject: [PATCH 0133/1910] leds: Let the binding document example for leds-gpio follow the gpio bindings In the gpio bindings documents it is requested to use the marco's in include/dt-bindings/gpio/gpio.h whenever possible. The gpios in the led drivers don't seem to form an exception, so update the example in the document bindings. Signed-off-by: Olliver Schinagl Acked-by: Rob Herring Acked-by: Linus Walleij Signed-off-by: Bryan Wu --- Documentation/devicetree/bindings/leds/leds-gpio.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-gpio.txt b/Documentation/devicetree/bindings/leds/leds-gpio.txt index f77148f372ea..fea1ebfe24a9 100644 --- a/Documentation/devicetree/bindings/leds/leds-gpio.txt +++ b/Documentation/devicetree/bindings/leds/leds-gpio.txt @@ -26,16 +26,18 @@ LED sub-node properties: Examples: +#include + leds { compatible = "gpio-leds"; hdd { label = "IDE Activity"; - gpios = <&mcu_pio 0 1>; /* Active low */ + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; linux,default-trigger = "ide-disk"; }; fault { - gpios = <&mcu_pio 1 0>; + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; /* Keep LED on if BIOS detected hardware fault */ default-state = "keep"; }; @@ -44,11 +46,11 @@ leds { run-control { compatible = "gpio-leds"; red { - gpios = <&mpc8572 6 0>; + gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>; default-state = "off"; }; green { - gpios = <&mpc8572 7 0>; + gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>; default-state = "on"; }; }; @@ -57,7 +59,7 @@ leds { compatible = "gpio-leds"; charger-led { - gpios = <&gpio1 2 0>; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; linux,default-trigger = "max8903-charger-charging"; retain-state-suspended; }; -- GitLab From eb2294c3432fb6366ec12b56a3b2a12cf4242b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 1 Mar 2015 13:25:47 -0800 Subject: [PATCH 0134/1910] leds: lp8860: make use of devm_gpiod_get_optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The probe function open coded a bad variant of devm_gpiod_get_optional using devm_gpiod_get and just ignoring all errors. In contrast to that devm_gpiod_get_optional returns NULL if there was no corresponding gpio specified in the device tree (or ACPI table) and fails if there is an error (or GPIOLIB is not enabled). Moreover since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output which allows some simplification. Signed-off-by: Uwe Kleine-König Signed-off-by: Bryan Wu --- drivers/leds/leds-lp8860.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 840e93f3ab3e..f2a29c256d32 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -391,11 +391,13 @@ static int lp8860_probe(struct i2c_client *client, } } - led->enable_gpio = devm_gpiod_get(&client->dev, "enable"); - if (IS_ERR(led->enable_gpio)) - led->enable_gpio = NULL; - else - gpiod_direction_output(led->enable_gpio, 0); + led->enable_gpio = devm_gpiod_get_optional(&client->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(led->enable_gpio)) { + ret = PTR_ERR(led->enable_gpio); + dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret); + return ret; + } led->regulator = devm_regulator_get(&client->dev, "vled"); if (IS_ERR(led->regulator)) -- GitLab From 1a4ba30cced3002add8459eadcd65b8d3cd1515e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Feb 2015 11:50:11 +0100 Subject: [PATCH 0135/1910] ALSA: hda - Split snd_hda_build_pcms() snd_hda_build_pcms() does actually three things: let the codec driver build up hda_pcm list, set the PCM default values, and call the attach_pcm bus ops for each hda_pcm instance. The former two are basically independent from the bus implementation, so it'd make the code a bit more readable. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 102 ++++++++++++++++++++++---------------- sound/pci/hda/hda_codec.h | 1 + 2 files changed, 60 insertions(+), 43 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index db86b446743c..40300fcc5308 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4569,71 +4569,87 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) return -EAGAIN; } -/* - * attach a new PCM stream - */ -static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) +/* call build_pcms ops of the given codec and set up the default parameters */ +int snd_hda_codec_parse_pcms(struct hda_codec *codec) { - struct hda_bus *bus = codec->bus; - struct hda_pcm_stream *info; - int stream, err; + unsigned int pcm; + int err; - if (snd_BUG_ON(!pcm->name)) - return -EINVAL; - for (stream = 0; stream < 2; stream++) { - info = &pcm->stream[stream]; - if (info->substreams) { + if (codec->num_pcms) + return 0; /* already parsed */ + + if (!codec->patch_ops.build_pcms) + return 0; + + err = codec->patch_ops.build_pcms(codec); + if (err < 0) { + codec_err(codec, "cannot build PCMs for #%d (error %d)\n", + codec->addr, err); + return err; + } + + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + int stream; + + for (stream = 0; stream < 2; stream++) { + struct hda_pcm_stream *info = &cpcm->stream[stream]; + + if (!info->substreams) + continue; + if (snd_BUG_ON(!cpcm->name)) + return -EINVAL; err = set_pcm_default_values(codec, info); - if (err < 0) + if (err < 0) { + codec_warn(codec, + "fail to setup default for PCM %s\n", + cpcm->name); return err; + } } } - return bus->ops.attach_pcm(bus, codec, pcm); + + return 0; } /* assign all PCMs of the given codec */ int snd_hda_codec_build_pcms(struct hda_codec *codec) { + struct hda_bus *bus = codec->bus; unsigned int pcm; - int err; + int dev, err; - if (!codec->num_pcms) { - if (!codec->patch_ops.build_pcms) - return 0; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) { - codec_err(codec, - "cannot build PCMs for #%d (error %d)\n", - codec->addr, err); - err = snd_hda_codec_reset(codec); - if (err < 0) { - codec_err(codec, - "cannot revert codec\n"); - return err; - } - } + if (snd_BUG_ON(!bus->ops.attach_pcm)) + return -EINVAL; + + err = snd_hda_codec_parse_pcms(codec); + if (err < 0) { + snd_hda_codec_reset(codec); + return err; } + + /* attach a new PCM streams */ for (pcm = 0; pcm < codec->num_pcms; pcm++) { struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - int dev; + if (cpcm->pcm) + continue; /* already attached */ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) continue; /* no substreams assigned */ - if (!cpcm->pcm) { - dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); - if (dev < 0) - continue; /* no fatal error */ - cpcm->device = dev; - err = snd_hda_attach_pcm(codec, cpcm); - if (err < 0) { - codec_err(codec, - "cannot attach PCM stream %d for codec #%d\n", - dev, codec->addr); - continue; /* no fatal error */ - } + dev = get_empty_pcm_device(bus, cpcm->pcm_type); + if (dev < 0) + continue; /* no fatal error */ + cpcm->device = dev; + err = bus->ops.attach_pcm(bus, codec, cpcm); + if (err < 0) { + codec_err(codec, + "cannot attach PCM stream %d for codec #%d\n", + dev, codec->addr); + continue; /* no fatal error */ } } + return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 457fc589eb46..8cf70369cd10 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -517,6 +517,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); +int snd_hda_codec_parse_pcms(struct hda_codec *codec); int snd_hda_codec_build_pcms(struct hda_codec *codec); int snd_hda_codec_prepare(struct hda_codec *codec, -- GitLab From 6efdd8513f182492c21fb7238592d4539d5c751a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 16:09:22 +0100 Subject: [PATCH 0136/1910] ALSA: hda - Add card field to hda_codec struct Allow the codec object to have an individual card pointer. Not only this simplifies the redirections in many places, also this will allow us to make each codec assigned to a different card object. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 4 ++-- sound/pci/hda/hda_bind.c | 6 +++--- sound/pci/hda/hda_codec.c | 30 +++++++++++++++--------------- sound/pci/hda/hda_codec.h | 5 +++-- sound/pci/hda/hda_controller.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_jack.c | 8 ++++---- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_trace.h | 4 ++-- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_hdmi.c | 6 +++--- sound/pci/hda/patch_via.c | 8 ++++---- 13 files changed, 41 insertions(+), 40 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e98438e95e79..581b7fdef0e3 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -160,7 +160,7 @@ static int snd_hda_do_attach(struct hda_beep *beep) input_dev->name = "HDA Digital PCBeep"; input_dev->phys = beep->phys; input_dev->id.bustype = BUS_PCI; - input_dev->dev.parent = &codec->bus->card->card_dev; + input_dev->dev.parent = &codec->card->card_dev; input_dev->id.vendor = codec->vendor_id >> 16; input_dev->id.product = codec->vendor_id & 0xffff; @@ -224,7 +224,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) if (beep == NULL) return -ENOMEM; snprintf(beep->phys, sizeof(beep->phys), - "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); + "card%d/codec#%d/beep0", codec->card->number, codec->addr); /* enable linear scale */ snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0x01); diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index ce2dd7b0dc07..2d00417494e2 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -287,9 +287,9 @@ int snd_hda_codec_configure(struct hda_codec *codec) } /* audio codec should override the mixer name */ - if (codec->afg || !*codec->bus->card->mixername) - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), + if (codec->afg || !*codec->card->mixername) + snprintf(codec->card->mixername, + sizeof(codec->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); return 0; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 40300fcc5308..0533c862b539 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1196,9 +1196,8 @@ static void snd_hda_codec_dev_release(struct device *dev) * * Returns 0 if successful, or a negative error code. */ -int snd_hda_codec_new(struct hda_bus *bus, - unsigned int codec_addr, - struct hda_codec **codecp) +int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, + unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; struct device *dev; @@ -1217,7 +1216,7 @@ int snd_hda_codec_new(struct hda_bus *bus, return -EINVAL; if (bus->caddr_tbl[codec_addr]) { - dev_err(bus->card->dev, + dev_err(card->dev, "address 0x%x is already occupied\n", codec_addr); return -EBUSY; @@ -1225,21 +1224,22 @@ int snd_hda_codec_new(struct hda_bus *bus, codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (codec == NULL) { - dev_err(bus->card->dev, "can't allocate struct hda_codec\n"); + dev_err(card->dev, "can't allocate struct hda_codec\n"); return -ENOMEM; } dev = hda_codec_dev(codec); device_initialize(dev); - dev->parent = bus->card->dev; + dev->parent = card->dev; dev->bus = &snd_hda_bus_type; dev->release = snd_hda_codec_dev_release; dev->groups = snd_hda_dev_attr_groups; - dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); + dev_set_name(dev, "hdaudioC%dD%d", card->number, codec_addr); dev_set_drvdata(dev, codec); /* for sysfs */ device_enable_async_suspend(dev); codec->bus = bus; + codec->card = card; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); mutex_init(&codec->control_mutex); @@ -1300,7 +1300,7 @@ int snd_hda_codec_new(struct hda_bus *bus, setup_fg_nodes(codec); if (!codec->afg && !codec->mfg) { - dev_err(bus->card->dev, "no AFG or MFG node found\n"); + dev_err(card->dev, "no AFG or MFG node found\n"); err = -ENODEV; goto error; } @@ -1308,7 +1308,7 @@ int snd_hda_codec_new(struct hda_bus *bus, fg = codec->afg ? codec->afg : codec->mfg; err = read_widget_caps(codec, fg); if (err < 0) { - dev_err(bus->card->dev, "cannot malloc\n"); + dev_err(card->dev, "cannot malloc\n"); goto error; } err = read_pin_defaults(codec); @@ -1337,9 +1337,9 @@ int snd_hda_codec_new(struct hda_bus *bus, sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); - snd_component_add(codec->bus->card, component); + snd_component_add(card, component); - err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops); + err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops); if (err < 0) goto error; @@ -2237,7 +2237,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) return NULL; strcpy(id.name, name); - return snd_ctl_find_id(codec->bus->card, &id); + return snd_ctl_find_id(codec->card, &id); } /** @@ -2301,7 +2301,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, nid = kctl->id.subdevice & 0xffff; if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) kctl->id.subdevice = 0; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_ctl_add(codec->card, kctl); if (err < 0) return err; item = snd_array_new(&codec->mixers); @@ -2354,7 +2354,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) int i; struct hda_nid_item *items = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) - snd_ctl_remove(codec->bus->card, items[i].kctl); + snd_ctl_remove(codec->card, items[i].kctl); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); } @@ -2427,7 +2427,7 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices); int snd_hda_codec_reset(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; - struct snd_card *card = bus->card; + struct snd_card *card = codec->card; int i; if (snd_hda_lock_devices(bus) < 0) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 8cf70369cd10..8908a0768736 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -274,6 +274,7 @@ struct hda_pcm { struct hda_codec { struct device dev; struct hda_bus *bus; + struct snd_card *card; unsigned int addr; /* codec addr*/ struct list_head list; /* list point */ @@ -420,8 +421,8 @@ enum { * constructors */ int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp); -int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp); +int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, + unsigned int codec_addr, struct hda_codec **codecp); int snd_hda_codec_configure(struct hda_codec *codec); int snd_hda_codec_update_widgets(struct hda_codec *codec); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 1695f0e2bd9d..f50863a5159d 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1898,7 +1898,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots) for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(bus, c, &codec); + err = snd_hda_codec_new(bus, bus->card, c, &codec); if (err < 0) continue; codec->jackpoll_interval = get_jackpoll_interval(chip); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 125f3420fa6a..57df06e76968 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -101,7 +101,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec) int err; sprintf(hwname, "HDA Codec %d", codec->addr); - err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); + err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep); if (err < 0) return err; codec->hwdep = hwdep; diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index e664307617bd..d7cfe7b8c32b 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -135,7 +135,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_INPUT_JACK /* free jack instances manually when clearing/reconfiguring */ if (!codec->bus->shutdown && jack->jack) - snd_device_free(codec->bus->card, jack->jack); + snd_device_free(codec->card, jack->jack); #endif for (cb = jack->callback; cb; cb = next) { next = cb->next; @@ -340,7 +340,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) if (!jack->kctl || jack->block_report) continue; state = get_jack_plug_state(jack->pin_sense); - snd_kctl_jack_report(codec->bus->card, jack->kctl, state); + snd_kctl_jack_report(codec->card, jack->kctl, state); #ifdef CONFIG_SND_HDA_INPUT_JACK if (jack->jack) snd_jack_report(jack->jack, @@ -412,11 +412,11 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, jack->phantom_jack = !!phantom_jack; state = snd_hda_jack_detect(codec, nid); - snd_kctl_jack_report(codec->bus->card, kctl, state); + snd_kctl_jack_report(codec->card, kctl, state); #ifdef CONFIG_SND_HDA_INPUT_JACK if (!phantom_jack) { jack->type = get_input_jack_type(codec, nid); - err = snd_jack_new(codec->bus->card, name, jack->type, + err = snd_jack_new(codec->card, name, jack->type, &jack->jack); if (err < 0) return err; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ce5a6da83419..cc32b878ae2e 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -839,7 +839,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec) int err; snprintf(name, sizeof(name), "codec#%d", codec->addr); - err = snd_card_proc_new(codec->bus->card, name, &entry); + err = snd_card_proc_new(codec->card, name, &entry); if (err < 0) return err; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index ccc962a1699f..e13c75d67847 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -149,7 +149,7 @@ static int reconfig_codec(struct hda_codec *codec) err = snd_hda_codec_build_controls(codec); if (err < 0) goto error; - err = snd_card_register(codec->bus->card); + err = snd_card_register(codec->card); error: snd_hda_power_down(codec); return err; diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h index c0e1c7d24dbe..7fedfa862419 100644 --- a/sound/pci/hda/hda_trace.h +++ b/sound/pci/hda/hda_trace.h @@ -23,7 +23,7 @@ DECLARE_EVENT_CLASS(hda_cmd, ), TP_fast_assign( - __entry->card = (codec)->bus->card->number; + __entry->card = (codec)->card->number; __entry->addr = (codec)->addr; __entry->val = (val); ), @@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(hda_power, ), TP_fast_assign( - __entry->card = (codec)->bus->card->number; + __entry->card = (codec)->card->number; __entry->addr = (codec)->addr; ), diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 81991b4134cd..ced3e82d9e23 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4352,7 +4352,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) const struct dsp_image_seg *dsp_os_image; const struct firmware *fw_entry; - if (request_firmware(&fw_entry, EFX_FILE, codec->bus->card->dev) != 0) + if (request_firmware(&fw_entry, EFX_FILE, codec->card->dev) != 0) return false; dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index f1812aabd63e..0f8354cbc7a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -579,7 +579,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) int err; snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); - err = snd_card_proc_new(codec->bus->card, name, &entry); + err = snd_card_proc_new(codec->card, name, &entry); if (err < 0) return err; @@ -594,7 +594,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) { if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { - snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry); + snd_device_free(per_pin->codec->card, per_pin->proc_entry); per_pin->proc_entry = NULL; } } @@ -1624,7 +1624,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) } if (eld_changed) - snd_ctl_notify(codec->bus->card, + snd_ctl_notify(codec->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &per_pin->eld_ctl->id); unlock: diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2045f33b1ace..57ad503ff940 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -907,16 +907,16 @@ static int patch_vt1708S(struct hda_codec *codec) if (get_codec_type(codec) == VT1708BCE) { kfree(codec->chip_name); codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), + snprintf(codec->card->mixername, + sizeof(codec->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } /* correct names for VT1705 */ if (codec->vendor_id == 0x11064397) { kfree(codec->chip_name); codec->chip_name = kstrdup("VT1705", GFP_KERNEL); - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), + snprintf(codec->card->mixername, + sizeof(codec->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } -- GitLab From f4de8fe6cffb449a779dff61f071bd1af9e18e0f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 16:17:18 +0100 Subject: [PATCH 0137/1910] ALSA: hda - Remove superfluous memory allocation error messages The memory allocators should have already given the kernel warning messages, thus we don't have to annoy again. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 16 ++++------------ sound/pci/hda/hda_controller.c | 18 ++++-------------- sound/pci/hda/hda_intel.c | 5 +---- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0533c862b539..262c41a8f96e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -776,10 +776,8 @@ int snd_hda_bus_new(struct snd_card *card, *busp = NULL; bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (bus == NULL) { - dev_err(card->dev, "can't allocate struct hda_bus\n"); + if (!bus) return -ENOMEM; - } bus->card = card; mutex_init(&bus->cmd_mutex); @@ -1223,10 +1221,8 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, } codec = kzalloc(sizeof(*codec), GFP_KERNEL); - if (codec == NULL) { - dev_err(card->dev, "can't allocate struct hda_codec\n"); + if (!codec) return -ENOMEM; - } dev = hda_codec_dev(codec); device_initialize(dev); @@ -1307,10 +1303,8 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, fg = codec->afg ? codec->afg : codec->mfg; err = read_widget_caps(codec, fg); - if (err < 0) { - dev_err(card->dev, "cannot malloc\n"); + if (err < 0) goto error; - } err = read_pin_defaults(codec); if (err < 0) goto error; @@ -1371,10 +1365,8 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) kfree(codec->wcaps); fg = codec->afg ? codec->afg : codec->mfg; err = read_widget_caps(codec, fg); - if (err < 0) { - codec_err(codec, "cannot malloc\n"); + if (err < 0) return err; - } snd_array_free(&codec->init_pins); err = read_pin_defaults(codec); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index f50863a5159d..be02bca6f7e6 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -974,14 +974,9 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, */ static int azx_alloc_cmd_io(struct azx *chip) { - int err; - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, - PAGE_SIZE, &chip->rb); - if (err < 0) - dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n"); - return err; + return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, + PAGE_SIZE, &chip->rb); } EXPORT_SYMBOL_GPL(azx_alloc_cmd_io); @@ -1472,7 +1467,6 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus, int azx_alloc_stream_pages(struct azx *chip) { int i, err; - struct snd_card *card = chip->card; for (i = 0; i < chip->num_streams; i++) { dsp_lock_init(&chip->azx_dev[i]); @@ -1480,18 +1474,14 @@ int azx_alloc_stream_pages(struct azx *chip) err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, BDL_SIZE, &chip->azx_dev[i].bdl); - if (err < 0) { - dev_err(card->dev, "cannot allocate BDL\n"); + if (err < 0) return -ENOMEM; - } } /* allocate memory for the position buffer */ err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, chip->num_streams * 8, &chip->posbuf); - if (err < 0) { - dev_err(card->dev, "cannot allocate posbuf\n"); + if (err < 0) return -ENOMEM; - } /* allocate CORB/RIRB */ err = azx_alloc_cmd_io(chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e75e8137e296..f7fb1b51d446 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1383,7 +1383,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, hda = kzalloc(sizeof(*hda), GFP_KERNEL); if (!hda) { - dev_err(card->dev, "Cannot allocate hda\n"); pci_disable_device(pci); return -ENOMEM; } @@ -1564,10 +1563,8 @@ static int azx_first_init(struct azx *chip) chip->num_streams = chip->playback_streams + chip->capture_streams; chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); - if (!chip->azx_dev) { - dev_err(card->dev, "cannot malloc azx_dev\n"); + if (!chip->azx_dev) return -ENOMEM; - } err = azx_alloc_stream_pages(chip); if (err < 0) -- GitLab From bbbc7e8502c95237dbd86cc4d0a12ca9a6b18c8f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 17:43:19 +0100 Subject: [PATCH 0138/1910] ALSA: hda - Allocate hda_pcm objects dynamically So far, the hda_codec object kept the hda_pcm list in an array, and the codec driver was expected to assign the array. However, this makes the object life cycle management harder, because the assigned array is freed at the codec driver detach while it might be still accessed by the opened streams. In this patch, we allocate each hda_pcm object dynamically and manage it as a linked list. Each object has a kref refcount, and both the codec driver binder and the PCM open/close touches it, so that the object won't be freed while in use. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 116 ++++++++++++++++++++++------------ sound/pci/hda/hda_codec.h | 18 +++++- sound/pci/hda/hda_generic.c | 28 ++++---- sound/pci/hda/hda_generic.h | 2 +- sound/pci/hda/hda_proc.c | 6 +- sound/pci/hda/patch_ca0132.c | 29 ++++----- sound/pci/hda/patch_hdmi.c | 30 +++------ sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 11 ++-- sound/pci/hda/patch_via.c | 6 +- 10 files changed, 145 insertions(+), 103 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 262c41a8f96e..20283bead10a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1116,6 +1116,60 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) return p; } +/* + * PCM device + */ +static void release_pcm(struct kref *kref) +{ + struct hda_pcm *pcm = container_of(kref, struct hda_pcm, kref); + + if (pcm->pcm) + snd_device_free(pcm->codec->card, pcm->pcm); + clear_bit(pcm->device, pcm->codec->bus->pcm_dev_bits); + kfree(pcm->name); + kfree(pcm); +} + +void snd_hda_codec_pcm_put(struct hda_pcm *pcm) +{ + kref_put(&pcm->kref, release_pcm); +} +EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_put); + +struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec, + const char *fmt, ...) +{ + struct hda_pcm *pcm; + va_list args; + + va_start(args, fmt); + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return NULL; + + pcm->codec = codec; + kref_init(&pcm->kref); + pcm->name = kvasprintf(GFP_KERNEL, fmt, args); + if (!pcm->name) { + kfree(pcm); + return NULL; + } + + list_add_tail(&pcm->list, &codec->pcm_list_head); + return pcm; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new); + +static void codec_release_pcms(struct hda_codec *codec) +{ + struct hda_pcm *pcm, *n; + + list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) { + list_del_init(&pcm->list); + snd_hda_codec_pcm_put(pcm); + } +} + /* * codec destructor */ @@ -1124,6 +1178,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) if (!codec) return; cancel_delayed_work_sync(&codec->jackpoll_work); + codec_release_pcms(codec); if (device_is_registered(hda_codec_dev(codec))) device_del(hda_codec_dev(codec)); snd_hda_jack_tbl_clear(codec); @@ -1251,6 +1306,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); INIT_LIST_HEAD(&codec->conn_list); + INIT_LIST_HEAD(&codec->pcm_list_head); INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); codec->depop_delay = -1; @@ -2370,9 +2426,8 @@ int snd_hda_lock_devices(struct hda_bus *bus) goto err_clear; list_for_each_entry(codec, &bus->codec_list, list) { - int pcm; - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + struct hda_pcm *cpcm; + list_for_each_entry(cpcm, &codec->pcm_list_head, list) { if (!cpcm->pcm) continue; if (cpcm->pcm->streams[0].substream_opened || @@ -2419,8 +2474,6 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices); int snd_hda_codec_reset(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; - struct snd_card *card = codec->card; - int i; if (snd_hda_lock_devices(bus) < 0) return -EBUSY; @@ -2429,14 +2482,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) cancel_delayed_work_sync(&codec->jackpoll_work); flush_workqueue(bus->workq); snd_hda_ctls_clear(codec); - /* release PCMs */ - for (i = 0; i < codec->num_pcms; i++) { - if (codec->pcm_info[i].pcm) { - snd_device_free(card, codec->pcm_info[i].pcm); - clear_bit(codec->pcm_info[i].device, - bus->pcm_dev_bits); - } - } + codec_release_pcms(codec); snd_hda_detach_beep_device(codec); if (device_is_registered(hda_codec_dev(codec))) device_del(hda_codec_dev(codec)); @@ -2454,8 +2500,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) snd_array_free(&codec->cvt_setups); snd_array_free(&codec->spdif_out); snd_array_free(&codec->verbs); - codec->num_pcms = 0; - codec->pcm_info = NULL; codec->preset = NULL; codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; @@ -3952,12 +3996,12 @@ static void hda_call_codec_resume(struct hda_codec *codec) static int hda_codec_runtime_suspend(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + struct hda_pcm *pcm; unsigned int state; - int i; cancel_delayed_work_sync(&codec->jackpoll_work); - for (i = 0; i < codec->num_pcms; i++) - snd_pcm_suspend_all(codec->pcm_info[i].pcm); + list_for_each_entry(pcm, &codec->pcm_list_head, list) + snd_pcm_suspend_all(pcm->pcm); state = hda_call_codec_suspend(codec); if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK)) clear_bit(codec->addr, &codec->bus->codec_powered); @@ -4018,22 +4062,21 @@ EXPORT_SYMBOL_GPL(snd_hda_build_controls); */ static int add_std_chmaps(struct hda_codec *codec) { - int i, str, err; + struct hda_pcm *pcm; + int str, err; - for (i = 0; i < codec->num_pcms; i++) { + list_for_each_entry(pcm, &codec->pcm_list_head, list) { for (str = 0; str < 2; str++) { - struct snd_pcm *pcm = codec->pcm_info[i].pcm; - struct hda_pcm_stream *hinfo = - &codec->pcm_info[i].stream[str]; + struct hda_pcm_stream *hinfo = &pcm->stream[str]; struct snd_pcm_chmap *chmap; const struct snd_pcm_chmap_elem *elem; - if (codec->pcm_info[i].own_chmap) + if (pcm->own_chmap) continue; if (!pcm || !hinfo->substreams) continue; elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; - err = snd_pcm_add_chmap_ctls(pcm, str, elem, + err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem, hinfo->channels_max, 0, &chmap); if (err < 0) @@ -4564,10 +4607,10 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) /* call build_pcms ops of the given codec and set up the default parameters */ int snd_hda_codec_parse_pcms(struct hda_codec *codec) { - unsigned int pcm; + struct hda_pcm *cpcm; int err; - if (codec->num_pcms) + if (!list_empty(&codec->pcm_list_head)) return 0; /* already parsed */ if (!codec->patch_ops.build_pcms) @@ -4580,8 +4623,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) return err; } - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + list_for_each_entry(cpcm, &codec->pcm_list_head, list) { int stream; for (stream = 0; stream < 2; stream++) { @@ -4589,8 +4631,6 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) if (!info->substreams) continue; - if (snd_BUG_ON(!cpcm->name)) - return -EINVAL; err = set_pcm_default_values(codec, info); if (err < 0) { codec_warn(codec, @@ -4608,7 +4648,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) int snd_hda_codec_build_pcms(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; - unsigned int pcm; + struct hda_pcm *cpcm; int dev, err; if (snd_BUG_ON(!bus->ops.attach_pcm)) @@ -4621,9 +4661,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) } /* attach a new PCM streams */ - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - + list_for_each_entry(cpcm, &codec->pcm_list_head, list) { if (cpcm->pcm) continue; /* already attached */ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) @@ -4651,11 +4689,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) * * Create PCM information for each codec included in the bus. * - * The build_pcms codec patch is requested to set up codec->num_pcms and - * codec->pcm_info properly. The array is referred by the top-level driver - * to create its PCM instances. - * The allocated codec->pcm_info should be released in codec->patch_ops.free - * callback. + * The build_pcms codec patch is requested to create and assign new + * hda_pcm objects. The codec is responsible to call snd_hda_codec_pcm_new() + * and fills the fields. Later they are instantiated by this function. * * At least, substreams, channels_min and channels_max must be filled for * each stream. substreams = 0 indicates that the stream doesn't exist. diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 8908a0768736..2ccd6f9a91fe 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -21,6 +21,7 @@ #ifndef __SOUND_HDA_CODEC_H #define __SOUND_HDA_CODEC_H +#include #include #include #include @@ -268,6 +269,10 @@ struct hda_pcm { int device; /* device number to assign */ struct snd_pcm *pcm; /* assigned PCM instance */ bool own_chmap; /* codec driver provides own channel maps */ + /* private: */ + struct hda_codec *codec; + struct kref kref; + struct list_head list; }; /* codec information */ @@ -301,8 +306,7 @@ struct hda_codec { struct hda_codec_ops patch_ops; /* PCM to create, set by patch_ops.build_pcms callback */ - unsigned int num_pcms; - struct hda_pcm *pcm_info; + struct list_head pcm_list_head; /* codec specific info */ void *spec; @@ -521,6 +525,16 @@ int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_parse_pcms(struct hda_codec *codec); int snd_hda_codec_build_pcms(struct hda_codec *codec); +__printf(2, 3) +struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec, + const char *fmt, ...); + +static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm) +{ + kref_get(&pcm->kref); +} +void snd_hda_codec_pcm_put(struct hda_pcm *pcm); + int snd_hda_codec_prepare(struct hda_codec *codec, struct hda_pcm_stream *hinfo, unsigned int stream, diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 947d1a50f384..092f06fd21bd 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -4644,7 +4644,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) err = snd_hda_create_dig_out_ctls(codec, spec->multiout.dig_out_nid, spec->multiout.dig_out_nid, - spec->pcm_rec[1].pcm_type); + spec->pcm_rec[1]->pcm_type); if (err < 0) return err; if (!spec->no_analog) { @@ -5115,20 +5115,20 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, int snd_hda_gen_build_pcms(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct hda_pcm *info; const struct hda_pcm_stream *p; bool have_multi_adcs; - codec->num_pcms = 1; - codec->pcm_info = info; - if (spec->no_analog) goto skip_analog; fill_pcm_stream_name(spec->stream_name_analog, sizeof(spec->stream_name_analog), " Analog", codec->chip_name); - info->name = spec->stream_name_analog; + info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog); + if (!info) + return -ENOMEM; + spec->pcm_rec[0] = info; if (spec->multiout.num_dacs > 0) { p = spec->stream_analog_playback; @@ -5161,10 +5161,12 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec) fill_pcm_stream_name(spec->stream_name_digital, sizeof(spec->stream_name_digital), " Digital", codec->chip_name); - codec->num_pcms = 2; + info = snd_hda_codec_pcm_new(codec, "%s", + spec->stream_name_digital); + if (!info) + return -ENOMEM; codec->slave_dig_outs = spec->multiout.slave_dig_outs; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; + spec->pcm_rec[1] = info; if (spec->dig_out_type) info->pcm_type = spec->dig_out_type; else @@ -5198,9 +5200,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec) fill_pcm_stream_name(spec->stream_name_alt_analog, sizeof(spec->stream_name_alt_analog), " Alt Analog", codec->chip_name); - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_alt_analog; + info = snd_hda_codec_pcm_new(codec, "%s", + spec->stream_name_alt_analog); + if (!info) + return -ENOMEM; + spec->pcm_rec[2] = info; if (spec->alt_dac_nid) { p = spec->stream_analog_alt_playback; if (!p) diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 3d852660443a..b211f889b335 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -144,7 +144,7 @@ struct hda_gen_spec { int const_channel_count; /* channel count for all */ /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in build_pcms() */ + struct hda_pcm *pcm_rec[3]; /* used in build_pcms() */ /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index cc32b878ae2e..aeb983e7506d 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -99,10 +99,10 @@ static void print_nid_array(struct snd_info_buffer *buffer, static void print_nid_pcms(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { - int pcm, type; + int type; struct hda_pcm *cpcm; - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - cpcm = &codec->pcm_info[pcm]; + + list_for_each_entry(cpcm, &codec->pcm_list_head, list) { for (type = 0; type < 2; type++) { if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) continue; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index ced3e82d9e23..555781fad26f 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -719,7 +719,6 @@ struct ca0132_spec { unsigned int num_inputs; hda_nid_t shared_mic_nid; hda_nid_t shared_out_nid; - struct hda_pcm pcm_rec[5]; /* PCM information */ /* chip access */ struct mutex chipio_mutex; /* chip access mutex */ @@ -4036,12 +4035,11 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = { static int ca0132_build_pcms(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct hda_pcm *info; - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0132 Analog"; + info = snd_hda_codec_pcm_new(codec, "CA0132 Analog"); + if (!info) + return -ENOMEM; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = @@ -4049,27 +4047,27 @@ static int ca0132_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - info++; - info->name = "CA0132 Analog Mic-In2"; + info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2"); + if (!info) + return -ENOMEM; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1]; - codec->num_pcms++; - info++; - info->name = "CA0132 What U Hear"; + info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear"); + if (!info) + return -ENOMEM; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2]; - codec->num_pcms++; if (!spec->dig_out && !spec->dig_in) return 0; - info++; - info->name = "CA0132 Digital"; + info = snd_hda_codec_pcm_new(codec, "CA0132 Digital"); + if (!info) + return -ENOMEM; info->pcm_type = HDA_PCM_TYPE_SPDIF; if (spec->dig_out) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = @@ -4081,7 +4079,6 @@ static int ca0132_build_pcms(struct hda_codec *codec) ca0132_pcm_digital_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; } - codec->num_pcms++; return 0; } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0f8354cbc7a7..708bbed15ea3 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -86,7 +86,6 @@ struct hdmi_spec_per_pin { bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ - char pcm_name[8]; /* filled in build_pcm callbacks */ #ifdef CONFIG_PROC_FS struct snd_info_entry *proc_entry; #endif @@ -132,7 +131,7 @@ struct hdmi_spec { int num_pins; struct snd_array pins; /* struct hdmi_spec_per_pin */ - struct snd_array pcm_rec; /* struct hda_pcm */ + struct hda_pcm *pcm_rec[16]; unsigned int channels_max; /* max over all cvts */ struct hdmi_eld temp_eld; @@ -355,8 +354,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) #define get_cvt(spec, idx) \ ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) -#define get_pcm_rec(spec, idx) \ - ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx)) +#define get_pcm_rec(spec, idx) ((spec)->pcm_rec[idx]) static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid) { @@ -2056,11 +2054,10 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) struct hdmi_spec_per_pin *per_pin; per_pin = get_pin(spec, pin_idx); - sprintf(per_pin->pcm_name, "HDMI %d", pin_idx); - info = snd_array_new(&spec->pcm_rec); + info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx); if (!info) return -ENOMEM; - info->name = per_pin->pcm_name; + spec->pcm_rec[pin_idx] = info; info->pcm_type = HDA_PCM_TYPE_HDMI; info->own_chmap = true; @@ -2070,9 +2067,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) /* other pstr fields are set in open */ } - codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec.list; - return 0; } @@ -2125,13 +2119,15 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) /* add channel maps */ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hda_pcm *pcm; struct snd_pcm_chmap *chmap; struct snd_kcontrol *kctl; int i; - if (!codec->pcm_info[pin_idx].pcm) + pcm = spec->pcm_rec[pin_idx]; + if (!pcm || !pcm->pcm) break; - err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm, + err = snd_pcm_add_chmap_ctls(pcm->pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, 0, pin_idx, &chmap); if (err < 0) @@ -2186,14 +2182,12 @@ static void hdmi_array_init(struct hdmi_spec *spec, int nums) { snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums); snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums); - snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums); } static void hdmi_array_free(struct hdmi_spec *spec) { snd_array_free(&spec->pins); snd_array_free(&spec->cvts); - snd_array_free(&spec->pcm_rec); } static void generic_hdmi_free(struct hda_codec *codec) @@ -2381,11 +2375,10 @@ static int simple_playback_build_pcms(struct hda_codec *codec) chans = get_wcaps(codec, per_cvt->cvt_nid); chans = get_wcaps_channels(chans); - info = snd_array_new(&spec->pcm_rec); + info = snd_hda_codec_pcm_new(codec, "HDMI 0"); if (!info) return -ENOMEM; - info->name = get_pin(spec, 0)->pcm_name; - sprintf(info->name, "HDMI 0"); + spec->pcm_rec[0] = info; info->pcm_type = HDA_PCM_TYPE_HDMI; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; *pstr = spec->pcm_playback; @@ -2393,9 +2386,6 @@ static int simple_playback_build_pcms(struct hda_codec *codec) if (pstr->channels_max <= 2 && chans && chans <= 16) pstr->channels_max = chans; - codec->num_pcms = 1; - codec->pcm_info = info; - return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 70808f92276a..0a5a2246e57a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5843,7 +5843,7 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_BUILD) { struct alc_spec *spec = codec->spec; - spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps; + spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps; } } diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 38a477333321..df243134baa8 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -83,7 +83,6 @@ struct si3054_spec { unsigned international; - struct hda_pcm pcm; }; @@ -199,11 +198,11 @@ static const struct hda_pcm_stream si3054_pcm = { static int si3054_build_pcms(struct hda_codec *codec) { - struct si3054_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm; - codec->num_pcms = 1; - codec->pcm_info = info; - info->name = "Si3054 Modem"; + struct hda_pcm *info; + + info = snd_hda_codec_pcm_new(codec, "Si3054 Modem"); + if (!info) + return -ENOMEM; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 57ad503ff940..11a05638e03b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -683,8 +683,10 @@ static int vt1708_build_pcms(struct hda_codec *codec) * 24bit samples are used. Until any workaround is found, * disable the 24bit format, so far. */ - for (i = 0; i < codec->num_pcms; i++) { - struct hda_pcm *info = &spec->gen.pcm_rec[i]; + for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) { + struct hda_pcm *info = spec->gen.pcm_rec[i]; + if (!info) + continue; if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams || info->pcm_type != HDA_PCM_TYPE_AUDIO) continue; -- GitLab From 61ca4107a16828559e2463e49b87002990da0b98 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 17:57:55 +0100 Subject: [PATCH 0139/1910] ALSA: hda - Don't assume non-NULL PCM ops The PCM ops might be set NULL, or cleared to NULL when the driver is unbound. Give a proper NULL check at each place to be more robust. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 9 +++++++-- sound/pci/hda/hda_controller.c | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 20283bead10a..3bd9158addc2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4525,7 +4525,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec, { int ret; mutex_lock(&codec->bus->prepare_mutex); - ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); + if (hinfo->ops.prepare) + ret = hinfo->ops.prepare(hinfo, codec, stream, format, + substream); + else + ret = -ENODEV; if (ret >= 0) purify_inactive_streams(codec); mutex_unlock(&codec->bus->prepare_mutex); @@ -4546,7 +4550,8 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, struct snd_pcm_substream *substream) { mutex_lock(&codec->bus->prepare_mutex); - hinfo->ops.cleanup(hinfo, codec, substream); + if (hinfo->ops.cleanup) + hinfo->ops.cleanup(hinfo, codec, substream); mutex_unlock(&codec->bus->prepare_mutex); } EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index be02bca6f7e6..ad85f9bfaf57 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -416,7 +416,8 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) azx_dev->running = 0; spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); - hinfo->ops.close(hinfo, apcm->codec, substream); + if (hinfo->ops.close) + hinfo->ops.close(hinfo, apcm->codec, substream); snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return 0; @@ -808,8 +809,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); if (azx_dev == NULL) { - mutex_unlock(&chip->open_mutex); - return -EBUSY; + err = -EBUSY; + goto unlock; } runtime->hw = azx_pcm_hw; runtime->hw.channels_min = hinfo->channels_min; @@ -844,12 +845,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, buff_step); snd_hda_power_up(apcm->codec); - err = hinfo->ops.open(hinfo, apcm->codec, substream); + if (hinfo->ops.open) + err = hinfo->ops.open(hinfo, apcm->codec, substream); + else + err = -ENODEV; if (err < 0) { azx_release_device(azx_dev); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); - return err; + goto powerdown; } snd_pcm_limit_hw_rates(runtime); /* sanity check */ @@ -858,10 +860,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_BUG_ON(!runtime->hw.formats) || snd_BUG_ON(!runtime->hw.rates)) { azx_release_device(azx_dev); - hinfo->ops.close(hinfo, apcm->codec, substream); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); - return -EINVAL; + if (hinfo->ops.close) + hinfo->ops.close(hinfo, apcm->codec, substream); + err = -EINVAL; + goto powerdown; } /* disable LINK_ATIME timestamps for capture streams @@ -880,6 +882,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); mutex_unlock(&chip->open_mutex); return 0; + + powerdown: + snd_hda_power_down(apcm->codec); + unlock: + mutex_unlock(&chip->open_mutex); + return err; } static int azx_pcm_mmap(struct snd_pcm_substream *substream, -- GitLab From e086e3035e0691b362755d1b5e24df631eee335a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 18:01:22 +0100 Subject: [PATCH 0140/1910] ALSA: core: Re-add snd_device_disconnect() Revive snd_device_disconnect() again so that it can be called from the individual driver. This time, HD-audio will need it. Signed-off-by: Takashi Iwai --- include/sound/core.h | 3 ++- sound/core/device.c | 43 +++++++++++++++++++++++++++++++++---------- sound/core/init.c | 5 +---- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index da5748289968..b12931f513f4 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, void *device_data, struct snd_device_ops *ops); int snd_device_register(struct snd_card *card, void *device_data); int snd_device_register_all(struct snd_card *card); -int snd_device_disconnect_all(struct snd_card *card); +void snd_device_disconnect(struct snd_card *card, void *device_data); +void snd_device_disconnect_all(struct snd_card *card); void snd_device_free(struct snd_card *card, void *device_data); void snd_device_free_all(struct snd_card *card); diff --git a/sound/core/device.c b/sound/core/device.c index 41bec3075ae5..446dc452654e 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -73,7 +73,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, } EXPORT_SYMBOL(snd_device_new); -static int __snd_device_disconnect(struct snd_device *dev) +static void __snd_device_disconnect(struct snd_device *dev) { if (dev->state == SNDRV_DEV_REGISTERED) { if (dev->ops->dev_disconnect && @@ -81,7 +81,6 @@ static int __snd_device_disconnect(struct snd_device *dev) dev_err(dev->card->dev, "device disconnect failure\n"); dev->state = SNDRV_DEV_DISCONNECTED; } - return 0; } static void __snd_device_free(struct snd_device *dev) @@ -108,6 +107,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) return NULL; } +/** + * snd_device_disconnect - disconnect the device + * @card: the card instance + * @device_data: the data pointer to disconnect + * + * Turns the device into the disconnection state, invoking + * dev_disconnect callback, if the device was already registered. + * + * Usually called from snd_card_disconnect(). + * + * Return: Zero if successful, or a negative error code on failure or if the + * device not found. + */ +void snd_device_disconnect(struct snd_card *card, void *device_data) +{ + struct snd_device *dev; + + if (snd_BUG_ON(!card || !device_data)) + return; + dev = look_for_dev(card, device_data); + if (dev) + __snd_device_disconnect(dev); + else + dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n", + device_data, __builtin_return_address(0)); +} +EXPORT_SYMBOL_GPL(snd_device_disconnect); + /** * snd_device_free - release the device from the card * @card: the card instance @@ -195,18 +222,14 @@ int snd_device_register_all(struct snd_card *card) * disconnect all the devices on the card. * called from init.c */ -int snd_device_disconnect_all(struct snd_card *card) +void snd_device_disconnect_all(struct snd_card *card) { struct snd_device *dev; - int err = 0; if (snd_BUG_ON(!card)) - return -ENXIO; - list_for_each_entry_reverse(dev, &card->devices, list) { - if (__snd_device_disconnect(dev) < 0) - err = -ENXIO; - } - return err; + return; + list_for_each_entry_reverse(dev, &card->devices, list) + __snd_device_disconnect(dev); } /* diff --git a/sound/core/init.c b/sound/core/init.c index 35419054821c..04734e047bfe 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops = int snd_card_disconnect(struct snd_card *card) { struct snd_monitor_file *mfile; - int err; if (!card) return -EINVAL; @@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card) #endif /* notify all devices that we are disconnected */ - err = snd_device_disconnect_all(card); - if (err < 0) - dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number); + snd_device_disconnect_all(card); snd_info_card_disconnect(card); if (card->registered) { -- GitLab From 9a6246ff78ac33af78f82704cde6fec361597eea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 18:17:28 +0100 Subject: [PATCH 0141/1910] ALSA: hda - Implement unbind more safely Now we have all pieces ready, and put them into places: - add the hda_pcm refcount to azx_pcm_open() and azx_pcm_close(), - call the most of cleanup code in hda_codec_reset() from the codec driver remove, - call the same code also from the hda_codec object free. Then the codec driver can be unbound more safely now. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_bind.c | 3 +- sound/pci/hda/hda_codec.c | 70 ++++++++++++++++++---------------- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_controller.c | 3 ++ sound/pci/hda/hda_local.h | 1 + 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 2d00417494e2..311896a23cd1 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -125,8 +125,7 @@ static int hda_codec_driver_remove(struct device *dev) if (codec->patch_ops.free) codec->patch_ops.free(codec); - codec->preset = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); + snd_hda_codec_cleanup_for_unbind(codec); module_put(dev->driver->owner); return 0; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3bd9158addc2..2c7e481a9171 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1160,36 +1160,62 @@ struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new); +/* + * codec destructor + */ static void codec_release_pcms(struct hda_codec *codec) { struct hda_pcm *pcm, *n; list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) { list_del_init(&pcm->list); + if (pcm->pcm) + snd_device_disconnect(codec->card, pcm->pcm); snd_hda_codec_pcm_put(pcm); } } -/* - * codec destructor - */ +void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) +{ + cancel_delayed_work_sync(&codec->jackpoll_work); + flush_workqueue(codec->bus->workq); + if (!codec->in_freeing) + snd_hda_ctls_clear(codec); + codec_release_pcms(codec); + snd_hda_detach_beep_device(codec); + memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); + snd_hda_jack_tbl_clear(codec); + codec->proc_widget_hook = NULL; + codec->spec = NULL; + + free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); + + /* free only driver_pins so that init_pins + user_pins are restored */ + snd_array_free(&codec->driver_pins); + snd_array_free(&codec->cvt_setups); + snd_array_free(&codec->spdif_out); + snd_array_free(&codec->verbs); + codec->preset = NULL; + codec->slave_dig_outs = NULL; + codec->spdif_status_reset = 0; + snd_array_free(&codec->mixers); + snd_array_free(&codec->nids); + remove_conn_list(codec); +} + static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; - cancel_delayed_work_sync(&codec->jackpoll_work); - codec_release_pcms(codec); + codec->in_freeing = 1; if (device_is_registered(hda_codec_dev(codec))) device_del(hda_codec_dev(codec)); - snd_hda_jack_tbl_clear(codec); free_init_pincfgs(codec); flush_workqueue(codec->bus->workq); list_del(&codec->list); - snd_array_free(&codec->mixers); - snd_array_free(&codec->nids); - snd_array_free(&codec->cvt_setups); - snd_array_free(&codec->spdif_out); - remove_conn_list(codec); codec->bus->caddr_tbl[codec->addr] = NULL; clear_bit(codec->addr, &codec->bus->codec_powered); snd_hda_sysfs_clear(codec); @@ -2479,31 +2505,9 @@ int snd_hda_codec_reset(struct hda_codec *codec) return -EBUSY; /* OK, let it free */ - cancel_delayed_work_sync(&codec->jackpoll_work); - flush_workqueue(bus->workq); - snd_hda_ctls_clear(codec); - codec_release_pcms(codec); - snd_hda_detach_beep_device(codec); if (device_is_registered(hda_codec_dev(codec))) device_del(hda_codec_dev(codec)); - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); - snd_hda_jack_tbl_clear(codec); - codec->proc_widget_hook = NULL; - codec->spec = NULL; - free_hda_cache(&codec->amp_cache); - free_hda_cache(&codec->cmd_cache); - init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); - init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); - /* free only driver_pins so that init_pins + user_pins are restored */ - snd_array_free(&codec->driver_pins); - snd_array_free(&codec->cvt_setups); - snd_array_free(&codec->spdif_out); - snd_array_free(&codec->verbs); - codec->preset = NULL; - codec->slave_dig_outs = NULL; - codec->spdif_status_reset = 0; - /* allow device access again */ snd_hda_unlock_devices(bus); return 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2ccd6f9a91fe..fc62ca51fd35 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -350,6 +350,7 @@ struct hda_codec { #endif /* misc flags */ + unsigned int in_freeing:1; /* being released */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change * (e.g. Realtek codecs) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index ad85f9bfaf57..cae50d5ffb81 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -420,6 +420,7 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) hinfo->ops.close(hinfo, apcm->codec, substream); snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); + snd_hda_codec_pcm_put(apcm->info); return 0; } @@ -806,6 +807,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) int err; int buff_step; + snd_hda_codec_pcm_get(apcm->info); mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); if (azx_dev == NULL) { @@ -887,6 +889,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_hda_power_down(apcm->codec); unlock: mutex_unlock(&chip->open_mutex); + snd_hda_codec_pcm_put(apcm->info); return err; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8588813163e3..1d001647fc47 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -150,6 +150,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, #define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \ __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) int snd_hda_codec_reset(struct hda_codec *codec); +void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec); enum { HDA_VMUTE_OFF, -- GitLab From bcd96557bd0ab1129fcdde073d5700aed8fcb942 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 20:44:54 +0100 Subject: [PATCH 0142/1910] ALSA: hda - Build PCMs and controls at codec driver probe This makes the code flow easier -- instead of the controller driver calling snd_hda_build_pcms() and snd_hda_build_controls() explicitly, the codec driver itself builds PCMs and controls at probe time. Then the controller driver only needs to call snd_card_register(). Also, this allows us the full bind/unbind control, too. Even when a codec driver is bound later, it automatically registers the new PCM and controls by itself. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_bind.c | 22 ++++++++++--- sound/pci/hda/hda_codec.c | 67 --------------------------------------- sound/pci/hda/hda_codec.h | 2 -- sound/pci/hda/hda_intel.c | 10 ------ sound/pci/hda/hda_tegra.c | 10 ------ 5 files changed, 17 insertions(+), 94 deletions(-) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 311896a23cd1..a49bc45c2ea5 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -106,16 +106,28 @@ static int hda_codec_driver_probe(struct device *dev) } err = codec->preset->patch(codec); - if (err < 0) { - module_put(owner); - goto error; + if (err < 0) + goto error_module; + + err = snd_hda_codec_build_pcms(codec); + if (err < 0) + goto error_module; + err = snd_hda_codec_build_controls(codec); + if (err < 0) + goto error_module; + if (codec->card->registered) { + err = snd_card_register(codec->card); + if (err < 0) + goto error_module; } return 0; + error_module: + module_put(owner); + error: - codec->preset = NULL; - memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); + snd_hda_codec_cleanup_for_unbind(codec); return err; } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2c7e481a9171..7085d3733d0d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4031,36 +4031,6 @@ const struct dev_pm_ops hda_codec_driver_pm = { NULL) }; -/** - * snd_hda_build_controls - build mixer controls - * @bus: the BUS - * - * Creates mixer controls for each codec included in the bus. - * - * Returns 0 if successful, otherwise a negative error code. - */ -int snd_hda_build_controls(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - int err = snd_hda_codec_build_controls(codec); - if (err < 0) { - codec_err(codec, - "cannot build controls for #%d (error %d)\n", - codec->addr, err); - err = snd_hda_codec_reset(codec); - if (err < 0) { - codec_err(codec, - "cannot revert codec\n"); - return err; - } - } - } - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_build_controls); - /* * add standard channel maps if not specified */ @@ -4692,43 +4662,6 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) return 0; } -/** - * snd_hda_build_pcms - build PCM information - * @bus: the BUS - * - * Create PCM information for each codec included in the bus. - * - * The build_pcms codec patch is requested to create and assign new - * hda_pcm objects. The codec is responsible to call snd_hda_codec_pcm_new() - * and fills the fields. Later they are instantiated by this function. - * - * At least, substreams, channels_min and channels_max must be filled for - * each stream. substreams = 0 indicates that the stream doesn't exist. - * When rates and/or formats are zero, the supported values are queried - * from the given nid. The nid is used also by the default ops.prepare - * and ops.cleanup callbacks. - * - * The driver needs to call ops.open in its open callback. Similarly, - * ops.close is supposed to be called in the close callback. - * ops.prepare should be called in the prepare or hw_params callback - * with the proper parameters for set up. - * ops.cleanup should be called in hw_free for clean up of streams. - * - * This function returns 0 if successful, or a negative error code. - */ -int snd_hda_build_pcms(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - int err = snd_hda_codec_build_pcms(codec); - if (err < 0) - return err; - } - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_build_pcms); - /** * snd_hda_add_new_ctls - create controls from the array * @codec: the HDA codec diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index fc62ca51fd35..46d253e2f266 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -516,13 +516,11 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid); /* * Mixer */ -int snd_hda_build_controls(struct hda_bus *bus); int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM */ -int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_parse_pcms(struct hda_codec *codec); int snd_hda_codec_build_pcms(struct hda_codec *codec); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f7fb1b51d446..e81461a413b8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1895,16 +1895,6 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } - /* create PCM streams */ - err = snd_hda_build_pcms(chip->bus); - if (err < 0) - goto out_free; - - /* create mixer controls */ - err = snd_hda_build_controls(chip->bus); - if (err < 0) - goto out_free; - err = snd_card_register(chip->card); if (err < 0) goto out_free; diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 1359fdd20f02..7586abe91dfb 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -497,16 +497,6 @@ static int hda_tegra_probe(struct platform_device *pdev) if (err < 0) goto out_free; - /* create PCM streams */ - err = snd_hda_build_pcms(chip->bus); - if (err < 0) - goto out_free; - - /* create mixer controls */ - err = snd_hda_build_controls(chip->bus); - if (err < 0) - goto out_free; - err = snd_card_register(chip->card); if (err < 0) goto out_free; -- GitLab From 2f35c630f7d49efdef29b58d81ed2531ddd916d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 22:43:26 +0100 Subject: [PATCH 0143/1910] ALSA: hda - Use standard workqueue for unsol and jack events The events that are handled by HD-audio drivers are no frequent and urgent ones, so we can use the standard workqueue without any problem nowadays. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 26 +++++--------------------- sound/pci/hda/hda_codec.h | 2 -- sound/pci/hda/hda_intel.c | 8 ++++---- sound/pci/hda/patch_ca0132.c | 3 +-- sound/pci/hda/patch_hdmi.c | 8 +++----- sound/pci/hda/patch_via.c | 3 +-- 6 files changed, 14 insertions(+), 36 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 7085d3733d0d..f2ccb39a3788 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -681,7 +681,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) struct hda_bus_unsolicited *unsol; unsigned int wp; - if (!bus || !bus->workq) + if (!bus) return 0; trace_hda_unsol_event(bus, res, res_ex); @@ -693,7 +693,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) unsol->queue[wp] = res; unsol->queue[wp + 1] = res_ex; - queue_work(bus->workq, &unsol->work); + schedule_work(&unsol->work); return 0; } @@ -732,13 +732,9 @@ static void snd_hda_bus_free(struct hda_bus *bus) return; WARN_ON(!list_empty(&bus->codec_list)); - if (bus->workq) - flush_workqueue(bus->workq); + cancel_work_sync(&bus->unsol.work); if (bus->ops.private_free) bus->ops.private_free(bus); - if (bus->workq) - destroy_workqueue(bus->workq); - kfree(bus); } @@ -785,16 +781,6 @@ int snd_hda_bus_new(struct snd_card *card, INIT_LIST_HEAD(&bus->codec_list); INIT_WORK(&bus->unsol.work, process_unsol_events); - snprintf(bus->workq_name, sizeof(bus->workq_name), - "hd-audio%d", card->number); - bus->workq = create_singlethread_workqueue(bus->workq_name); - if (!bus->workq) { - dev_err(card->dev, "cannot create workqueue %s\n", - bus->workq_name); - kfree(bus); - return -ENOMEM; - } - err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); if (err < 0) { snd_hda_bus_free(bus); @@ -1068,8 +1054,8 @@ static void hda_jackpoll_work(struct work_struct *work) if (!codec->jackpoll_interval) return; - queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, - codec->jackpoll_interval); + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); } static void init_hda_cache(struct hda_cache_rec *cache, @@ -1178,7 +1164,6 @@ static void codec_release_pcms(struct hda_codec *codec) void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) { cancel_delayed_work_sync(&codec->jackpoll_work); - flush_workqueue(codec->bus->workq); if (!codec->in_freeing) snd_hda_ctls_clear(codec); codec_release_pcms(codec); @@ -1214,7 +1199,6 @@ static void snd_hda_codec_free(struct hda_codec *codec) if (device_is_registered(hda_codec_dev(codec))) device_del(hda_codec_dev(codec)); free_init_pincfgs(codec); - flush_workqueue(codec->bus->workq); list_del(&codec->list); codec->bus->caddr_tbl[codec->addr] = NULL; clear_bit(codec->addr, &codec->bus->codec_powered); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 46d253e2f266..bf9efb7e1b9a 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -132,8 +132,6 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited unsol; - char workq_name[16]; - struct workqueue_struct *workq; /* common workqueue for codecs */ /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e81461a413b8..dbc5a593da46 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -528,10 +528,10 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) if (ok == 1) { azx_dev->irq_pending = 0; return ok; - } else if (ok == 0 && chip->bus && chip->bus->workq) { + } else if (ok == 0) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - queue_work(chip->bus->workq, &hda->irq_pending_work); + schedule_work(&hda->irq_pending_work); } return 0; } @@ -893,8 +893,8 @@ static int azx_runtime_resume(struct device *dev) if (status && bus) { list_for_each_entry(codec, &bus->codec_list, list) if (status & (1 << codec->addr)) - queue_delayed_work(codec->bus->workq, - &codec->jackpoll_work, codec->jackpoll_interval); + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); } /* disable controller Wake Up event*/ diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 555781fad26f..72d20652df50 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4410,8 +4410,7 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) * state machine run. */ cancel_delayed_work_sync(&spec->unsol_hp_work); - queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work, - msecs_to_jiffies(500)); + schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500)); cb->tbl->block_report = 1; } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 708bbed15ea3..7e9ff7b16e56 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1576,9 +1576,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) update_eld = true; } else if (repoll) { - queue_delayed_work(codec->bus->workq, - &per_pin->work, - msecs_to_jiffies(300)); + schedule_delayed_work(&per_pin->work, + msecs_to_jiffies(300)); goto unlock; } } @@ -2198,11 +2197,10 @@ static void generic_hdmi_free(struct hda_codec *codec) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); - cancel_delayed_work(&per_pin->work); + cancel_delayed_work_sync(&per_pin->work); eld_proc_free(per_pin); } - flush_workqueue(codec->bus->workq); hdmi_array_free(spec); kfree(spec); } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 11a05638e03b..2112fbe9e577 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -222,8 +222,7 @@ static void vt1708_update_hp_work(struct hda_codec *codec) if (!spec->hp_work_active) { codec->jackpoll_interval = msecs_to_jiffies(100); snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0); - queue_delayed_work(codec->bus->workq, - &codec->jackpoll_work, 0); + schedule_delayed_work(&codec->jackpoll_work, 0); spec->hp_work_active = true; } } else if (!hp_detect_with_aa(codec)) -- GitLab From d56db741b8e688a0b9d4d5bb9caa11dfcb7c0b08 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Feb 2015 23:25:35 +0100 Subject: [PATCH 0144/1910] ALSA: hda - Release resources in device release callback Move the destructor code to device release callback for the codec object instead. This is a safer place to release the resources than dev_free callback in general. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 51 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f2ccb39a3788..6fecf57c8d7c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1191,28 +1191,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) remove_conn_list(codec); } -static void snd_hda_codec_free(struct hda_codec *codec) -{ - if (!codec) - return; - codec->in_freeing = 1; - if (device_is_registered(hda_codec_dev(codec))) - device_del(hda_codec_dev(codec)); - free_init_pincfgs(codec); - list_del(&codec->list); - codec->bus->caddr_tbl[codec->addr] = NULL; - clear_bit(codec->addr, &codec->bus->codec_powered); - snd_hda_sysfs_clear(codec); - free_hda_cache(&codec->amp_cache); - free_hda_cache(&codec->cmd_cache); - kfree(codec->vendor_name); - kfree(codec->chip_name); - kfree(codec->modelname); - kfree(codec->wcaps); - codec->bus->num_codecs--; - put_device(hda_codec_dev(codec)); -} - static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); @@ -1241,14 +1219,32 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device) static int snd_hda_codec_dev_free(struct snd_device *device) { - snd_hda_codec_free(device->device_data); + struct hda_codec *codec = device->device_data; + + codec->in_freeing = 1; + if (device_is_registered(hda_codec_dev(codec))) + device_del(hda_codec_dev(codec)); + put_device(hda_codec_dev(codec)); return 0; } -/* just free the container */ static void snd_hda_codec_dev_release(struct device *dev) { - kfree(dev_to_hda_codec(dev)); + struct hda_codec *codec = dev_to_hda_codec(dev); + + free_init_pincfgs(codec); + list_del(&codec->list); + codec->bus->caddr_tbl[codec->addr] = NULL; + clear_bit(codec->addr, &codec->bus->codec_powered); + snd_hda_sysfs_clear(codec); + free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); + kfree(codec->vendor_name); + kfree(codec->chip_name); + kfree(codec->modelname); + kfree(codec->wcaps); + codec->bus->num_codecs--; + kfree(codec); } /** @@ -1362,7 +1358,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, setup_fg_nodes(codec); if (!codec->afg && !codec->mfg) { - dev_err(card->dev, "no AFG or MFG node found\n"); + codec_err(codec, "no AFG or MFG node found\n"); err = -ENODEV; goto error; } @@ -1408,7 +1404,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, return 0; error: - snd_hda_codec_free(codec); + put_device(hda_codec_dev(codec)); return err; } EXPORT_SYMBOL_GPL(snd_hda_codec_new); @@ -2464,7 +2460,6 @@ void snd_hda_unlock_devices(struct hda_bus *bus) { struct snd_card *card = bus->card; - card = bus->card; spin_lock(&card->files_lock); card->shutdown = 0; spin_unlock(&card->files_lock); -- GitLab From 0004defd4e44d81966b0c4164c2ee01f20ab357b Mon Sep 17 00:00:00 2001 From: Vishal Thanki Date: Tue, 3 Mar 2015 18:59:00 +0530 Subject: [PATCH 0145/1910] ASoC: simple-card: Add a NULL pointer check in asoc_simple_card_dai_link_of Make sure devm_kzalloc() succeeds. Signed-off-by: Vishal Thanki Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f7c6734bd5da..fb550b5869d2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, strlen(dai_link->cpu_dai_name) + strlen(dai_link->codec_dai_name) + 2, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto dai_link_of_err; + } + sprintf(name, "%s-%s", dai_link->cpu_dai_name, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; -- GitLab From 3591276d16f8e568449e4b6c719165ad2decf222 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 3 Mar 2015 11:33:15 -0500 Subject: [PATCH 0146/1910] c6x: kernel: setup: Include "linux/console.h" Or c6x will cause building break for allmodconfig, the related error: CC arch/c6x/kernel/setup.o arch/c6x/kernel/setup.c: In function 'setup_arch': arch/c6x/kernel/setup.c:433:2: error: 'conswitchp' undeclared (first use in this function) conswitchp = &dummy_con; ^ arch/c6x/kernel/setup.c:433:2: note: each undeclared identifier is reported only once for each function it appears in arch/c6x/kernel/setup.c:433:16: error: 'dummy_con' undeclared (first use in this function) conswitchp = &dummy_con; ^ Signed-off-by: Chen Gang [removed unnecessary #ifdef around include] Signed-off-by: Mark Salter --- arch/c6x/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c index 757128868d43..f016128ece13 100644 --- a/arch/c6x/kernel/setup.c +++ b/arch/c6x/kernel/setup.c @@ -26,7 +26,7 @@ #include #include #include - +#include #include #include -- GitLab From d44679ab13ee5f2f2b80e1bfa039a6eeb20ec41e Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 27 Feb 2015 10:48:19 +0300 Subject: [PATCH 0147/1910] xtensa: wire bpf and execveat syscalls Signed-off-by: Max Filippov --- arch/xtensa/include/uapi/asm/unistd.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h index db5bb72e2f4e..9d30db15ccb9 100644 --- a/arch/xtensa/include/uapi/asm/unistd.h +++ b/arch/xtensa/include/uapi/asm/unistd.h @@ -749,8 +749,12 @@ __SYSCALL(337, sys_seccomp, 3) __SYSCALL(338, sys_getrandom, 3) #define __NR_memfd_create 339 __SYSCALL(339, sys_memfd_create, 2) +#define __NR_bpf 340 +__SYSCALL(340, sys_bpf, 3) +#define __NR_execveat 341 +__SYSCALL(341, sys_execveat, 5) -#define __NR_syscall_count 340 +#define __NR_syscall_count 342 /* * sysxtensa syscall handler -- GitLab From 01e84c70fe40c8111f960987bcf7f931842e6d07 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 27 Feb 2015 11:02:38 +0300 Subject: [PATCH 0148/1910] xtensa: provide __NR_sync_file_range2 instead of __NR_sync_file_range xtensa actually uses sync_file_range2 implementation, so it should define __NR_sync_file_range2 as other architectures that use that function. That fixes userspace interface (that apparently never worked) and avoids special-casing xtensa in libc implementations. See the thread ending at http://lists.busybox.net/pipermail/uclibc/2015-February/048833.html for more details. Cc: stable@vger.kernel.org Signed-off-by: Max Filippov --- arch/xtensa/include/uapi/asm/unistd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h index 9d30db15ccb9..b95c30594355 100644 --- a/arch/xtensa/include/uapi/asm/unistd.h +++ b/arch/xtensa/include/uapi/asm/unistd.h @@ -715,7 +715,7 @@ __SYSCALL(323, sys_process_vm_writev, 6) __SYSCALL(324, sys_name_to_handle_at, 5) #define __NR_open_by_handle_at 325 __SYSCALL(325, sys_open_by_handle_at, 3) -#define __NR_sync_file_range 326 +#define __NR_sync_file_range2 326 __SYSCALL(326, sys_sync_file_range2, 6) #define __NR_perf_event_open 327 __SYSCALL(327, sys_perf_event_open, 5) -- GitLab From 7b24d97f16f561cc90eab1658100598d54a414fd Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 27 Feb 2015 20:00:00 +0100 Subject: [PATCH 0149/1910] crypto: doc - describe internal structure The kernel crypto API has many indirections which warrant a description as otherwise one can get easily lost. The description explains the layers of the kernel crypto API based on examples. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 264 ++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 04a8c24ead47..33f63cfc00ca 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -509,6 +509,270 @@ select it due to the used type and mask field. + + Internal Structure of Kernel Crypto API + + + The kernel crypto API has an internal structure where a cipher + implementation may use many layers and indirections. This section + shall help to clarify how the kernel crypto API uses + various components to implement the complete cipher. + + + + The following subsections explain the internal structure based + on existing cipher implementations. The first section addresses + the most complex scenario where all other scenarios form a logical + subset. + + + Generic AEAD Cipher Structure + + + The following ASCII art decomposes the kernel crypto API layers + when using the AEAD cipher with the automated IV generation. The + shown example is used by the IPSEC layer. + + + + For other use cases of AEAD ciphers, the ASCII art applies as + well, but the caller may not use the GIVCIPHER interface. In + this case, the caller must generate the IV. + + + + The depicted example decomposes the AEAD cipher of GCM(AES) based + on the generic C implementations (gcm.c, aes-generic.c, ctr.c, + ghash-generic.c, seqiv.c). The generic implementation serves as an + example showing the complete logic of the kernel crypto API. + + + + It is possible that some streamlined cipher implementations (like + AES-NI) provide implementations merging aspects which in the view + of the kernel crypto API cannot be decomposed into layers any more. + In case of the AES-NI implementation, the CTR mode, the GHASH + implementation and the AES cipher are all merged into one cipher + implementation registered with the kernel crypto API. In this case, + the concept described by the following ASCII art applies too. However, + the decomposition of GCM into the individual sub-components + by the kernel crypto API is not done any more. + + + + Each block in the following ASCII art is an independent cipher + instance obtained from the kernel crypto API. Each block + is accessed by the caller or by other blocks using the API functions + defined by the kernel crypto API for the cipher implementation type. + + + + The blocks below indicate the cipher type as well as the specific + logic implemented in the cipher. + + + + The ASCII art picture also indicates the call structure, i.e. who + calls which component. The arrows point to the invoked block + where the caller uses the API applicable to the cipher type + specified for the block. + + + + + + + + The following call sequence is applicable when the IPSEC layer + triggers an encryption operation with the esp_output function. During + configuration, the administrator set up the use of rfc4106(gcm(aes)) as + the cipher for ESP. The following call sequence is now depicted in the + ASCII art above: + + + + + + esp_output() invokes crypto_aead_givencrypt() to trigger an encryption + operation of the GIVCIPHER implementation. + + + + In case of GCM, the SEQIV implementation is registered as GIVCIPHER + in crypto_rfc4106_alloc(). + + + + The SEQIV performs its operation to generate an IV where the core + function is seqiv_geniv(). + + + + + + Now, SEQIV uses the AEAD API function calls to invoke the associated + AEAD cipher. In our case, during the instantiation of SEQIV, the + cipher handle for GCM is provided to SEQIV. This means that SEQIV + invokes AEAD cipher operations with the GCM cipher handle. + + + + During instantiation of the GCM handle, the CTR(AES) and GHASH + ciphers are instantiated. The cipher handles for CTR(AES) and GHASH + are retained for later use. + + + + The GCM implementation is responsible to invoke the CTR mode AES and + the GHASH cipher in the right manner to implement the GCM + specification. + + + + + + The GCM AEAD cipher type implementation now invokes the ABLKCIPHER API + with the instantiated CTR(AES) cipher handle. + + + + During instantiation of the CTR(AES) cipher, the CIPHER type + implementation of AES is instantiated. The cipher handle for AES is + retained. + + + + That means that the ABLKCIPHER implementation of CTR(AES) only + implements the CTR block chaining mode. After performing the block + chaining operation, the CIPHER implementation of AES is invoked. + + + + + + The ABLKCIPHER of CTR(AES) now invokes the CIPHER API with the AES + cipher handle to encrypt one block. + + + + + + The GCM AEAD implementation also invokes the GHASH cipher + implementation via the AHASH API. + + + + + + When the IPSEC layer triggers the esp_input() function, the same call + sequence is followed with the only difference that the operation starts + with step (2). + + + + Generic Block Cipher Structure + + Generic block ciphers follow the same concept as depicted with the ASCII + art picture above. + + + + For example, CBC(AES) is implemented with cbc.c, and aes-generic.c. The + ASCII art picture above applies as well with the difference that only + step (4) is used and the ABLKCIPHER block chaining mode is CBC. + + + + Generic Keyed Message Digest Structure + + Keyed message digest implementations again follow the same concept as + depicted in the ASCII art picture above. + + + + For example, HMAC(SHA256) is implemented with hmac.c and + sha256_generic.c. The following ASCII art illustrates the + implementation: + + + + + + + + The following call sequence is applicable when a caller triggers + an HMAC operation: + + + + + + The AHASH API functions are invoked by the caller. The HMAC + implementation performs its operation as needed. + + + + During initialization of the HMAC cipher, the SHASH cipher type of + SHA256 is instantiated. The cipher handle for the SHA256 instance is + retained. + + + + At one time, the HMAC implementation requires a SHA256 operation + where the SHA256 cipher handle is used. + + + + + + The HMAC instance now invokes the SHASH API with the SHA256 + cipher handle to calculate the message digest. + + + + + Developing Cipher Algorithms -- GitLab From 400c40cf78da00c16e561a3a253ca272455c42ef Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sat, 28 Feb 2015 20:50:00 +0100 Subject: [PATCH 0150/1910] crypto: algif - add AEAD support This patch adds the AEAD support for AF_ALG. The implementation is based on algif_skcipher, but contains heavy modifications to streamline the interface for AEAD uses. To use AEAD, the user space consumer has to use the salg_type named "aead". The AEAD implementation includes some overhead to calculate the size of the ciphertext, because the AEAD implementation of the kernel crypto API makes implied assumption on the location of the authentication tag. When performing an encryption, the tag will be added to the created ciphertext (note, the tag is placed adjacent to the ciphertext). For decryption, the caller must hand in the ciphertext with the tag appended to the ciphertext. Therefore, the selection of the used memory needs to add/subtract the tag size from the source/destination buffers depending on the encryption type. The code is provided with comments explaining when and how that operation is performed. A fully working example using all aspects of AEAD is provided at http://www.chronox.de/libkcapi.html Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/algif_aead.c | 666 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 666 insertions(+) create mode 100644 crypto/algif_aead.c diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c new file mode 100644 index 000000000000..527d27b023ab --- /dev/null +++ b/crypto/algif_aead.c @@ -0,0 +1,666 @@ +/* + * algif_aead: User-space interface for AEAD algorithms + * + * Copyright (C) 2014, Stephan Mueller + * + * This file provides the user-space API for AEAD ciphers. + * + * This file is derived from algif_skcipher.c. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct aead_sg_list { + unsigned int cur; + struct scatterlist sg[ALG_MAX_PAGES]; +}; + +struct aead_ctx { + struct aead_sg_list tsgl; + /* + * RSGL_MAX_ENTRIES is an artificial limit where user space at maximum + * can cause the kernel to allocate RSGL_MAX_ENTRIES * ALG_MAX_PAGES + * bytes + */ +#define RSGL_MAX_ENTRIES ALG_MAX_PAGES + struct af_alg_sgl rsgl[RSGL_MAX_ENTRIES]; + + void *iv; + + struct af_alg_completion completion; + + unsigned long used; + + unsigned int len; + bool more; + bool merge; + bool enc; + + size_t aead_assoclen; + struct aead_request aead_req; +}; + +static inline int aead_sndbuf(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + + return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) - + ctx->used, 0); +} + +static inline bool aead_writable(struct sock *sk) +{ + return PAGE_SIZE <= aead_sndbuf(sk); +} + +static inline bool aead_sufficient_data(struct aead_ctx *ctx) +{ + unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req)); + + return (ctx->used >= (ctx->aead_assoclen + (ctx->enc ? 0 : as))); +} + +static void aead_put_sgl(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + struct aead_sg_list *sgl = &ctx->tsgl; + struct scatterlist *sg = sgl->sg; + unsigned int i; + + for (i = 0; i < sgl->cur; i++) { + if (!sg_page(sg + i)) + continue; + + put_page(sg_page(sg + i)); + sg_assign_page(sg + i, NULL); + } + sgl->cur = 0; + ctx->used = 0; + ctx->more = 0; + ctx->merge = 0; +} + +static void aead_wmem_wakeup(struct sock *sk) +{ + struct socket_wq *wq; + + if (!aead_writable(sk)) + return; + + rcu_read_lock(); + wq = rcu_dereference(sk->sk_wq); + if (wq_has_sleeper(wq)) + wake_up_interruptible_sync_poll(&wq->wait, POLLIN | + POLLRDNORM | + POLLRDBAND); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); + rcu_read_unlock(); +} + +static int aead_wait_for_data(struct sock *sk, unsigned flags) +{ + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + long timeout; + DEFINE_WAIT(wait); + int err = -ERESTARTSYS; + + if (flags & MSG_DONTWAIT) + return -EAGAIN; + + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + + for (;;) { + if (signal_pending(current)) + break; + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + timeout = MAX_SCHEDULE_TIMEOUT; + if (sk_wait_event(sk, &timeout, !ctx->more)) { + err = 0; + break; + } + } + finish_wait(sk_sleep(sk), &wait); + + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + + return err; +} + +static void aead_data_wakeup(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + struct socket_wq *wq; + + if (ctx->more) + return; + if (!ctx->used) + return; + + rcu_read_lock(); + wq = rcu_dereference(sk->sk_wq); + if (wq_has_sleeper(wq)) + wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | + POLLRDNORM | + POLLRDBAND); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); + rcu_read_unlock(); +} + +static int aead_sendmsg(struct kiocb *unused, struct socket *sock, + struct msghdr *msg, size_t size) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + unsigned ivsize = + crypto_aead_ivsize(crypto_aead_reqtfm(&ctx->aead_req)); + struct aead_sg_list *sgl = &ctx->tsgl; + struct af_alg_control con = {}; + long copied = 0; + bool enc = 0; + bool init = 0; + int err = -EINVAL; + + if (msg->msg_controllen) { + err = af_alg_cmsg_send(msg, &con); + if (err) + return err; + + init = 1; + switch (con.op) { + case ALG_OP_ENCRYPT: + enc = 1; + break; + case ALG_OP_DECRYPT: + enc = 0; + break; + default: + return -EINVAL; + } + + if (con.iv && con.iv->ivlen != ivsize) + return -EINVAL; + } + + lock_sock(sk); + if (!ctx->more && ctx->used) + goto unlock; + + if (init) { + ctx->enc = enc; + if (con.iv) + memcpy(ctx->iv, con.iv->iv, ivsize); + + ctx->aead_assoclen = con.aead_assoclen; + } + + while (size) { + unsigned long len = size; + struct scatterlist *sg = NULL; + + /* use the existing memory in an allocated page */ + if (ctx->merge) { + sg = sgl->sg + sgl->cur - 1; + len = min_t(unsigned long, len, + PAGE_SIZE - sg->offset - sg->length); + err = memcpy_from_msg(page_address(sg_page(sg)) + + sg->offset + sg->length, + msg, len); + if (err) + goto unlock; + + sg->length += len; + ctx->merge = (sg->offset + sg->length) & + (PAGE_SIZE - 1); + + ctx->used += len; + copied += len; + size -= len; + continue; + } + + if (!aead_writable(sk)) { + /* user space sent too much data */ + aead_put_sgl(sk); + err = -EMSGSIZE; + goto unlock; + } + + /* allocate a new page */ + len = min_t(unsigned long, size, aead_sndbuf(sk)); + while (len) { + int plen = 0; + + if (sgl->cur >= ALG_MAX_PAGES) { + aead_put_sgl(sk); + err = -E2BIG; + goto unlock; + } + + sg = sgl->sg + sgl->cur; + plen = min_t(int, len, PAGE_SIZE); + + sg_assign_page(sg, alloc_page(GFP_KERNEL)); + err = -ENOMEM; + if (!sg_page(sg)) + goto unlock; + + err = memcpy_from_msg(page_address(sg_page(sg)), + msg, plen); + if (err) { + __free_page(sg_page(sg)); + sg_assign_page(sg, NULL); + goto unlock; + } + + sg->offset = 0; + sg->length = plen; + len -= plen; + ctx->used += plen; + copied += plen; + sgl->cur++; + size -= plen; + ctx->merge = plen & (PAGE_SIZE - 1); + } + } + + err = 0; + + ctx->more = msg->msg_flags & MSG_MORE; + if (!ctx->more && !aead_sufficient_data(ctx)) { + aead_put_sgl(sk); + err = -EMSGSIZE; + } + +unlock: + aead_data_wakeup(sk); + release_sock(sk); + + return err ?: copied; +} + +static ssize_t aead_sendpage(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + struct aead_sg_list *sgl = &ctx->tsgl; + int err = -EINVAL; + + if (flags & MSG_SENDPAGE_NOTLAST) + flags |= MSG_MORE; + + if (sgl->cur >= ALG_MAX_PAGES) + return -E2BIG; + + lock_sock(sk); + if (!ctx->more && ctx->used) + goto unlock; + + if (!size) + goto done; + + if (!aead_writable(sk)) { + /* user space sent too much data */ + aead_put_sgl(sk); + err = -EMSGSIZE; + goto unlock; + } + + ctx->merge = 0; + + get_page(page); + sg_set_page(sgl->sg + sgl->cur, page, size, offset); + sgl->cur++; + ctx->used += size; + + err = 0; + +done: + ctx->more = flags & MSG_MORE; + if (!ctx->more && !aead_sufficient_data(ctx)) { + aead_put_sgl(sk); + err = -EMSGSIZE; + } + +unlock: + aead_data_wakeup(sk); + release_sock(sk); + + return err ?: size; +} + +static int aead_recvmsg(struct kiocb *unused, struct socket *sock, + struct msghdr *msg, size_t ignored, int flags) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + unsigned bs = crypto_aead_blocksize(crypto_aead_reqtfm(&ctx->aead_req)); + unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req)); + struct aead_sg_list *sgl = &ctx->tsgl; + struct scatterlist *sg = NULL; + struct scatterlist assoc[ALG_MAX_PAGES]; + size_t assoclen = 0; + unsigned int i = 0; + int err = -EINVAL; + unsigned long used = 0; + size_t outlen = 0; + size_t usedpages = 0; + unsigned int cnt = 0; + + /* Limit number of IOV blocks to be accessed below */ + if (msg->msg_iter.nr_segs > RSGL_MAX_ENTRIES) + return -ENOMSG; + + lock_sock(sk); + + /* + * AEAD memory structure: For encryption, the tag is appended to the + * ciphertext which implies that the memory allocated for the ciphertext + * must be increased by the tag length. For decryption, the tag + * is expected to be concatenated to the ciphertext. The plaintext + * therefore has a memory size of the ciphertext minus the tag length. + * + * The memory structure for cipher operation has the following + * structure: + * AEAD encryption input: assoc data || plaintext + * AEAD encryption output: cipherntext || auth tag + * AEAD decryption input: assoc data || ciphertext || auth tag + * AEAD decryption output: plaintext + */ + + if (ctx->more) { + err = aead_wait_for_data(sk, flags); + if (err) + goto unlock; + } + + used = ctx->used; + + /* + * Make sure sufficient data is present -- note, the same check is + * is also present in sendmsg/sendpage. The checks in sendpage/sendmsg + * shall provide an information to the data sender that something is + * wrong, but they are irrelevant to maintain the kernel integrity. + * We need this check here too in case user space decides to not honor + * the error message in sendmsg/sendpage and still call recvmsg. This + * check here protects the kernel integrity. + */ + if (!aead_sufficient_data(ctx)) + goto unlock; + + /* + * The cipher operation input data is reduced by the associated data + * length as this data is processed separately later on. + */ + used -= ctx->aead_assoclen; + + if (ctx->enc) { + /* round up output buffer to multiple of block size */ + outlen = ((used + bs - 1) / bs * bs); + /* add the size needed for the auth tag to be created */ + outlen += as; + } else { + /* output data size is input without the authentication tag */ + outlen = used - as; + /* round up output buffer to multiple of block size */ + outlen = ((outlen + bs - 1) / bs * bs); + } + + /* convert iovecs of output buffers into scatterlists */ + while (iov_iter_count(&msg->msg_iter)) { + size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter), + (outlen - usedpages)); + + /* make one iovec available as scatterlist */ + err = af_alg_make_sg(&ctx->rsgl[cnt], &msg->msg_iter, + seglen); + if (err < 0) + goto unlock; + usedpages += err; + /* chain the new scatterlist with initial list */ + if (cnt) + scatterwalk_crypto_chain(ctx->rsgl[0].sg, + ctx->rsgl[cnt].sg, 1, + sg_nents(ctx->rsgl[cnt-1].sg)); + /* we do not need more iovecs as we have sufficient memory */ + if (outlen <= usedpages) + break; + iov_iter_advance(&msg->msg_iter, err); + cnt++; + } + + err = -EINVAL; + /* ensure output buffer is sufficiently large */ + if (usedpages < outlen) + goto unlock; + + sg_init_table(assoc, ALG_MAX_PAGES); + assoclen = ctx->aead_assoclen; + /* + * Split scatterlist into two: first part becomes AD, second part + * is plaintext / ciphertext. The first part is assigned to assoc + * scatterlist. When this loop finishes, sg points to the start of the + * plaintext / ciphertext. + */ + for (i = 0; i < ctx->tsgl.cur; i++) { + sg = sgl->sg + i; + if (sg->length <= assoclen) { + /* AD is larger than one page */ + sg_set_page(assoc + i, sg_page(sg), + sg->length, sg->offset); + assoclen -= sg->length; + if (i >= ctx->tsgl.cur) + goto unlock; + } else if (!assoclen) { + /* current page is to start of plaintext / ciphertext */ + if (i) + /* AD terminates at page boundary */ + sg_mark_end(assoc + i - 1); + else + /* AD size is zero */ + sg_mark_end(assoc); + break; + } else { + /* AD does not terminate at page boundary */ + sg_set_page(assoc + i, sg_page(sg), + assoclen, sg->offset); + sg_mark_end(assoc + i); + /* plaintext / ciphertext starts after AD */ + sg->length -= assoclen; + sg->offset += assoclen; + break; + } + } + + aead_request_set_assoc(&ctx->aead_req, assoc, ctx->aead_assoclen); + aead_request_set_crypt(&ctx->aead_req, sg, ctx->rsgl[0].sg, used, + ctx->iv); + + err = af_alg_wait_for_completion(ctx->enc ? + crypto_aead_encrypt(&ctx->aead_req) : + crypto_aead_decrypt(&ctx->aead_req), + &ctx->completion); + + if (err) { + /* EBADMSG implies a valid cipher operation took place */ + if (err == -EBADMSG) + aead_put_sgl(sk); + goto unlock; + } + + aead_put_sgl(sk); + + err = 0; + +unlock: + for (i = 0; i < cnt; i++) + af_alg_free_sg(&ctx->rsgl[i]); + + aead_wmem_wakeup(sk); + release_sock(sk); + + return err ? err : outlen; +} + +static unsigned int aead_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + unsigned int mask; + + sock_poll_wait(file, sk_sleep(sk), wait); + mask = 0; + + if (!ctx->more) + mask |= POLLIN | POLLRDNORM; + + if (aead_writable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + + return mask; +} + +static struct proto_ops algif_aead_ops = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .accept = sock_no_accept, + .setsockopt = sock_no_setsockopt, + + .release = af_alg_release, + .sendmsg = aead_sendmsg, + .sendpage = aead_sendpage, + .recvmsg = aead_recvmsg, + .poll = aead_poll, +}; + +static void *aead_bind(const char *name, u32 type, u32 mask) +{ + return crypto_alloc_aead(name, type, mask); +} + +static void aead_release(void *private) +{ + crypto_free_aead(private); +} + +static int aead_setauthsize(void *private, unsigned int authsize) +{ + return crypto_aead_setauthsize(private, authsize); +} + +static int aead_setkey(void *private, const u8 *key, unsigned int keylen) +{ + return crypto_aead_setkey(private, key, keylen); +} + +static void aead_sock_destruct(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + struct aead_ctx *ctx = ask->private; + unsigned int ivlen = crypto_aead_ivsize( + crypto_aead_reqtfm(&ctx->aead_req)); + + aead_put_sgl(sk); + sock_kzfree_s(sk, ctx->iv, ivlen); + sock_kfree_s(sk, ctx, ctx->len); + af_alg_release_parent(sk); +} + +static int aead_accept_parent(void *private, struct sock *sk) +{ + struct aead_ctx *ctx; + struct alg_sock *ask = alg_sk(sk); + unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private); + unsigned int ivlen = crypto_aead_ivsize(private); + + ctx = sock_kmalloc(sk, len, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + memset(ctx, 0, len); + + ctx->iv = sock_kmalloc(sk, ivlen, GFP_KERNEL); + if (!ctx->iv) { + sock_kfree_s(sk, ctx, len); + return -ENOMEM; + } + memset(ctx->iv, 0, ivlen); + + ctx->len = len; + ctx->used = 0; + ctx->more = 0; + ctx->merge = 0; + ctx->enc = 0; + ctx->tsgl.cur = 0; + ctx->aead_assoclen = 0; + af_alg_init_completion(&ctx->completion); + sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES); + + ask->private = ctx; + + aead_request_set_tfm(&ctx->aead_req, private); + aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, + af_alg_complete, &ctx->completion); + + sk->sk_destruct = aead_sock_destruct; + + return 0; +} + +static const struct af_alg_type algif_type_aead = { + .bind = aead_bind, + .release = aead_release, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .accept = aead_accept_parent, + .ops = &algif_aead_ops, + .name = "aead", + .owner = THIS_MODULE +}; + +static int __init algif_aead_init(void) +{ + return af_alg_register_type(&algif_type_aead); +} + +static void __exit algif_aead_exit(void) +{ + int err = af_alg_unregister_type(&algif_type_aead); + BUG_ON(err); +} + +module_init(algif_aead_init); +module_exit(algif_aead_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stephan Mueller "); +MODULE_DESCRIPTION("AEAD kernel crypto API user space interface"); -- GitLab From 44cac4fce9b820c37a8792df52a0e4ce33201949 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sat, 28 Feb 2015 20:50:40 +0100 Subject: [PATCH 0151/1910] crypto: algif - enable AEAD interface compilation Enable compilation of the AEAD AF_ALG support and provide a Kconfig option to compile the AEAD AF_ALG support. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/Kconfig | 9 +++++++++ crypto/Makefile | 1 + 2 files changed, 10 insertions(+) diff --git a/crypto/Kconfig b/crypto/Kconfig index 67275b7f176d..e74cecadef70 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1552,6 +1552,15 @@ config CRYPTO_USER_API_RNG This option enables the user-spaces interface for random number generator algorithms. +config CRYPTO_USER_API_AEAD + tristate "User-space interface for AEAD cipher algorithms" + depends on NET + select CRYPTO_AEAD + select CRYPTO_USER_API + help + This option enables the user-spaces interface for AEAD + cipher algorithms. + config CRYPTO_HASH_INFO bool diff --git a/crypto/Makefile b/crypto/Makefile index ba19465f9ad3..97b7d3ac87e7 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o +obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o # # generic algorithms and the async_tx api -- GitLab From be208356762c3609dc05d0f187be87fd60d8d32e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 28 Feb 2015 20:40:10 +0000 Subject: [PATCH 0152/1910] crypto: atmel - fix typo in dev_err error message Fix typo, "intialization" -> "initialization" Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 2 +- drivers/crypto/atmel-sha.c | 2 +- drivers/crypto/atmel-tdes.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 6597aac9905d..2e875aaeaed7 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -1374,7 +1374,7 @@ static int atmel_aes_probe(struct platform_device *pdev) /* Initializing the clock */ aes_dd->iclk = clk_get(&pdev->dev, "aes_clk"); if (IS_ERR(aes_dd->iclk)) { - dev_err(dev, "clock intialization failed.\n"); + dev_err(dev, "clock initialization failed.\n"); err = PTR_ERR(aes_dd->iclk); goto clk_err; } diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 34db04addc18..325d6b66c27c 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1385,7 +1385,7 @@ static int atmel_sha_probe(struct platform_device *pdev) /* Initializing the clock */ sha_dd->iclk = clk_get(&pdev->dev, "sha_clk"); if (IS_ERR(sha_dd->iclk)) { - dev_err(dev, "clock intialization failed.\n"); + dev_err(dev, "clock initialization failed.\n"); err = PTR_ERR(sha_dd->iclk); goto clk_err; } diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 258772d9b22f..8495b8959d0b 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -1408,7 +1408,7 @@ static int atmel_tdes_probe(struct platform_device *pdev) /* Initializing the clock */ tdes_dd->iclk = clk_get(&pdev->dev, "tdes_clk"); if (IS_ERR(tdes_dd->iclk)) { - dev_err(dev, "clock intialization failed.\n"); + dev_err(dev, "clock initialization failed.\n"); err = PTR_ERR(tdes_dd->iclk); goto clk_err; } -- GitLab From 209232d02586bc9b69ce028d22ae2512910f9e7f Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 1 Mar 2015 19:30:35 +0100 Subject: [PATCH 0153/1910] crypto: powerpc/md5 - assembler This is the assembler code for the MD5 implementation. Handling of algorithm constants has been slightly changed to reduce register usage and make better use of cores with multiple ALUs. Thus they are stored as delta values. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/md5-asm.S | 243 ++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 arch/powerpc/crypto/md5-asm.S diff --git a/arch/powerpc/crypto/md5-asm.S b/arch/powerpc/crypto/md5-asm.S new file mode 100644 index 000000000000..10cdf5bceebb --- /dev/null +++ b/arch/powerpc/crypto/md5-asm.S @@ -0,0 +1,243 @@ +/* + * Fast MD5 implementation for PPC + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include + +#define rHP r3 +#define rWP r4 + +#define rH0 r0 +#define rH1 r6 +#define rH2 r7 +#define rH3 r5 + +#define rW00 r8 +#define rW01 r9 +#define rW02 r10 +#define rW03 r11 +#define rW04 r12 +#define rW05 r14 +#define rW06 r15 +#define rW07 r16 +#define rW08 r17 +#define rW09 r18 +#define rW10 r19 +#define rW11 r20 +#define rW12 r21 +#define rW13 r22 +#define rW14 r23 +#define rW15 r24 + +#define rT0 r25 +#define rT1 r26 + +#define INITIALIZE \ + PPC_STLU r1,-INT_FRAME_SIZE(r1); \ + SAVE_8GPRS(14, r1); /* push registers onto stack */ \ + SAVE_4GPRS(22, r1); \ + SAVE_GPR(26, r1) + +#define FINALIZE \ + REST_8GPRS(14, r1); /* pop registers from stack */ \ + REST_4GPRS(22, r1); \ + REST_GPR(26, r1); \ + addi r1,r1,INT_FRAME_SIZE; + +#ifdef __BIG_ENDIAN__ +#define LOAD_DATA(reg, off) \ + lwbrx reg,0,rWP; /* load data */ +#define INC_PTR \ + addi rWP,rWP,4; /* increment per word */ +#define NEXT_BLOCK /* nothing to do */ +#else +#define LOAD_DATA(reg, off) \ + lwz reg,off(rWP); /* load data */ +#define INC_PTR /* nothing to do */ +#define NEXT_BLOCK \ + addi rWP,rWP,64; /* increment per block */ +#endif + +#define R_00_15(a, b, c, d, w0, w1, p, q, off, k0h, k0l, k1h, k1l) \ + LOAD_DATA(w0, off) /* W */ \ + and rT0,b,c; /* 1: f = b and c */ \ + INC_PTR /* ptr++ */ \ + andc rT1,d,b; /* 1: f' = ~b and d */ \ + LOAD_DATA(w1, off+4) /* W */ \ + or rT0,rT0,rT1; /* 1: f = f or f' */ \ + addi w0,w0,k0l; /* 1: wk = w + k */ \ + add a,a,rT0; /* 1: a = a + f */ \ + addis w0,w0,k0h; /* 1: wk = w + k' */ \ + addis w1,w1,k1h; /* 2: wk = w + k */ \ + add a,a,w0; /* 1: a = a + wk */ \ + addi w1,w1,k1l; /* 2: wk = w + k' */ \ + rotrwi a,a,p; /* 1: a = a rotl x */ \ + add d,d,w1; /* 2: a = a + wk */ \ + add a,a,b; /* 1: a = a + b */ \ + and rT0,a,b; /* 2: f = b and c */ \ + andc rT1,c,a; /* 2: f' = ~b and d */ \ + or rT0,rT0,rT1; /* 2: f = f or f' */ \ + add d,d,rT0; /* 2: a = a + f */ \ + INC_PTR /* ptr++ */ \ + rotrwi d,d,q; /* 2: a = a rotl x */ \ + add d,d,a; /* 2: a = a + b */ + +#define R_16_31(a, b, c, d, w0, w1, p, q, k0h, k0l, k1h, k1l) \ + andc rT0,c,d; /* 1: f = c and ~d */ \ + and rT1,b,d; /* 1: f' = b and d */ \ + addi w0,w0,k0l; /* 1: wk = w + k */ \ + or rT0,rT0,rT1; /* 1: f = f or f' */ \ + addis w0,w0,k0h; /* 1: wk = w + k' */ \ + add a,a,rT0; /* 1: a = a + f */ \ + addi w1,w1,k1l; /* 2: wk = w + k */ \ + add a,a,w0; /* 1: a = a + wk */ \ + addis w1,w1,k1h; /* 2: wk = w + k' */ \ + andc rT0,b,c; /* 2: f = c and ~d */ \ + rotrwi a,a,p; /* 1: a = a rotl x */ \ + add a,a,b; /* 1: a = a + b */ \ + add d,d,w1; /* 2: a = a + wk */ \ + and rT1,a,c; /* 2: f' = b and d */ \ + or rT0,rT0,rT1; /* 2: f = f or f' */ \ + add d,d,rT0; /* 2: a = a + f */ \ + rotrwi d,d,q; /* 2: a = a rotl x */ \ + add d,d,a; /* 2: a = a +b */ + +#define R_32_47(a, b, c, d, w0, w1, p, q, k0h, k0l, k1h, k1l) \ + xor rT0,b,c; /* 1: f' = b xor c */ \ + addi w0,w0,k0l; /* 1: wk = w + k */ \ + xor rT1,rT0,d; /* 1: f = f xor f' */ \ + addis w0,w0,k0h; /* 1: wk = w + k' */ \ + add a,a,rT1; /* 1: a = a + f */ \ + addi w1,w1,k1l; /* 2: wk = w + k */ \ + add a,a,w0; /* 1: a = a + wk */ \ + addis w1,w1,k1h; /* 2: wk = w + k' */ \ + rotrwi a,a,p; /* 1: a = a rotl x */ \ + add d,d,w1; /* 2: a = a + wk */ \ + add a,a,b; /* 1: a = a + b */ \ + xor rT1,rT0,a; /* 2: f = b xor f' */ \ + add d,d,rT1; /* 2: a = a + f */ \ + rotrwi d,d,q; /* 2: a = a rotl x */ \ + add d,d,a; /* 2: a = a + b */ + +#define R_48_63(a, b, c, d, w0, w1, p, q, k0h, k0l, k1h, k1l) \ + addi w0,w0,k0l; /* 1: w = w + k */ \ + orc rT0,b,d; /* 1: f = b or ~d */ \ + addis w0,w0,k0h; /* 1: w = w + k' */ \ + xor rT0,rT0,c; /* 1: f = f xor c */ \ + add a,a,w0; /* 1: a = a + wk */ \ + addi w1,w1,k1l; /* 2: w = w + k */ \ + add a,a,rT0; /* 1: a = a + f */ \ + addis w1,w1,k1h; /* 2: w = w + k' */ \ + rotrwi a,a,p; /* 1: a = a rotl x */ \ + add a,a,b; /* 1: a = a + b */ \ + orc rT0,a,c; /* 2: f = b or ~d */ \ + add d,d,w1; /* 2: a = a + wk */ \ + xor rT0,rT0,b; /* 2: f = f xor c */ \ + add d,d,rT0; /* 2: a = a + f */ \ + rotrwi d,d,q; /* 2: a = a rotl x */ \ + add d,d,a; /* 2: a = a + b */ + +_GLOBAL(ppc_md5_transform) + INITIALIZE + + mtctr r5 + lwz rH0,0(rHP) + lwz rH1,4(rHP) + lwz rH2,8(rHP) + lwz rH3,12(rHP) + +ppc_md5_main: + R_00_15(rH0, rH1, rH2, rH3, rW00, rW01, 25, 20, 0, + 0xd76b, -23432, 0xe8c8, -18602) + R_00_15(rH2, rH3, rH0, rH1, rW02, rW03, 15, 10, 8, + 0x2420, 0x70db, 0xc1be, -12562) + R_00_15(rH0, rH1, rH2, rH3, rW04, rW05, 25, 20, 16, + 0xf57c, 0x0faf, 0x4788, -14806) + R_00_15(rH2, rH3, rH0, rH1, rW06, rW07, 15, 10, 24, + 0xa830, 0x4613, 0xfd47, -27391) + R_00_15(rH0, rH1, rH2, rH3, rW08, rW09, 25, 20, 32, + 0x6981, -26408, 0x8b45, -2129) + R_00_15(rH2, rH3, rH0, rH1, rW10, rW11, 15, 10, 40, + 0xffff, 0x5bb1, 0x895d, -10306) + R_00_15(rH0, rH1, rH2, rH3, rW12, rW13, 25, 20, 48, + 0x6b90, 0x1122, 0xfd98, 0x7193) + R_00_15(rH2, rH3, rH0, rH1, rW14, rW15, 15, 10, 56, + 0xa679, 0x438e, 0x49b4, 0x0821) + + R_16_31(rH0, rH1, rH2, rH3, rW01, rW06, 27, 23, + 0x0d56, 0x6e0c, 0x1810, 0x6d2d) + R_16_31(rH2, rH3, rH0, rH1, rW11, rW00, 18, 12, + 0x9d02, -32109, 0x124c, 0x2332) + R_16_31(rH0, rH1, rH2, rH3, rW05, rW10, 27, 23, + 0x8ea7, 0x4a33, 0x0245, -18270) + R_16_31(rH2, rH3, rH0, rH1, rW15, rW04, 18, 12, + 0x8eee, -8608, 0xf258, -5095) + R_16_31(rH0, rH1, rH2, rH3, rW09, rW14, 27, 23, + 0x969d, -10697, 0x1cbe, -15288) + R_16_31(rH2, rH3, rH0, rH1, rW03, rW08, 18, 12, + 0x3317, 0x3e99, 0xdbd9, 0x7c15) + R_16_31(rH0, rH1, rH2, rH3, rW13, rW02, 27, 23, + 0xac4b, 0x7772, 0xd8cf, 0x331d) + R_16_31(rH2, rH3, rH0, rH1, rW07, rW12, 18, 12, + 0x6a28, 0x6dd8, 0x219a, 0x3b68) + + R_32_47(rH0, rH1, rH2, rH3, rW05, rW08, 28, 21, + 0x29cb, 0x28e5, 0x4218, -7788) + R_32_47(rH2, rH3, rH0, rH1, rW11, rW14, 16, 9, + 0x473f, 0x06d1, 0x3aae, 0x3036) + R_32_47(rH0, rH1, rH2, rH3, rW01, rW04, 28, 21, + 0xaea1, -15134, 0x640b, -11295) + R_32_47(rH2, rH3, rH0, rH1, rW07, rW10, 16, 9, + 0x8f4c, 0x4887, 0xbc7c, -22499) + R_32_47(rH0, rH1, rH2, rH3, rW13, rW00, 28, 21, + 0x7eb8, -27199, 0x00ea, 0x6050) + R_32_47(rH2, rH3, rH0, rH1, rW03, rW06, 16, 9, + 0xe01a, 0x22fe, 0x4447, 0x69c5) + R_32_47(rH0, rH1, rH2, rH3, rW09, rW12, 28, 21, + 0xb7f3, 0x0253, 0x59b1, 0x4d5b) + R_32_47(rH2, rH3, rH0, rH1, rW15, rW02, 16, 9, + 0x4701, -27017, 0xc7bd, -19859) + + R_48_63(rH0, rH1, rH2, rH3, rW00, rW07, 26, 22, + 0x0988, -1462, 0x4c70, -19401) + R_48_63(rH2, rH3, rH0, rH1, rW14, rW05, 17, 11, + 0xadaf, -5221, 0xfc99, 0x66f7) + R_48_63(rH0, rH1, rH2, rH3, rW12, rW03, 26, 22, + 0x7e80, -16418, 0xba1e, -25587) + R_48_63(rH2, rH3, rH0, rH1, rW10, rW01, 17, 11, + 0x4130, 0x380d, 0xe0c5, 0x738d) + lwz rW00,0(rHP) + R_48_63(rH0, rH1, rH2, rH3, rW08, rW15, 26, 22, + 0xe837, -30770, 0xde8a, 0x69e8) + lwz rW14,4(rHP) + R_48_63(rH2, rH3, rH0, rH1, rW06, rW13, 17, 11, + 0x9e79, 0x260f, 0x256d, -27941) + lwz rW12,8(rHP) + R_48_63(rH0, rH1, rH2, rH3, rW04, rW11, 26, 22, + 0xab75, -20775, 0x4f9e, -28397) + lwz rW10,12(rHP) + R_48_63(rH2, rH3, rH0, rH1, rW02, rW09, 17, 11, + 0x662b, 0x7c56, 0x11b2, 0x0358) + + add rH0,rH0,rW00 + stw rH0,0(rHP) + add rH1,rH1,rW14 + stw rH1,4(rHP) + add rH2,rH2,rW12 + stw rH2,8(rHP) + add rH3,rH3,rW10 + stw rH3,12(rHP) + NEXT_BLOCK + + bdnz ppc_md5_main + + FINALIZE + blr -- GitLab From e90508d3b0866c29146535576931356aba072a86 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 1 Mar 2015 19:30:41 +0100 Subject: [PATCH 0154/1910] crypto: powerpc/md5 - glue Glue code for crypto infrastructure. Call the assembler code where required. Take a little care about small input data. Kick out early for input chunks < 64 bytes and replace memset for context cleanup with simple loop. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/md5_glue.c | 165 +++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 arch/powerpc/crypto/md5_glue.c diff --git a/arch/powerpc/crypto/md5_glue.c b/arch/powerpc/crypto/md5_glue.c new file mode 100644 index 000000000000..452fb4dc575f --- /dev/null +++ b/arch/powerpc/crypto/md5_glue.c @@ -0,0 +1,165 @@ +/* + * Glue code for MD5 implementation for PPC assembler + * + * Based on generic implementation. + * + * Copyright (c) 2015 Markus Stockhausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void ppc_md5_transform(u32 *state, const u8 *src, u32 blocks); + +static inline void ppc_md5_clear_context(struct md5_state *sctx) +{ + int count = sizeof(struct md5_state) >> 2; + u32 *ptr = (u32 *)sctx; + + /* make sure we can clear the fast way */ + BUILD_BUG_ON(sizeof(struct md5_state) % 4); + do { *ptr++ = 0; } while (--count); +} + +static int ppc_md5_init(struct shash_desc *desc) +{ + struct md5_state *sctx = shash_desc_ctx(desc); + + sctx->hash[0] = 0x67452301; + sctx->hash[1] = 0xefcdab89; + sctx->hash[2] = 0x98badcfe; + sctx->hash[3] = 0x10325476; + sctx->byte_count = 0; + + return 0; +} + +static int ppc_md5_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct md5_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->byte_count & 0x3f; + unsigned int avail = 64 - offset; + const u8 *src = data; + + sctx->byte_count += len; + + if (avail > len) { + memcpy((char *)sctx->block + offset, src, len); + return 0; + } + + if (offset) { + memcpy((char *)sctx->block + offset, src, avail); + ppc_md5_transform(sctx->hash, (const u8 *)sctx->block, 1); + len -= avail; + src += avail; + } + + if (len > 63) { + ppc_md5_transform(sctx->hash, src, len >> 6); + src += len & ~0x3f; + len &= 0x3f; + } + + memcpy((char *)sctx->block, src, len); + return 0; +} + +static int ppc_md5_final(struct shash_desc *desc, u8 *out) +{ + struct md5_state *sctx = shash_desc_ctx(desc); + const unsigned int offset = sctx->byte_count & 0x3f; + const u8 *src = (const u8 *)sctx->block; + u8 *p = (u8 *)src + offset; + int padlen = 55 - offset; + __le64 *pbits = (__le64 *)((char *)sctx->block + 56); + __le32 *dst = (__le32 *)out; + + *p++ = 0x80; + + if (padlen < 0) { + memset(p, 0x00, padlen + sizeof (u64)); + ppc_md5_transform(sctx->hash, src, 1); + p = (char *)sctx->block; + padlen = 56; + } + + memset(p, 0, padlen); + *pbits = cpu_to_le64(sctx->byte_count << 3); + ppc_md5_transform(sctx->hash, src, 1); + + dst[0] = cpu_to_le32(sctx->hash[0]); + dst[1] = cpu_to_le32(sctx->hash[1]); + dst[2] = cpu_to_le32(sctx->hash[2]); + dst[3] = cpu_to_le32(sctx->hash[3]); + + ppc_md5_clear_context(sctx); + return 0; +} + +static int ppc_md5_export(struct shash_desc *desc, void *out) +{ + struct md5_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int ppc_md5_import(struct shash_desc *desc, const void *in) +{ + struct md5_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg alg = { + .digestsize = MD5_DIGEST_SIZE, + .init = ppc_md5_init, + .update = ppc_md5_update, + .final = ppc_md5_final, + .export = ppc_md5_export, + .import = ppc_md5_import, + .descsize = sizeof(struct md5_state), + .statesize = sizeof(struct md5_state), + .base = { + .cra_name = "md5", + .cra_driver_name= "md5-ppc", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init ppc_md5_mod_init(void) +{ + return crypto_register_shash(&alg); +} + +static void __exit ppc_md5_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(ppc_md5_mod_init); +module_exit(ppc_md5_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, PPC assembler"); + +MODULE_ALIAS_CRYPTO("md5"); +MODULE_ALIAS_CRYPTO("md5-ppc"); -- GitLab From e8e5995372ac3fc63995915dcb351f38a3560018 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 1 Mar 2015 19:30:46 +0100 Subject: [PATCH 0155/1910] crypto: powerpc/md5 - kernel config Integrate the module into the kernel config tree. Signed-off-by: Markus Stockhausen Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Makefile | 2 ++ crypto/Kconfig | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index d400bf9e43c6..c6b25cba3a0c 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -5,11 +5,13 @@ # obj-$(CONFIG_CRYPTO_AES_PPC_SPE) += aes-ppc-spe.o +obj-$(CONFIG_CRYPTO_MD5_PPC) += md5-ppc.o obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o obj-$(CONFIG_CRYPTO_SHA1_PPC_SPE) += sha1-ppc-spe.o obj-$(CONFIG_CRYPTO_SHA256_PPC_SPE) += sha256-ppc-spe.o aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes_spe_glue.o +md5-ppc-y := md5-asm.o md5_glue.o sha1-powerpc-y := sha1-powerpc-asm.o sha1.o sha1-ppc-spe-y := sha1-spe-asm.o sha1_spe_glue.o sha256-ppc-spe-y := sha256-spe-asm.o sha256_spe_glue.o diff --git a/crypto/Kconfig b/crypto/Kconfig index e74cecadef70..6918aff74f4d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -436,6 +436,14 @@ config CRYPTO_MD5_OCTEON MD5 message digest algorithm (RFC1321) implemented using OCTEON crypto instructions, when available. +config CRYPTO_MD5_PPC + tristate "MD5 digest algorithm (PPC)" + depends on PPC + select CRYPTO_HASH + help + MD5 message digest algorithm (RFC1321) implemented + in PPC assembler. + config CRYPTO_MD5_SPARC64 tristate "MD5 digest algorithm (SPARC64)" depends on SPARC64 -- GitLab From 04bcbfcf7e28ba502383a8e19d99960ab8e347c8 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 1 Mar 2015 20:39:17 +0100 Subject: [PATCH 0156/1910] crypto: drbg - use single block cipher API The CTR DRBG only encrypts one single block at a time. Thus, use the single block crypto API to avoid additional overhead from the block chaining modes. With the patch, the speed of the DRBG increases between 30% and 40%. The DRBG still passes the CTR DRBG CAVS test. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index d8ff16e5c322..c14274ac8d61 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -119,19 +119,19 @@ static const struct drbg_core drbg_cores[] = { .statelen = 32, /* 256 bits as defined in 10.2.1 */ .blocklen_bytes = 16, .cra_name = "ctr_aes128", - .backend_cra_name = "ecb(aes)", + .backend_cra_name = "aes", }, { .flags = DRBG_CTR | DRBG_STRENGTH192, .statelen = 40, /* 320 bits as defined in 10.2.1 */ .blocklen_bytes = 16, .cra_name = "ctr_aes192", - .backend_cra_name = "ecb(aes)", + .backend_cra_name = "aes", }, { .flags = DRBG_CTR | DRBG_STRENGTH256, .statelen = 48, /* 384 bits as defined in 10.2.1 */ .blocklen_bytes = 16, .cra_name = "ctr_aes256", - .backend_cra_name = "ecb(aes)", + .backend_cra_name = "aes", }, #endif /* CONFIG_CRYPTO_DRBG_CTR */ #ifdef CONFIG_CRYPTO_DRBG_HASH @@ -1644,24 +1644,24 @@ static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key, static int drbg_init_sym_kernel(struct drbg_state *drbg) { int ret = 0; - struct crypto_blkcipher *tfm; + struct crypto_cipher *tfm; - tfm = crypto_alloc_blkcipher(drbg->core->backend_cra_name, 0, 0); + tfm = crypto_alloc_cipher(drbg->core->backend_cra_name, 0, 0); if (IS_ERR(tfm)) { pr_info("DRBG: could not allocate cipher TFM handle\n"); return PTR_ERR(tfm); } - BUG_ON(drbg_blocklen(drbg) != crypto_blkcipher_blocksize(tfm)); + BUG_ON(drbg_blocklen(drbg) != crypto_cipher_blocksize(tfm)); drbg->priv_data = tfm; return ret; } static int drbg_fini_sym_kernel(struct drbg_state *drbg) { - struct crypto_blkcipher *tfm = - (struct crypto_blkcipher *)drbg->priv_data; + struct crypto_cipher *tfm = + (struct crypto_cipher *)drbg->priv_data; if (tfm) - crypto_free_blkcipher(tfm); + crypto_free_cipher(tfm); drbg->priv_data = NULL; return 0; } @@ -1669,21 +1669,14 @@ static int drbg_fini_sym_kernel(struct drbg_state *drbg) static int drbg_kcapi_sym(struct drbg_state *drbg, const unsigned char *key, unsigned char *outval, const struct drbg_string *in) { - int ret = 0; - struct scatterlist sg_in, sg_out; - struct blkcipher_desc desc; - struct crypto_blkcipher *tfm = - (struct crypto_blkcipher *)drbg->priv_data; - - desc.tfm = tfm; - desc.flags = 0; - crypto_blkcipher_setkey(tfm, key, (drbg_keylen(drbg))); - /* there is only component in *in */ - sg_init_one(&sg_in, in->buf, in->len); - sg_init_one(&sg_out, outval, drbg_blocklen(drbg)); - ret = crypto_blkcipher_encrypt(&desc, &sg_out, &sg_in, in->len); + struct crypto_cipher *tfm = + (struct crypto_cipher *)drbg->priv_data; - return ret; + crypto_cipher_setkey(tfm, key, (drbg_keylen(drbg))); + /* there is only component in *in */ + BUG_ON(in->len < drbg_blocklen(drbg)); + crypto_cipher_encrypt_one(tfm, outval, in->buf); + return 0; } #endif /* CONFIG_CRYPTO_DRBG_CTR */ -- GitLab From 37821da088d090d8e152f3f8cc072948fa544e5a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 1 Mar 2015 20:40:17 +0100 Subject: [PATCH 0157/1910] crypto: drbg - remove superflowous memsets The DRBG code contains memset(0) calls to initialize a varaible that are not necessary as the variable is always overwritten by the processing. This patch increases the CTR and Hash DRBGs by about 5%. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index c14274ac8d61..56c1d7ec3d9e 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -308,9 +308,6 @@ static int drbg_ctr_bcc(struct drbg_state *drbg, drbg_string_fill(&data, out, drbg_blocklen(drbg)); - /* 10.4.3 step 1 */ - memset(out, 0, drbg_blocklen(drbg)); - /* 10.4.3 step 2 / 4 */ list_for_each_entry(curr, in, list) { const unsigned char *pos = curr->buf; @@ -406,7 +403,6 @@ static int drbg_ctr_df(struct drbg_state *drbg, memset(pad, 0, drbg_blocklen(drbg)); memset(iv, 0, drbg_blocklen(drbg)); - memset(temp, 0, drbg_statelen(drbg)); /* 10.4.2 step 1 is implicit as we work byte-wise */ @@ -523,7 +519,6 @@ static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, unsigned int len = 0; struct drbg_string cipherin; - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); if (3 > reseed) memset(df_data, 0, drbg_statelen(drbg)); @@ -585,8 +580,6 @@ static int drbg_ctr_generate(struct drbg_state *drbg, int ret = 0; struct drbg_string data; - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - /* 10.2.1.5.2 step 2 */ if (addtl && !list_empty(addtl)) { ret = drbg_ctr_update(drbg, addtl, 2); @@ -761,7 +754,6 @@ static struct drbg_state_ops drbg_hmac_ops = { .generate = drbg_hmac_generate, .crypto_init = drbg_init_hash_kernel, .crypto_fini = drbg_fini_hash_kernel, - }; #endif /* CONFIG_CRYPTO_DRBG_HMAC */ @@ -838,8 +830,6 @@ static int drbg_hash_df(struct drbg_state *drbg, unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg); struct drbg_string data; - memset(tmp, 0, drbg_blocklen(drbg)); - /* 10.4.1 step 3 */ input[0] = 1; drbg_cpu_to_be32((outlen * 8), &input[1]); @@ -879,7 +869,6 @@ static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed, unsigned char *V = drbg->scratchpad; unsigned char prefix = DRBG_PREFIX1; - memset(drbg->scratchpad, 0, drbg_statelen(drbg)); if (!seed) return -EINVAL; @@ -921,9 +910,6 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg, LIST_HEAD(datalist); unsigned char prefix = DRBG_PREFIX2; - /* this is value w as per documentation */ - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - /* 10.1.1.4 step 2 */ if (!addtl || list_empty(addtl)) return 0; @@ -959,9 +945,6 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, struct drbg_string data; LIST_HEAD(datalist); - memset(src, 0, drbg_statelen(drbg)); - memset(dst, 0, drbg_blocklen(drbg)); - /* 10.1.1.4 step hashgen 2 */ memcpy(src, drbg->V, drbg_statelen(drbg)); @@ -1018,7 +1001,6 @@ static int drbg_hash_generate(struct drbg_state *drbg, len = drbg_hash_hashgen(drbg, buf, buflen); /* this is the value H as documented in 10.1.1.4 */ - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); /* 10.1.1.4 step 4 */ drbg_string_fill(&data1, &prefix, 1); list_add_tail(&data1.list, &datalist); -- GitLab From 1a6ab46fa9c2bc9399694b4856ab7ea19c036485 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 4 Mar 2015 10:56:13 +0900 Subject: [PATCH 0158/1910] ALSA: Fix spelling typo in Documentation/DocBook/alsa-driver-api.xml This patch fix spelling typo found in alsa-driver-api.xml. It is because this file is generated from comments in source files, I have to fix source files. Signed-off-by: Masanari Iida Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 4 ++-- include/sound/control.h | 2 +- include/sound/soc.h | 2 +- include/uapi/sound/compress_offload.h | 2 +- sound/core/pcm_dmaengine.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index f48089d364c5..fa1d05512c09 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -70,7 +70,7 @@ struct snd_compr_runtime { * @device: device pointer * @direction: stream direction, playback/recording * @metadata_set: metadata set flag, true when set - * @next_track: has userspace signall next track transistion, true when set + * @next_track: has userspace signal next track transition, true when set * @private_data: pointer to DSP private data */ struct snd_compr_stream { @@ -95,7 +95,7 @@ struct snd_compr_stream { * and the stream properties * @get_params: retrieve the codec parameters, mandatory * @set_metadata: Set the metadata values for a stream - * @get_metadata: retreives the requested metadata values from stream + * @get_metadata: retrieves the requested metadata values from stream * @trigger: Trigger operations like start, pause, resume, drain, stop. * This callback is mandatory * @pointer: Retrieve current h/w pointer information. Mandatory diff --git a/include/sound/control.h b/include/sound/control.h index 75f3054023f7..95aad6d3fd1a 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -227,7 +227,7 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) * Add a virtual slave control to the given master. * Unlike snd_ctl_add_slave(), the element added via this function * is supposed to have volatile values, and get callback is called - * at each time quried from the master. + * at each time queried from the master. * * When the control peeks the hardware values directly and the value * can be changed by other means than the put callback of the element, diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..cf0bb156d6da 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1469,7 +1469,7 @@ static inline struct snd_soc_codec *snd_soc_kcontrol_codec( } /** - * snd_soc_kcontrol_platform() - Returns the platform that registerd the control + * snd_soc_kcontrol_platform() - Returns the platform that registered the control * @kcontrol: The control for which to get the platform * * Note: This function will only work correctly if the control has been diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 22ed8cb7800b..e00d8cbfc628 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -75,7 +75,7 @@ struct snd_compr_tstamp { /** * struct snd_compr_avail - avail descriptor * @avail: Number of bytes available in ring buffer for writing/reading - * @tstamp: timestamp infomation + * @tstamp: timestamp information */ struct snd_compr_avail { __u64 avail; diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 6542c4083594..fba365a78390 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -289,7 +289,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel); * * The function should usually be called from the pcm open callback. Note that * this function will use private_data field of the substream's runtime. So it - * is not availabe to your pcm driver implementation. + * is not available to your pcm driver implementation. */ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, struct dma_chan *chan) @@ -328,7 +328,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); * This function will request a DMA channel using the passed filter function and * data. The function should usually be called from the pcm open callback. Note * that this function will use private_data field of the substream's runtime. So - * it is not availabe to your pcm driver implementation. + * it is not available to your pcm driver implementation. */ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data) -- GitLab From 0a240339a8deeb13a19043389bba4285a6c0592e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Nov 2014 00:42:09 +0100 Subject: [PATCH 0159/1910] quota: Make VFS quotas use new interface for getting quota info Create new internal interface for getting information about quota which contains everything needed for both VFS quotas and XFS quotas. Make VFS use this and hook it up to Q_GETINFO. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/ext3/super.c | 2 +- fs/ext4/super.c | 2 +- fs/quota/dquot.c | 41 ++++++++++++++++++++++++++-------------- fs/quota/quota.c | 25 ++++++++++++++++++++---- fs/reiserfs/super.c | 2 +- include/linux/quota.h | 33 +++++++++++++++++++++++++++++++- include/linux/quotaops.h | 2 +- 7 files changed, 84 insertions(+), 23 deletions(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index d4dbf3c259b3..f037b4b27300 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -789,7 +789,7 @@ static const struct quotactl_ops ext3_qctl_operations = { .quota_on = ext3_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e061e66c8280..d348c7d29d80 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1076,7 +1076,7 @@ static const struct quotactl_ops ext4_qctl_operations = { .quota_on = ext4_quota_on, .quota_off = ext4_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 0ccd4ba3a246..cf4edd87e854 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2614,26 +2614,39 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid qid, EXPORT_SYMBOL(dquot_set_dqblk); /* Generic routine for getting common part of quota file information */ -int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int dquot_get_state(struct super_block *sb, struct qc_state *state) { struct mem_dqinfo *mi; + struct qc_type_state *tstate; + struct quota_info *dqopt = sb_dqopt(sb); + int type; mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); - if (!sb_has_quota_active(sb, type)) { - mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); - return -ESRCH; + memset(state, 0, sizeof(*state)); + for (type = 0; type < MAXQUOTAS; type++) { + if (!sb_has_quota_active(sb, type)) + continue; + tstate = state->s_state + type; + mi = sb_dqopt(sb)->info + type; + tstate->flags = QCI_ACCT_ENABLED; + spin_lock(&dq_data_lock); + if (mi->dqi_flags & DQF_SYS_FILE) + tstate->flags |= QCI_SYSFILE; + if (mi->dqi_flags & DQF_ROOT_SQUASH) + tstate->flags |= QCI_ROOT_SQUASH; + if (sb_has_quota_limits_enabled(sb, type)) + tstate->flags |= QCI_LIMITS_ENFORCED; + tstate->spc_timelimit = mi->dqi_bgrace; + tstate->ino_timelimit = mi->dqi_igrace; + tstate->ino = dqopt->files[type]->i_ino; + tstate->blocks = dqopt->files[type]->i_blocks; + tstate->nextents = 1; /* We don't know... */ + spin_unlock(&dq_data_lock); } - mi = sb_dqopt(sb)->info + type; - spin_lock(&dq_data_lock); - ii->dqi_bgrace = mi->dqi_bgrace; - ii->dqi_igrace = mi->dqi_igrace; - ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK; - ii->dqi_valid = IIF_ALL; - spin_unlock(&dq_data_lock); mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); return 0; } -EXPORT_SYMBOL(dquot_get_dqinfo); +EXPORT_SYMBOL(dquot_get_state); /* Generic routine for setting common part of quota file information */ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) @@ -2677,7 +2690,7 @@ const struct quotactl_ops dquot_quotactl_ops = { .quota_on = dquot_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk @@ -2688,7 +2701,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = { .quota_enable = dquot_quota_enable, .quota_disable = dquot_quota_disable, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk diff --git a/fs/quota/quota.c b/fs/quota/quota.c index d14a799c7785..00d50fca1005 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -118,13 +118,30 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr) static int quota_getinfo(struct super_block *sb, int type, void __user *addr) { - struct if_dqinfo info; + struct qc_state state; + struct qc_type_state *tstate; + struct if_dqinfo uinfo; int ret; - if (!sb->s_qcop->get_info) + /* This checks whether qc_state has enough entries... */ + BUILD_BUG_ON(MAXQUOTAS > XQM_MAXQUOTAS); + if (!sb->s_qcop->get_state) return -ENOSYS; - ret = sb->s_qcop->get_info(sb, type, &info); - if (!ret && copy_to_user(addr, &info, sizeof(info))) + ret = sb->s_qcop->get_state(sb, &state); + if (ret) + return ret; + tstate = state.s_state + type; + if (!(tstate->flags & QCI_ACCT_ENABLED)) + return -ESRCH; + memset(&uinfo, 0, sizeof(uinfo)); + uinfo.dqi_bgrace = tstate->spc_timelimit; + uinfo.dqi_igrace = tstate->ino_timelimit; + if (tstate->flags & QCI_SYSFILE) + uinfo.dqi_flags |= DQF_SYS_FILE; + if (tstate->flags & QCI_ROOT_SQUASH) + uinfo.dqi_flags |= DQF_ROOT_SQUASH; + uinfo.dqi_valid = IIF_ALL; + if (!ret && copy_to_user(addr, &uinfo, sizeof(uinfo))) return -EFAULT; return ret; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 71fbbe3e2dab..68b5f182984e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -805,7 +805,7 @@ static const struct quotactl_ops reiserfs_qctl_operations = { .quota_on = reiserfs_quota_on, .quota_off = dquot_quota_off, .quota_sync = dquot_quota_sync, - .get_info = dquot_get_dqinfo, + .get_state = dquot_get_state, .set_info = dquot_set_dqinfo, .get_dqblk = dquot_get_dqblk, .set_dqblk = dquot_set_dqblk, diff --git a/include/linux/quota.h b/include/linux/quota.h index d534e8ed308a..6ecac0f3b2ca 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -366,6 +366,37 @@ struct qc_dqblk { #define QC_RT_SPACE (1<<14) #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE) +#define QCI_SYSFILE (1 << 0) /* Quota file is hidden from userspace */ +#define QCI_ROOT_SQUASH (1 << 1) /* Root squash turned on */ +#define QCI_ACCT_ENABLED (1 << 2) /* Quota accounting enabled */ +#define QCI_LIMITS_ENFORCED (1 << 3) /* Quota limits enforced */ + +/* Structures for communicating via ->get_state */ +struct qc_type_state { + unsigned int flags; /* Flags QCI_* */ + unsigned int spc_timelimit; /* Time after which space softlimit is + * enforced */ + unsigned int ino_timelimit; /* Ditto for inode softlimit */ + unsigned int rt_spc_timelimit; /* Ditto for real-time space */ + unsigned int spc_warnlimit; /* Limit for number of space warnings */ + unsigned int ino_warnlimit; /* Ditto for inodes */ + unsigned int rt_spc_warnlimit; /* Ditto for real-time space */ + unsigned long long ino; /* Inode number of quota file */ + blkcnt_t blocks; /* Number of 512-byte blocks in the file */ + blkcnt_t nextents; /* Number of extents in the file */ +}; + +struct qc_state { + unsigned int s_incoredqs; /* Number of dquots in core */ + /* + * Per quota type information. The array should really have + * max(MAXQUOTAS, XQM_MAXQUOTAS) entries. BUILD_BUG_ON in + * quota_getinfo() makes sure XQM_MAXQUOTAS is large enough. Once VFS + * supports project quotas, this can be changed to MAXQUOTAS + */ + struct qc_type_state s_state[XQM_MAXQUOTAS]; +}; + /* Operations handling requests from userspace */ struct quotactl_ops { int (*quota_on)(struct super_block *, int, int, struct path *); @@ -373,10 +404,10 @@ struct quotactl_ops { int (*quota_enable)(struct super_block *, unsigned int); int (*quota_disable)(struct super_block *, unsigned int); int (*quota_sync)(struct super_block *, int); - int (*get_info)(struct super_block *, int, struct if_dqinfo *); int (*set_info)(struct super_block *, int, struct if_dqinfo *); int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); + int (*get_state)(struct super_block *, struct qc_state *); int (*get_xstate)(struct super_block *, struct fs_quota_stat *); int (*get_xstatev)(struct super_block *, struct fs_quota_statv *); int (*rm_xquota)(struct super_block *, unsigned int); diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index df73258cca47..6509a29523e2 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -95,7 +95,7 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name, int dquot_quota_off(struct super_block *sb, int type); int dquot_writeback_dquots(struct super_block *sb, int type); int dquot_quota_sync(struct super_block *sb, int type); -int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); +int dquot_get_state(struct super_block *sb, struct qc_state *state); int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); int dquot_get_dqblk(struct super_block *sb, struct kqid id, struct qc_dqblk *di); -- GitLab From bc230e4a2326e30476092ed967fced0e43667c82 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Nov 2014 16:17:45 +0100 Subject: [PATCH 0160/1910] quota: Wire up Q_GETXSTATE and Q_GETXSTATV calls to work with ->get_state Add appropriate conversion functions so that filesystems supporting ->get_state() method can be queried using Q_GETXSTATE and Q_GETXSTATV calls. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/quota/quota.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 4 deletions(-) diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 00d50fca1005..83939ff4c444 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -269,25 +269,152 @@ static int quota_disable(struct super_block *sb, void __user *addr) return sb->s_qcop->quota_disable(sb, flags); } +static int quota_state_to_flags(struct qc_state *state) +{ + int flags = 0; + + if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_UDQ_ACCT; + if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_UDQ_ENFD; + if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_GDQ_ACCT; + if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_GDQ_ENFD; + if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) + flags |= FS_QUOTA_PDQ_ACCT; + if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED) + flags |= FS_QUOTA_PDQ_ENFD; + return flags; +} + +static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs) +{ + int type; + struct qc_state state; + int ret; + + ret = sb->s_qcop->get_state(sb, &state); + if (ret < 0) + return ret; + + memset(fqs, 0, sizeof(*fqs)); + fqs->qs_version = FS_QSTAT_VERSION; + fqs->qs_flags = quota_state_to_flags(&state); + /* No quota enabled? */ + if (!fqs->qs_flags) + return -ENOSYS; + fqs->qs_incoredqs = state.s_incoredqs; + /* + * GETXSTATE quotactl has space for just one set of time limits so + * report them for the first enabled quota type + */ + for (type = 0; type < XQM_MAXQUOTAS; type++) + if (state.s_state[type].flags & QCI_ACCT_ENABLED) + break; + BUG_ON(type == XQM_MAXQUOTAS); + fqs->qs_btimelimit = state.s_state[type].spc_timelimit; + fqs->qs_itimelimit = state.s_state[type].ino_timelimit; + fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; + fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; + fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; + if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; + fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; + fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; + } + if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; + fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; + } + if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { + /* + * Q_XGETQSTAT doesn't have room for both group and project + * quotas. So, allow the project quota values to be copied out + * only if there is no group quota information available. + */ + if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) { + fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino; + fqs->qs_gquota.qfs_nblks = + state.s_state[PRJQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = + state.s_state[PRJQUOTA].nextents; + } + } + return 0; +} + static int quota_getxstate(struct super_block *sb, void __user *addr) { struct fs_quota_stat fqs; int ret; - if (!sb->s_qcop->get_xstate) + if (!sb->s_qcop->get_xstate && !sb->s_qcop->get_state) return -ENOSYS; - ret = sb->s_qcop->get_xstate(sb, &fqs); + if (sb->s_qcop->get_state) + ret = quota_getstate(sb, &fqs); + else + ret = sb->s_qcop->get_xstate(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; } +static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs) +{ + int type; + struct qc_state state; + int ret; + + ret = sb->s_qcop->get_state(sb, &state); + if (ret < 0) + return ret; + + memset(fqs, 0, sizeof(*fqs)); + fqs->qs_version = FS_QSTAT_VERSION; + fqs->qs_flags = quota_state_to_flags(&state); + /* No quota enabled? */ + if (!fqs->qs_flags) + return -ENOSYS; + fqs->qs_incoredqs = state.s_incoredqs; + /* + * GETXSTATV quotactl has space for just one set of time limits so + * report them for the first enabled quota type + */ + for (type = 0; type < XQM_MAXQUOTAS; type++) + if (state.s_state[type].flags & QCI_ACCT_ENABLED) + break; + BUG_ON(type == XQM_MAXQUOTAS); + fqs->qs_btimelimit = state.s_state[type].spc_timelimit; + fqs->qs_itimelimit = state.s_state[type].ino_timelimit; + fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; + fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; + fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; + if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; + fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; + fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; + } + if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; + fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; + fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; + } + if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { + fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino; + fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks; + fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents; + } + return 0; +} + static int quota_getxstatev(struct super_block *sb, void __user *addr) { struct fs_quota_statv fqs; int ret; - if (!sb->s_qcop->get_xstatev) + if (!sb->s_qcop->get_xstatev && !sb->s_qcop->get_state) return -ENOSYS; memset(&fqs, 0, sizeof(fqs)); @@ -301,7 +428,10 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) default: return -EINVAL; } - ret = sb->s_qcop->get_xstatev(sb, &fqs); + if (sb->s_qcop->get_state) + ret = quota_getstatev(sb, &fqs); + else + ret = sb->s_qcop->get_xstatev(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; -- GitLab From 5d3684c2823bcf14a14bc7117c56c592f27815b9 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Nov 2014 12:03:59 +0100 Subject: [PATCH 0161/1910] xfs: Convert to using ->get_state callback Convert xfs to use ->get_state callback instead of ->get_xstate and ->get_xstatev. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/xfs/xfs_qm.h | 4 - fs/xfs/xfs_qm_syscalls.c | 176 --------------------------------------- fs/xfs/xfs_quotaops.c | 96 +++++++++++++++------ 3 files changed, 71 insertions(+), 205 deletions(-) diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index 0d4d3590cf85..996a04064894 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h @@ -168,10 +168,6 @@ extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t, uint, struct qc_dqblk *); extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint, struct qc_dqblk *); -extern int xfs_qm_scall_getqstat(struct xfs_mount *, - struct fs_quota_stat *); -extern int xfs_qm_scall_getqstatv(struct xfs_mount *, - struct fs_quota_statv *); extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint); extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint); diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 9b965db45800..9a25c9275fb3 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -38,7 +38,6 @@ STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, uint); -STATIC uint xfs_qm_export_flags(uint); /* * Turn off quota accounting and/or enforcement for all udquots and/or @@ -389,159 +388,6 @@ xfs_qm_scall_quotaon( return 0; } - -/* - * Return quota status information, such as uquota-off, enforcements, etc. - * for Q_XGETQSTAT command. - */ -int -xfs_qm_scall_getqstat( - struct xfs_mount *mp, - struct fs_quota_stat *out) -{ - struct xfs_quotainfo *q = mp->m_quotainfo; - struct xfs_inode *uip = NULL; - struct xfs_inode *gip = NULL; - struct xfs_inode *pip = NULL; - bool tempuqip = false; - bool tempgqip = false; - bool temppqip = false; - - memset(out, 0, sizeof(fs_quota_stat_t)); - - out->qs_version = FS_QSTAT_VERSION; - out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & - (XFS_ALL_QUOTA_ACCT| - XFS_ALL_QUOTA_ENFD)); - uip = q->qi_uquotaip; - gip = q->qi_gquotaip; - pip = q->qi_pquotaip; - if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, - 0, 0, &uip) == 0) - tempuqip = true; - } - if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, - 0, 0, &gip) == 0) - tempgqip = true; - } - /* - * Q_XGETQSTAT doesn't have room for both group and project quotas. - * So, allow the project quota values to be copied out only if - * there is no group quota information available. - */ - if (!gip) { - if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, - 0, 0, &pip) == 0) - temppqip = true; - } - } else - pip = NULL; - if (uip) { - out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; - out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; - out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; - if (tempuqip) - IRELE(uip); - } - - if (gip) { - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; - if (tempgqip) - IRELE(gip); - } - if (pip) { - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = pip->i_d.di_nextents; - if (temppqip) - IRELE(pip); - } - out->qs_incoredqs = q->qi_dquots; - out->qs_btimelimit = q->qi_btimelimit; - out->qs_itimelimit = q->qi_itimelimit; - out->qs_rtbtimelimit = q->qi_rtbtimelimit; - out->qs_bwarnlimit = q->qi_bwarnlimit; - out->qs_iwarnlimit = q->qi_iwarnlimit; - - return 0; -} - -/* - * Return quota status information, such as uquota-off, enforcements, etc. - * for Q_XGETQSTATV command, to support separate project quota field. - */ -int -xfs_qm_scall_getqstatv( - struct xfs_mount *mp, - struct fs_quota_statv *out) -{ - struct xfs_quotainfo *q = mp->m_quotainfo; - struct xfs_inode *uip = NULL; - struct xfs_inode *gip = NULL; - struct xfs_inode *pip = NULL; - bool tempuqip = false; - bool tempgqip = false; - bool temppqip = false; - - out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & - (XFS_ALL_QUOTA_ACCT| - XFS_ALL_QUOTA_ENFD)); - out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; - out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; - out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino; - - uip = q->qi_uquotaip; - gip = q->qi_gquotaip; - pip = q->qi_pquotaip; - if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, - 0, 0, &uip) == 0) - tempuqip = true; - } - if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, - 0, 0, &gip) == 0) - tempgqip = true; - } - if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, - 0, 0, &pip) == 0) - temppqip = true; - } - if (uip) { - out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; - out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; - if (tempuqip) - IRELE(uip); - } - - if (gip) { - out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; - out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; - if (tempgqip) - IRELE(gip); - } - if (pip) { - out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks; - out->qs_pquota.qfs_nextents = pip->i_d.di_nextents; - if (temppqip) - IRELE(pip); - } - out->qs_incoredqs = q->qi_dquots; - out->qs_btimelimit = q->qi_btimelimit; - out->qs_itimelimit = q->qi_itimelimit; - out->qs_rtbtimelimit = q->qi_rtbtimelimit; - out->qs_bwarnlimit = q->qi_bwarnlimit; - out->qs_iwarnlimit = q->qi_iwarnlimit; - - return 0; -} - #define XFS_QC_MASK \ (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK) @@ -873,28 +719,6 @@ xfs_qm_scall_getquota( return error; } -STATIC uint -xfs_qm_export_flags( - uint flags) -{ - uint uflags; - - uflags = 0; - if (flags & XFS_UQUOTA_ACCT) - uflags |= FS_QUOTA_UDQ_ACCT; - if (flags & XFS_GQUOTA_ACCT) - uflags |= FS_QUOTA_GDQ_ACCT; - if (flags & XFS_PQUOTA_ACCT) - uflags |= FS_QUOTA_PDQ_ACCT; - if (flags & XFS_UQUOTA_ENFD) - uflags |= FS_QUOTA_UDQ_ENFD; - if (flags & XFS_GQUOTA_ENFD) - uflags |= FS_QUOTA_GDQ_ENFD; - if (flags & XFS_PQUOTA_ENFD) - uflags |= FS_QUOTA_PDQ_ENFD; - return uflags; -} - STATIC int xfs_dqrele_inode( diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index 6923905ab33d..5775acb0589b 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -23,45 +23,92 @@ #include "xfs_inode.h" #include "xfs_quota.h" #include "xfs_trans.h" +#include "xfs_trace.h" +#include "xfs_icache.h" #include "xfs_qm.h" #include -STATIC int -xfs_quota_type(int type) +static void +xfs_qm_fill_state( + struct qc_type_state *tstate, + struct xfs_mount *mp, + struct xfs_inode *ip, + xfs_ino_t ino) { - switch (type) { - case USRQUOTA: - return XFS_DQ_USER; - case GRPQUOTA: - return XFS_DQ_GROUP; - default: - return XFS_DQ_PROJ; + struct xfs_quotainfo *q = mp->m_quotainfo; + bool tempqip = false; + + tstate->ino = ino; + if (!ip && ino == NULLFSINO) + return; + if (!ip) { + if (xfs_iget(mp, NULL, ino, 0, 0, &ip)) + return; + tempqip = true; } + tstate->flags |= QCI_SYSFILE; + tstate->blocks = ip->i_d.di_nblocks; + tstate->nextents = ip->i_d.di_nextents; + tstate->spc_timelimit = q->qi_btimelimit; + tstate->ino_timelimit = q->qi_itimelimit; + tstate->rt_spc_timelimit = q->qi_rtbtimelimit; + tstate->spc_warnlimit = q->qi_bwarnlimit; + tstate->ino_warnlimit = q->qi_iwarnlimit; + tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit; + if (tempqip) + IRELE(ip); } -STATIC int -xfs_fs_get_xstate( +/* + * Return quota status information, such as enforcements, quota file inode + * numbers etc. + */ +static int +xfs_fs_get_quota_state( struct super_block *sb, - struct fs_quota_stat *fqs) + struct qc_state *state) { - struct xfs_mount *mp = XFS_M(sb); + struct xfs_mount *mp = XFS_M(sb); + struct xfs_quotainfo *q = mp->m_quotainfo; + memset(state, 0, sizeof(*state)); if (!XFS_IS_QUOTA_RUNNING(mp)) - return -ENOSYS; - return xfs_qm_scall_getqstat(mp, fqs); + return 0; + state->s_incoredqs = q->qi_dquots; + if (XFS_IS_UQUOTA_RUNNING(mp)) + state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_UQUOTA_ENFORCED(mp)) + state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; + if (XFS_IS_GQUOTA_RUNNING(mp)) + state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_GQUOTA_ENFORCED(mp)) + state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; + if (XFS_IS_PQUOTA_RUNNING(mp)) + state->s_state[PRJQUOTA].flags |= QCI_ACCT_ENABLED; + if (XFS_IS_PQUOTA_ENFORCED(mp)) + state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED; + + xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip, + mp->m_sb.sb_uquotino); + xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip, + mp->m_sb.sb_gquotino); + xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip, + mp->m_sb.sb_pquotino); + return 0; } STATIC int -xfs_fs_get_xstatev( - struct super_block *sb, - struct fs_quota_statv *fqs) +xfs_quota_type(int type) { - struct xfs_mount *mp = XFS_M(sb); - - if (!XFS_IS_QUOTA_RUNNING(mp)) - return -ENOSYS; - return xfs_qm_scall_getqstatv(mp, fqs); + switch (type) { + case USRQUOTA: + return XFS_DQ_USER; + case GRPQUOTA: + return XFS_DQ_GROUP; + default: + return XFS_DQ_PROJ; + } } static unsigned int @@ -178,8 +225,7 @@ xfs_fs_set_dqblk( } const struct quotactl_ops xfs_quotactl_operations = { - .get_xstatev = xfs_fs_get_xstatev, - .get_xstate = xfs_fs_get_xstate, + .get_state = xfs_fs_get_quota_state, .quota_enable = xfs_quota_enable, .quota_disable = xfs_quota_disable, .rm_xquota = xfs_fs_rm_xquota, -- GitLab From e54b2e2d723f138df35de0bf1f8262da116ca6fa Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Nov 2014 16:41:07 +0100 Subject: [PATCH 0162/1910] gfs2: Convert to using ->get_state callback Convert gfs2 to use ->get_state callback instead of ->get_xstate. Acked-by: Bob Peterson Signed-off-by: Jan Kara --- fs/gfs2/quota.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 3aa17d4d1cfc..fa54cbf4c866 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1468,32 +1468,34 @@ int gfs2_quotad(void *data) return 0; } -static int gfs2_quota_get_xstate(struct super_block *sb, - struct fs_quota_stat *fqs) +static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state) { struct gfs2_sbd *sdp = sb->s_fs_info; - memset(fqs, 0, sizeof(struct fs_quota_stat)); - fqs->qs_version = FS_QSTAT_VERSION; + memset(state, 0, sizeof(*state)); switch (sdp->sd_args.ar_quota) { case GFS2_QUOTA_ON: - fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD); + state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; + state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; /*FALLTHRU*/ case GFS2_QUOTA_ACCOUNT: - fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT); + state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED | + QCI_SYSFILE; + state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED | + QCI_SYSFILE; break; case GFS2_QUOTA_OFF: break; } - if (sdp->sd_quota_inode) { - fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; - fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; + state->s_state[USRQUOTA].ino = + GFS2_I(sdp->sd_quota_inode)->i_no_addr; + state->s_state[USRQUOTA].blocks = sdp->sd_quota_inode->i_blocks; } - fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ - fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ - fqs->qs_incoredqs = list_lru_count(&gfs2_qd_lru); + state->s_state[USRQUOTA].nextents = 1; /* unsupported */ + state->s_state[GRPQUOTA] = state->s_state[USRQUOTA]; + state->s_incoredqs = list_lru_count(&gfs2_qd_lru); return 0; } @@ -1638,7 +1640,7 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid, const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, - .get_xstate = gfs2_quota_get_xstate, + .get_state = gfs2_quota_get_state, .get_dqblk = gfs2_get_dqblk, .set_dqblk = gfs2_set_dqblk, }; -- GitLab From 59b6ba699043e0f55d4057cf2ae79d9c1171bc58 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Nov 2014 16:44:58 +0100 Subject: [PATCH 0163/1910] quota: Remove ->get_xstate and ->get_xstatev callbacks These callbacks are now unused. Remove them. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/quota/quota.c | 14 ++++---------- include/linux/quota.h | 2 -- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 83939ff4c444..20d11cd21247 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -350,12 +350,9 @@ static int quota_getxstate(struct super_block *sb, void __user *addr) struct fs_quota_stat fqs; int ret; - if (!sb->s_qcop->get_xstate && !sb->s_qcop->get_state) + if (!sb->s_qcop->get_state) return -ENOSYS; - if (sb->s_qcop->get_state) - ret = quota_getstate(sb, &fqs); - else - ret = sb->s_qcop->get_xstate(sb, &fqs); + ret = quota_getstate(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; @@ -414,7 +411,7 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) struct fs_quota_statv fqs; int ret; - if (!sb->s_qcop->get_xstatev && !sb->s_qcop->get_state) + if (!sb->s_qcop->get_state) return -ENOSYS; memset(&fqs, 0, sizeof(fqs)); @@ -428,10 +425,7 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) default: return -EINVAL; } - if (sb->s_qcop->get_state) - ret = quota_getstatev(sb, &fqs); - else - ret = sb->s_qcop->get_xstatev(sb, &fqs); + ret = quota_getstatev(sb, &fqs); if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; return ret; diff --git a/include/linux/quota.h b/include/linux/quota.h index 6ecac0f3b2ca..a07f2ed25284 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -408,8 +408,6 @@ struct quotactl_ops { int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*get_state)(struct super_block *, struct qc_state *); - int (*get_xstate)(struct super_block *, struct fs_quota_stat *); - int (*get_xstatev)(struct super_block *, struct fs_quota_statv *); int (*rm_xquota)(struct super_block *, unsigned int); }; -- GitLab From 5eacb2ac029161d94969a511e0adf7dca28cda1f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 16 Dec 2014 12:03:51 +0100 Subject: [PATCH 0164/1910] quota: Make ->set_info use structure with neccesary info to VFS and XFS Change ->set_info to take new qc_info structure which contains all the necessary information both for XFS and VFS. Convert Q_SETINFO handler to use this structure. Signed-off-by: Jan Kara --- fs/quota/dquot.c | 27 ++++++++++++++++----------- fs/quota/quota.c | 21 ++++++++++++++++++++- include/linux/quota.h | 21 +++++++++++++++++++-- include/linux/quotaops.h | 2 +- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index cf4edd87e854..f37b74eab807 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2649,33 +2649,38 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state) EXPORT_SYMBOL(dquot_get_state); /* Generic routine for setting common part of quota file information */ -int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii) { struct mem_dqinfo *mi; int err = 0; + if ((ii->i_fieldmask & QC_WARNS_MASK) || + (ii->i_fieldmask & QC_RT_SPC_TIMER)) + return -EINVAL; mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); if (!sb_has_quota_active(sb, type)) { err = -ESRCH; goto out; } mi = sb_dqopt(sb)->info + type; - if (ii->dqi_valid & IIF_FLAGS) { - if (ii->dqi_flags & ~DQF_SETINFO_MASK || - (ii->dqi_flags & DQF_ROOT_SQUASH && + if (ii->i_fieldmask & QC_FLAGS) { + if ((ii->i_flags & QCI_ROOT_SQUASH && mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) { err = -EINVAL; goto out; } } spin_lock(&dq_data_lock); - if (ii->dqi_valid & IIF_BGRACE) - mi->dqi_bgrace = ii->dqi_bgrace; - if (ii->dqi_valid & IIF_IGRACE) - mi->dqi_igrace = ii->dqi_igrace; - if (ii->dqi_valid & IIF_FLAGS) - mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) | - (ii->dqi_flags & DQF_SETINFO_MASK); + if (ii->i_fieldmask & QC_SPC_TIMER) + mi->dqi_bgrace = ii->i_spc_timelimit; + if (ii->i_fieldmask & QC_INO_TIMER) + mi->dqi_igrace = ii->i_ino_timelimit; + if (ii->i_fieldmask & QC_FLAGS) { + if (ii->i_flags & QCI_ROOT_SQUASH) + mi->dqi_flags |= DQF_ROOT_SQUASH; + else + mi->dqi_flags &= ~DQF_ROOT_SQUASH; + } spin_unlock(&dq_data_lock); mark_info_dirty(sb, type); /* Force write to disk */ diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 20d11cd21247..741d5a178268 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -149,12 +149,31 @@ static int quota_getinfo(struct super_block *sb, int type, void __user *addr) static int quota_setinfo(struct super_block *sb, int type, void __user *addr) { struct if_dqinfo info; + struct qc_info qinfo; if (copy_from_user(&info, addr, sizeof(info))) return -EFAULT; if (!sb->s_qcop->set_info) return -ENOSYS; - return sb->s_qcop->set_info(sb, type, &info); + if (info.dqi_valid & ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE)) + return -EINVAL; + memset(&qinfo, 0, sizeof(qinfo)); + if (info.dqi_valid & IIF_FLAGS) { + if (info.dqi_flags & ~DQF_SETINFO_MASK) + return -EINVAL; + if (info.dqi_flags & DQF_ROOT_SQUASH) + qinfo.i_flags |= QCI_ROOT_SQUASH; + qinfo.i_fieldmask |= QC_FLAGS; + } + if (info.dqi_valid & IIF_BGRACE) { + qinfo.i_spc_timelimit = info.dqi_bgrace; + qinfo.i_fieldmask |= QC_SPC_TIMER; + } + if (info.dqi_valid & IIF_IGRACE) { + qinfo.i_ino_timelimit = info.dqi_igrace; + qinfo.i_fieldmask |= QC_INO_TIMER; + } + return sb->s_qcop->set_info(sb, type, &qinfo); } static inline qsize_t qbtos(qsize_t blocks) diff --git a/include/linux/quota.h b/include/linux/quota.h index a07f2ed25284..3d521199a0bd 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -344,7 +344,10 @@ struct qc_dqblk { int d_rt_spc_warns; /* # warnings issued wrt RT space */ }; -/* Field specifiers for ->set_dqblk() in struct qc_dqblk */ +/* + * Field specifiers for ->set_dqblk() in struct qc_dqblk and also for + * ->set_info() in struct qc_info + */ #define QC_INO_SOFT (1<<0) #define QC_INO_HARD (1<<1) #define QC_SPC_SOFT (1<<2) @@ -365,6 +368,7 @@ struct qc_dqblk { #define QC_INO_COUNT (1<<13) #define QC_RT_SPACE (1<<14) #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE) +#define QC_FLAGS (1<<15) #define QCI_SYSFILE (1 << 0) /* Quota file is hidden from userspace */ #define QCI_ROOT_SQUASH (1 << 1) /* Root squash turned on */ @@ -397,6 +401,19 @@ struct qc_state { struct qc_type_state s_state[XQM_MAXQUOTAS]; }; +/* Structure for communicating via ->set_info */ +struct qc_info { + int i_fieldmask; /* mask of fields to change in ->set_info() */ + unsigned int i_flags; /* Flags QCI_* */ + unsigned int i_spc_timelimit; /* Time after which space softlimit is + * enforced */ + unsigned int i_ino_timelimit; /* Ditto for inode softlimit */ + unsigned int i_rt_spc_timelimit;/* Ditto for real-time space */ + unsigned int i_spc_warnlimit; /* Limit for number of space warnings */ + unsigned int i_ino_warnlimit; /* Limit for number of inode warnings */ + unsigned int i_rt_spc_warnlimit; /* Ditto for real-time space */ +}; + /* Operations handling requests from userspace */ struct quotactl_ops { int (*quota_on)(struct super_block *, int, int, struct path *); @@ -404,7 +421,7 @@ struct quotactl_ops { int (*quota_enable)(struct super_block *, unsigned int); int (*quota_disable)(struct super_block *, unsigned int); int (*quota_sync)(struct super_block *, int); - int (*set_info)(struct super_block *, int, struct if_dqinfo *); + int (*set_info)(struct super_block *, int, struct qc_info *); int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*get_state)(struct super_block *, struct qc_state *); diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 6509a29523e2..9f4b07ba9e8c 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -96,7 +96,7 @@ int dquot_quota_off(struct super_block *sb, int type); int dquot_writeback_dquots(struct super_block *sb, int type); int dquot_quota_sync(struct super_block *sb, int type); int dquot_get_state(struct super_block *sb, struct qc_state *state); -int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); +int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); int dquot_get_dqblk(struct super_block *sb, struct kqid id, struct qc_dqblk *di); int dquot_set_dqblk(struct super_block *sb, struct kqid id, -- GitLab From c14cad9eed11343014f73aae4a77278239b201b8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 16 Dec 2014 13:07:45 +0100 Subject: [PATCH 0165/1910] xfs: Add support for Q_SETINFO Add support to XFS so that time limits can be set through Q_SETINFO quotactl. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/xfs/xfs_quotaops.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index 5775acb0589b..7795e0d01382 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -111,6 +111,42 @@ xfs_quota_type(int type) } } +#define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK) + +/* + * Adjust quota timers & warnings + */ +static int +xfs_fs_set_info( + struct super_block *sb, + int type, + struct qc_info *info) +{ + struct xfs_mount *mp = XFS_M(sb); + struct qc_dqblk newlim; + + if (sb->s_flags & MS_RDONLY) + return -EROFS; + if (!XFS_IS_QUOTA_RUNNING(mp)) + return -ENOSYS; + if (!XFS_IS_QUOTA_ON(mp)) + return -ESRCH; + if (info->i_fieldmask & ~XFS_QC_SETINFO_MASK) + return -EINVAL; + if ((info->i_fieldmask & XFS_QC_SETINFO_MASK) == 0) + return 0; + + newlim.d_fieldmask = info->i_fieldmask; + newlim.d_spc_timer = info->i_spc_timelimit; + newlim.d_ino_timer = info->i_ino_timelimit; + newlim.d_rt_spc_timer = info->i_rt_spc_timelimit; + newlim.d_ino_warns = info->i_ino_warnlimit; + newlim.d_spc_warns = info->i_spc_warnlimit; + newlim.d_rt_spc_warns = info->i_rt_spc_warnlimit; + + return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), &newlim); +} + static unsigned int xfs_quota_flags(unsigned int uflags) { @@ -226,6 +262,7 @@ xfs_fs_set_dqblk( const struct quotactl_ops xfs_quotactl_operations = { .get_state = xfs_fs_get_quota_state, + .set_info = xfs_fs_set_info, .quota_enable = xfs_quota_enable, .quota_disable = xfs_quota_disable, .rm_xquota = xfs_fs_rm_xquota, -- GitLab From c39fb53b48c851b185c22548153581d78f2acc11 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 16 Dec 2014 16:12:27 +0100 Subject: [PATCH 0166/1910] quota: Hook up Q_XSETQLIM for id 0 to ->set_info Setting timers or warning counts for id 0 via Q_XSETQLIM is used to actually set time limits and warning limits for all users. Hook up ->set_info to this so that VFS quota time limits get set the same way as XFS ones. When doing this Q_XSETQLIM for XFS is effectively split into two independent transactions - one for setting timers and warning limits and one for setting space and inode limits. Although this is inefficient, it is rare enough that it does not matter. Reviewed-by: Christoph Hellwig Signed-off-by: Jan Kara --- fs/quota/quota.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 741d5a178268..86ded7375c21 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -517,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src) dst->d_fieldmask |= QC_RT_SPACE; } +static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst, + struct fs_disk_quota *src) +{ + memset(dst, 0, sizeof(*dst)); + dst->i_spc_timelimit = src->d_btimer; + dst->i_ino_timelimit = src->d_itimer; + dst->i_rt_spc_timelimit = src->d_rtbtimer; + dst->i_ino_warnlimit = src->d_iwarns; + dst->i_spc_warnlimit = src->d_bwarns; + dst->i_rt_spc_warnlimit = src->d_rtbwarns; + if (src->d_fieldmask & FS_DQ_BWARNS) + dst->i_fieldmask |= QC_SPC_WARNS; + if (src->d_fieldmask & FS_DQ_IWARNS) + dst->i_fieldmask |= QC_INO_WARNS; + if (src->d_fieldmask & FS_DQ_RTBWARNS) + dst->i_fieldmask |= QC_RT_SPC_WARNS; + if (src->d_fieldmask & FS_DQ_BTIMER) + dst->i_fieldmask |= QC_SPC_TIMER; + if (src->d_fieldmask & FS_DQ_ITIMER) + dst->i_fieldmask |= QC_INO_TIMER; + if (src->d_fieldmask & FS_DQ_RTBTIMER) + dst->i_fieldmask |= QC_RT_SPC_TIMER; +} + static int quota_setxquota(struct super_block *sb, int type, qid_t id, void __user *addr) { @@ -531,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id, qid = make_kqid(current_user_ns(), type, id); if (!qid_valid(qid)) return -EINVAL; + /* Are we actually setting timer / warning limits for all users? */ + if (from_kqid(&init_user_ns, qid) == 0 && + fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) { + struct qc_info qinfo; + int ret; + + if (!sb->s_qcop->set_info) + return -EINVAL; + copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq); + ret = sb->s_qcop->set_info(sb, type, &qinfo); + if (ret) + return ret; + /* These are already done */ + fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK); + } copy_from_xfs_dqblk(&qdq, &fdq); return sb->s_qcop->set_dqblk(sb, qid, &qdq); } -- GitLab From 33350e6b1833b15cf9c9c4c84d8534ad68b0c7b8 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Tue, 27 Jan 2015 16:03:57 -0500 Subject: [PATCH 0167/1910] Mailbox: Restructure and simplify PCC mailbox code Previously the PCC driver depended on the client side to map the communication space base address. This region was was then used in the PCC driver and the client side. The client side used this region to read and write its data and the PCC driver used it to only write the PCC command. Removing this split simplifies the PCC driver a lot. This patch moves all communication region read/writes to the client side. The PCC clients can now drive the PCC mailbox controller via the mbox_client_txdone() method. Signed-off-by: Ashwin Chaugule --- drivers/mailbox/pcc.c | 122 +++++++++++++----------------------------- 1 file changed, 37 insertions(+), 85 deletions(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 977c814cdf6f..7e91d68a3ac3 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -20,10 +20,35 @@ * shared memory regions as defined in the PCC table entries. The PCC * specification supports a Doorbell mechanism for the PCC clients * to notify the platform about new data. This Doorbell information - * is also specified in each PCC table entry. See pcc_send_data() - * and pcc_tx_done() for basic mode of operation. + * is also specified in each PCC table entry. * - * For more details about PCC, please see the ACPI specification from + * Typical high level flow of operation is: + * + * PCC Reads: + * * Client tries to acquire a channel lock. + * * After it is acquired it writes READ cmd in communication region cmd + * address. + * * Client issues mbox_send_message() which rings the PCC doorbell + * for its PCC channel. + * * If command completes, then client has control over channel and + * it can proceed with its reads. + * * Client releases lock. + * + * PCC Writes: + * * Client tries to acquire channel lock. + * * Client writes to its communication region after it acquires a + * channel lock. + * * Client writes WRITE cmd in communication region cmd address. + * * Client issues mbox_send_message() which rings the PCC doorbell + * for its PCC channel. + * * If command completes, then writes have succeded and it can release + * the channel lock. + * + * There is a Nominal latency defined for each channel which indicates + * how long to wait until a command completes. If command is not complete + * the client needs to retry or assume failure. + * + * For more details about PCC, please see the ACPI specification from * http://www.uefi.org/ACPIv5.1 Section 14. * * This file implements PCC as a Mailbox controller and allows for PCC @@ -42,8 +67,6 @@ #include "mailbox.h" #define MAX_PCC_SUBSPACES 256 -#define PCCS_SS_SIG_MAGIC 0x50434300 -#define PCC_CMD_COMPLETE 0x1 static struct mbox_chan *pcc_mbox_channels; @@ -70,23 +93,6 @@ static struct mbox_chan *get_pcc_channel(int id) return pcc_chan; } -/** - * get_subspace_id - Given a Mailbox channel, find out the - * PCC subspace id. - * @chan: Pointer to Mailbox Channel from which we want - * the index. - * Return: Errno if not found, else positive index number. - */ -static int get_subspace_id(struct mbox_chan *chan) -{ - unsigned int id = chan - pcc_mbox_channels; - - if (id < 0 || id > pcc_mbox_ctrl.num_chans) - return -ENOENT; - - return id; -} - /** * pcc_mbox_request_channel - PCC clients call this function to * request a pointer to their PCC subspace, from which they @@ -117,7 +123,7 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, chan = get_pcc_channel(subspace_id); if (!chan || chan->cl) { - dev_err(dev, "%s: PCC mailbox not free\n", __func__); + dev_err(dev, "Channel not found for idx: %d\n", subspace_id); return ERR_PTR(-EBUSY); } @@ -161,81 +167,30 @@ void pcc_mbox_free_channel(struct mbox_chan *chan) EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); /** - * pcc_tx_done - Callback from Mailbox controller code to - * check if PCC message transmission completed. - * @chan: Pointer to Mailbox channel on which previous - * transmission occurred. - * - * Return: TRUE if succeeded. - */ -static bool pcc_tx_done(struct mbox_chan *chan) -{ - struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv; - struct acpi_pcct_shared_memory *generic_comm_base = - (struct acpi_pcct_shared_memory *) pcct_ss->base_address; - u16 cmd_delay = pcct_ss->latency; - unsigned int retries = 0; - - /* Try a few times while waiting for platform to consume */ - while (!(readw_relaxed(&generic_comm_base->status) - & PCC_CMD_COMPLETE)) { - - if (retries++ < 5) - udelay(cmd_delay); - else { - /* - * If the remote is dead, this will cause the Mbox - * controller to timeout after mbox client.tx_tout - * msecs. - */ - pr_err("PCC platform did not respond.\n"); - return false; - } - } - return true; -} - -/** - * pcc_send_data - Called from Mailbox Controller code to finally - * transmit data over channel. + * pcc_send_data - Called from Mailbox Controller code. Used + * here only to ring the channel doorbell. The PCC client + * specific read/write is done in the client driver in + * order to maintain atomicity over PCC channel once + * OS has control over it. See above for flow of operations. * @chan: Pointer to Mailbox channel over which to send data. - * @data: Actual data to be written over channel. + * @data: Client specific data written over channel. Used here + * only for debug after PCC transaction completes. * * Return: Err if something failed else 0 for success. */ static int pcc_send_data(struct mbox_chan *chan, void *data) { struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv; - struct acpi_pcct_shared_memory *generic_comm_base = - (struct acpi_pcct_shared_memory *) pcct_ss->base_address; struct acpi_generic_address doorbell; u64 doorbell_preserve; u64 doorbell_val; u64 doorbell_write; - u16 cmd = *(u16 *) data; - u16 ss_idx = -1; - - ss_idx = get_subspace_id(chan); - - if (ss_idx < 0) { - pr_err("Invalid Subspace ID from PCC client\n"); - return -EINVAL; - } doorbell = pcct_ss->doorbell_register; doorbell_preserve = pcct_ss->preserve_mask; doorbell_write = pcct_ss->write_mask; - /* Write to the shared comm region. */ - writew(cmd, &generic_comm_base->command); - - /* Write Subspace MAGIC value so platform can identify destination. */ - writel((PCCS_SS_SIG_MAGIC | ss_idx), &generic_comm_base->signature); - - /* Flip CMD COMPLETE bit */ - writew(0, &generic_comm_base->status); - - /* Sync notification from OSPM to Platform. */ + /* Sync notification from OS to Platform. */ acpi_read(&doorbell_val, &doorbell); acpi_write((doorbell_val & doorbell_preserve) | doorbell_write, &doorbell); @@ -245,7 +200,6 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) static struct mbox_chan_ops pcc_chan_ops = { .send_data = pcc_send_data, - .last_tx_done = pcc_tx_done, }; /** @@ -351,8 +305,6 @@ static int pcc_mbox_probe(struct platform_device *pdev) pcc_mbox_ctrl.chans = pcc_mbox_channels; pcc_mbox_ctrl.ops = &pcc_chan_ops; - pcc_mbox_ctrl.txdone_poll = true; - pcc_mbox_ctrl.txpoll_period = 10; pcc_mbox_ctrl.dev = &pdev->dev; pr_info("Registering PCC driver as Mailbox controller\n"); -- GitLab From 8b28c93fe5a55873ce22b7126e84eb59290f8603 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Mar 2015 15:37:01 +0100 Subject: [PATCH 0168/1910] ALSA: usb-audio: Check Marantz/Denon USB DACs in a single place There are three places doing the same check. Let's make them together. Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 753a47de8459..353532b8aee4 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1120,17 +1120,24 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) /* Marantz/Denon USB DACs need a vendor cmd to switch * between PCM and native DSD mode */ +static bool is_marantz_denon_dac(unsigned int id) +{ + switch (id) { + case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ + case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ + case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + return true; + } + return false; +} + int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; int err; - switch (subs->stream->chip->usb_id) { - case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */ - case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ - case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ - + if (is_marantz_denon_dac(subs->stream->chip->usb_id)) { /* First switch to alt set 0, otherwise the mode switch cmd * will not be accepted by the DAC */ @@ -1203,17 +1210,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, /* Marantz/Denon devices with USB DAC functionality need a delay * after each class compliant request */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) && - (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) { - - switch (le16_to_cpu(dev->descriptor.idProduct)) { - case 0x1003: /* Denon DA300-USB */ - case 0x3005: /* Marantz HD-DAC1 */ - case 0x3006: /* Marantz SA-14S1 */ - mdelay(20); - break; - } - } + if (is_marantz_denon_dac(USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct))) + && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); /* Zoom R16/24 needs a tiny delay here, otherwise requests like * get/set frequency return as failed despite actually succeeding. @@ -1268,15 +1268,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, } /* Denon/Marantz devices with USB DAC functionality */ - switch (chip->usb_id) { - case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */ - case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ - case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + if (is_marantz_denon_dac(chip->usb_id)) { if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; - break; - default: - break; } return 0; -- GitLab From 5bcd3b6f639c277ed7fa71f2f8ed6fb072615011 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 12 Feb 2015 12:36:37 +0300 Subject: [PATCH 0169/1910] quota: optimize i_dquot access Remove redundant calls of i_dquot(), keep pointer in local variable. add/remove: 0/0 grow/shrink: 3/7 up/down: 40/-278 (-238) function old new delta __dquot_free_space 734 750 +16 __dquot_alloc_space 484 500 +16 dquot_free_inode 324 332 +8 dquot_drop 82 69 -13 vfs_load_quota_inode 1357 1341 -16 dquot_reclaim_space_nodirty 348 316 -32 dquot_disable 1980 1944 -36 dquot_claim_space_nodirty 354 314 -40 __dquot_drop 125 83 -42 __dquot_initialize 522 423 -99 Signed-off-by: Konstantin Khlebnikov Signed-off-by: Jan Kara --- fs/quota/dquot.c | 63 ++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 0ccd4ba3a246..2112ed33de41 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -900,14 +900,17 @@ static inline struct dquot **i_dquot(struct inode *inode) static int dqinit_needed(struct inode *inode, int type) { + struct dquot * const *dquots; int cnt; if (IS_NOQUOTA(inode)) return 0; + + dquots = i_dquot(inode); if (type != -1) - return !i_dquot(inode)[type]; + return !dquots[type]; for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (!i_dquot(inode)[cnt]) + if (!dquots[cnt]) return 1; return 0; } @@ -970,12 +973,13 @@ static void add_dquot_ref(struct super_block *sb, int type) static void remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { - struct dquot *dquot = i_dquot(inode)[type]; + struct dquot **dquots = i_dquot(inode); + struct dquot *dquot = dquots[type]; - i_dquot(inode)[type] = NULL; if (!dquot) return; + dquots[type] = NULL; if (list_empty(&dquot->dq_free)) { /* * The inode still has reference to dquot so it can't be in the @@ -1389,13 +1393,15 @@ static int dquot_active(const struct inode *inode) static void __dquot_initialize(struct inode *inode, int type) { int cnt, init_needed = 0; - struct dquot *got[MAXQUOTAS]; + struct dquot **dquots, *got[MAXQUOTAS]; struct super_block *sb = inode->i_sb; qsize_t rsv; if (!dquot_active(inode)) return; + dquots = i_dquot(inode); + /* First get references to structures we might need. */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { struct kqid qid; @@ -1407,7 +1413,7 @@ static void __dquot_initialize(struct inode *inode, int type) * we check it without locking here to avoid unnecessary * dqget()/dqput() calls. */ - if (i_dquot(inode)[cnt]) + if (dquots[cnt]) continue; init_needed = 1; @@ -1438,8 +1444,8 @@ static void __dquot_initialize(struct inode *inode, int type) /* We could race with quotaon or dqget() could have failed */ if (!got[cnt]) continue; - if (!i_dquot(inode)[cnt]) { - i_dquot(inode)[cnt] = got[cnt]; + if (!dquots[cnt]) { + dquots[cnt] = got[cnt]; got[cnt] = NULL; /* * Make quota reservation system happy if someone @@ -1447,7 +1453,7 @@ static void __dquot_initialize(struct inode *inode, int type) */ rsv = inode_get_rsv_space(inode); if (unlikely(rsv)) - dquot_resv_space(i_dquot(inode)[cnt], rsv); + dquot_resv_space(dquots[cnt], rsv); } } out_err: @@ -1473,12 +1479,13 @@ EXPORT_SYMBOL(dquot_initialize); static void __dquot_drop(struct inode *inode) { int cnt; + struct dquot **dquots = i_dquot(inode); struct dquot *put[MAXQUOTAS]; spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - put[cnt] = i_dquot(inode)[cnt]; - i_dquot(inode)[cnt] = NULL; + put[cnt] = dquots[cnt]; + dquots[cnt] = NULL; } spin_unlock(&dq_data_lock); dqput_all(put); @@ -1486,6 +1493,7 @@ static void __dquot_drop(struct inode *inode) void dquot_drop(struct inode *inode) { + struct dquot * const *dquots; int cnt; if (IS_NOQUOTA(inode)) @@ -1498,8 +1506,9 @@ void dquot_drop(struct inode *inode) * must assure that nobody can come after the DQUOT_DROP and * add quota pointers back anyway. */ + dquots = i_dquot(inode); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) + if (dquots[cnt]) break; } @@ -1600,8 +1609,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) { int cnt, ret = 0, index; struct dquot_warn warn[MAXQUOTAS]; - struct dquot **dquots = i_dquot(inode); int reserve = flags & DQUOT_SPACE_RESERVE; + struct dquot **dquots; if (!dquot_active(inode)) { inode_incr_space(inode, number, reserve); @@ -1611,6 +1620,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) for (cnt = 0; cnt < MAXQUOTAS; cnt++) warn[cnt].w_type = QUOTA_NL_NOWARN; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1652,13 +1662,14 @@ int dquot_alloc_inode(struct inode *inode) { int cnt, ret = 0, index; struct dquot_warn warn[MAXQUOTAS]; - struct dquot * const *dquots = i_dquot(inode); + struct dquot * const *dquots; if (!dquot_active(inode)) return 0; for (cnt = 0; cnt < MAXQUOTAS; cnt++) warn[cnt].w_type = QUOTA_NL_NOWARN; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1690,6 +1701,7 @@ EXPORT_SYMBOL(dquot_alloc_inode); */ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) { + struct dquot **dquots; int cnt, index; if (!dquot_active(inode)) { @@ -1697,18 +1709,18 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) return 0; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); /* Claim reserved quotas to allocated quotas */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) - dquot_claim_reserved_space(i_dquot(inode)[cnt], - number); + if (dquots[cnt]) + dquot_claim_reserved_space(dquots[cnt], number); } /* Update inode bytes */ inode_claim_rsv_space(inode, number); spin_unlock(&dq_data_lock); - mark_all_dquot_dirty(i_dquot(inode)); + mark_all_dquot_dirty(dquots); srcu_read_unlock(&dquot_srcu, index); return 0; } @@ -1719,6 +1731,7 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty); */ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) { + struct dquot **dquots; int cnt, index; if (!dquot_active(inode)) { @@ -1726,18 +1739,18 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) return; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); /* Claim reserved quotas to allocated quotas */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - if (i_dquot(inode)[cnt]) - dquot_reclaim_reserved_space(i_dquot(inode)[cnt], - number); + if (dquots[cnt]) + dquot_reclaim_reserved_space(dquots[cnt], number); } /* Update inode bytes */ inode_reclaim_rsv_space(inode, number); spin_unlock(&dq_data_lock); - mark_all_dquot_dirty(i_dquot(inode)); + mark_all_dquot_dirty(dquots); srcu_read_unlock(&dquot_srcu, index); return; } @@ -1750,7 +1763,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) { unsigned int cnt; struct dquot_warn warn[MAXQUOTAS]; - struct dquot **dquots = i_dquot(inode); + struct dquot **dquots; int reserve = flags & DQUOT_SPACE_RESERVE, index; if (!dquot_active(inode)) { @@ -1758,6 +1771,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) return; } + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1793,12 +1807,13 @@ void dquot_free_inode(struct inode *inode) { unsigned int cnt; struct dquot_warn warn[MAXQUOTAS]; - struct dquot * const *dquots = i_dquot(inode); + struct dquot * const *dquots; int index; if (!dquot_active(inode)) return; + dquots = i_dquot(inode); index = srcu_read_lock(&dquot_srcu); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -- GitLab From 69a25ee217ba8c93a6d4c6671d9208c0155c0485 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 12 Feb 2015 12:36:49 +0300 Subject: [PATCH 0170/1910] quota: paranoia: check quota tree root Root level in quota tree must be already allocated otherwise this block could be used for something else. Signed-off-by: Konstantin Khlebnikov Signed-off-by: Jan Kara --- fs/quota/quota_tree.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index d65877fbe8f4..58efb83dec1c 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c @@ -349,6 +349,13 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int tmp = QT_TREEOFF; + +#ifdef __QUOTA_QT_PARANOIA + if (info->dqi_blocks <= QT_TREEOFF) { + quota_error(dquot->dq_sb, "Quota tree root isn't allocated!"); + return -EIO; + } +#endif return do_insert_tree(info, dquot, &tmp, 0); } -- GitLab From 781970240a56d1c15a9b8ee37d28987b8182f060 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 12 Feb 2015 19:08:16 +0300 Subject: [PATCH 0171/1910] quota: reorder flags in quota state Flags in struct quota_state keep flags for each quota type and some common flags. This patch reorders typed flags: Before: 0 USRQUOTA DQUOT_USAGE_ENABLED 1 USRQUOTA DQUOT_LIMITS_ENABLED 2 USRQUOTA DQUOT_SUSPENDED 3 GRPQUOTA DQUOT_USAGE_ENABLED 4 GRPQUOTA DQUOT_LIMITS_ENABLED 5 GRPQUOTA DQUOT_SUSPENDED 6 DQUOT_QUOTA_SYS_FILE 7 DQUOT_NEGATIVE_USAGE After: 0 USRQUOTA DQUOT_USAGE_ENABLED 1 GRPQUOTA DQUOT_USAGE_ENABLED 2 USRQUOTA DQUOT_LIMITS_ENABLED 3 GRPQUOTA DQUOT_LIMITS_ENABLED 4 USRQUOTA DQUOT_SUSPENDED 5 GRPQUOTA DQUOT_SUSPENDED 6 DQUOT_QUOTA_SYS_FILE 7 DQUOT_NEGATIVE_USAGE Now we can get bitmap of all enabled/suspended quota types without loop. For example suspended: (flags / DQUOT_SUSPENDED) & ((1 << MAXQUOTAS) - 1). add/remove: 0/1 grow/shrink: 3/11 up/down: 56/-215 (-159) function old new delta __dquot_initialize 423 447 +24 dquot_transfer 181 197 +16 dquot_alloc_inode 286 302 +16 dquot_reclaim_space_nodirty 316 313 -3 dquot_claim_space_nodirty 314 311 -3 dquot_resume 286 281 -5 dquot_free_inode 332 324 -8 __dquot_alloc_space 500 492 -8 dquot_disable 1944 1929 -15 dquot_quota_enable 252 236 -16 __dquot_free_space 750 734 -16 dquot_writeback_dquots 625 608 -17 __dquot_transfer 1186 1154 -32 dquot_quota_sync 299 261 -38 dquot_active.isra 54 - -54 Signed-off-by: Konstantin Khlebnikov Signed-off-by: Jan Kara --- include/linux/quota.h | 32 +++++++++++++++++++++++++------- include/linux/quotaops.h | 10 ++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/linux/quota.h b/include/linux/quota.h index d534e8ed308a..a3374dc3a91b 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -389,7 +389,19 @@ struct quota_format_type { struct quota_format_type *qf_next; }; -/* Quota state flags - they actually come in two flavors - for users and groups */ +/** + * Quota state flags - they actually come in two flavors - for users and groups. + * + * Actual typed flags layout: + * USRQUOTA GRPQUOTA + * DQUOT_USAGE_ENABLED 0x0001 0x0002 + * DQUOT_LIMITS_ENABLED 0x0004 0x0008 + * DQUOT_SUSPENDED 0x0010 0x0020 + * + * Following bits are used for non-typed flags: + * DQUOT_QUOTA_SYS_FILE 0x0040 + * DQUOT_NEGATIVE_USAGE 0x0080 + */ enum { _DQUOT_USAGE_ENABLED = 0, /* Track disk usage for users */ _DQUOT_LIMITS_ENABLED, /* Enforce quota limits for users */ @@ -398,9 +410,9 @@ enum { * memory to turn them on */ _DQUOT_STATE_FLAGS }; -#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED) -#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED) -#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED) +#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED * MAXQUOTAS) +#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED * MAXQUOTAS) +#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED * MAXQUOTAS) #define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ DQUOT_SUSPENDED) /* Other quota flags */ @@ -414,15 +426,21 @@ enum { */ #define DQUOT_NEGATIVE_USAGE (1 << (DQUOT_STATE_LAST + 1)) /* Allow negative quota usage */ - static inline unsigned int dquot_state_flag(unsigned int flags, int type) { - return flags << _DQUOT_STATE_FLAGS * type; + return flags << type; } static inline unsigned int dquot_generic_flag(unsigned int flags, int type) { - return (flags >> _DQUOT_STATE_FLAGS * type) & DQUOT_STATE_FLAGS; + return (flags >> type) & DQUOT_STATE_FLAGS; +} + +/* Bitmap of quota types where flag is set in flags */ +static __always_inline unsigned dquot_state_types(unsigned flags, unsigned flag) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(flag); + return (flags / flag) & ((1 << MAXQUOTAS) - 1); } #ifdef CONFIG_QUOTA_NETLINK_INTERFACE diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index df73258cca47..8778ec4775eb 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -134,10 +134,7 @@ static inline bool sb_has_quota_suspended(struct super_block *sb, int type) static inline unsigned sb_any_quota_suspended(struct super_block *sb) { - unsigned type, tmsk = 0; - for (type = 0; type < MAXQUOTAS; type++) - tmsk |= sb_has_quota_suspended(sb, type) << type; - return tmsk; + return dquot_state_types(sb_dqopt(sb)->flags, DQUOT_SUSPENDED); } /* Does kernel know about any quota information for given sb + type? */ @@ -149,10 +146,7 @@ static inline bool sb_has_quota_loaded(struct super_block *sb, int type) static inline unsigned sb_any_quota_loaded(struct super_block *sb) { - unsigned type, tmsk = 0; - for (type = 0; type < MAXQUOTAS; type++) - tmsk |= sb_has_quota_loaded(sb, type) << type; - return tmsk; + return dquot_state_types(sb_dqopt(sb)->flags, DQUOT_USAGE_ENABLED); } static inline bool sb_has_quota_active(struct super_block *sb, int type) -- GitLab From 7e08da50cf706151f324349f9235ebd311226997 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 4 Mar 2015 14:42:02 +0100 Subject: [PATCH 0172/1910] quota: Fix maximum quota limit settings Currently quota format that supports 64-bit usage sets maximum quota limit as 2^64-1. However quota core code uses signed numbers to track usage and even limits themselves are stored in long long. Checking of maximum allowable limits worked by luck until commit 14bf61ffe6ac (quota: Switch ->get_dqblk() and ->set_dqblk() to use bytes as space units) because variable we compared with was unsigned. After that commit the type we compared against changed to signed and thus checks for maximum limits with the newest VFS quota format started to refuse any non-negative value. Later the problem was inadvertedly fixed by commit b10a08194c2b (quota: Store maximum space limit in bytes) because we started to compare against unsigned type as well. Fix possible future problems of this kind by setting maximum limits to 2^63-1 to avoid overflow issues. Reported-by: Carlos Carvalho Signed-off-by: Jan Kara --- fs/quota/quota_v2.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 9cb10d7197f7..2aa012a68e90 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -117,12 +117,16 @@ static int v2_read_file_info(struct super_block *sb, int type) qinfo = info->dqi_priv; if (version == 0) { /* limits are stored as unsigned 32-bit data */ - info->dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS; + info->dqi_max_spc_limit = 0xffffffffLL << QUOTABLOCK_BITS; info->dqi_max_ino_limit = 0xffffffff; } else { - /* used space is stored as unsigned 64-bit value in bytes */ - info->dqi_max_spc_limit = 0xffffffffffffffffULL; /* 2^64-1 */ - info->dqi_max_ino_limit = 0xffffffffffffffffULL; + /* + * Used space is stored as unsigned 64-bit value in bytes but + * quota core supports only signed 64-bit values so use that + * as a limit + */ + info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */ + info->dqi_max_ino_limit = 0x7fffffffffffffffLL; } info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); -- GitLab From c472b93990e02c31f02322ddf0fdd9d571169310 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:16 +0100 Subject: [PATCH 0173/1910] ASoC: sn95031: Pass CODEC to sn95031_jack_detection() The sn95031 driver currently gets the CODEC implicitly from the jack that is passed to sn95031_jack_detection(). But the codec field is going to be removed from the snd_soc_jack struct, so refactor things to pass the CODEC explicitly. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sn95031.c | 14 ++++++++------ sound/soc/codecs/sn95031.h | 3 ++- sound/soc/intel/mfld_machine.c | 13 +++++++------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 47b257e41809..1e5d2643c286 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -783,19 +783,21 @@ static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec) snd_soc_write(codec, SN95031_BTNCTRL2, 0x01); } -static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack) +static int sn95031_get_headset_state(struct snd_soc_codec *codec, + struct snd_soc_jack *mfld_jack) { - int micbias = sn95031_get_mic_bias(mfld_jack->codec); + int micbias = sn95031_get_mic_bias(codec); int jack_type = snd_soc_jack_get_type(mfld_jack, micbias); pr_debug("jack type detected = %d\n", jack_type); if (jack_type == SND_JACK_HEADSET) - sn95031_enable_jack_btn(mfld_jack->codec); + sn95031_enable_jack_btn(codec); return jack_type; } -void sn95031_jack_detection(struct mfld_jack_data *jack_data) +void sn95031_jack_detection(struct snd_soc_codec *codec, + struct mfld_jack_data *jack_data) { unsigned int status; unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET; @@ -809,11 +811,11 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data) status = SND_JACK_HEADSET | SND_JACK_BTN_1; } else if (jack_data->intr_id & 0x4) { pr_debug("headset or headphones inserted\n"); - status = sn95031_get_headset_state(jack_data->mfld_jack); + status = sn95031_get_headset_state(codec, jack_data->mfld_jack); } else if (jack_data->intr_id & 0x8) { pr_debug("headset or headphones removed\n"); status = 0; - sn95031_disable_jack_btn(jack_data->mfld_jack->codec); + sn95031_disable_jack_btn(codec); } else { pr_err("unidentified interrupt\n"); return; diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h index 20376d234fb8..7651fe4e6a45 100644 --- a/sound/soc/codecs/sn95031.h +++ b/sound/soc/codecs/sn95031.h @@ -127,6 +127,7 @@ struct mfld_jack_data { struct snd_soc_jack *mfld_jack; }; -extern void sn95031_jack_detection(struct mfld_jack_data *jack_data); +extern void sn95031_jack_detection(struct snd_soc_codec *codec, + struct mfld_jack_data *jack_data); #endif diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index 90b7a57713a0..d22b44db824e 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c @@ -228,10 +228,13 @@ static void mfld_jack_check(unsigned int intr_status) { struct mfld_jack_data jack_data; + if (!mfld_codec) + return; + jack_data.mfld_jack = &mfld_jack; jack_data.intr_id = intr_status; - sn95031_jack_detection(&jack_data); + sn95031_jack_detection(mfld_codec, &jack_data); /* TODO: add american headset detection post gpiolib support */ } @@ -240,8 +243,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dapm_context *dapm = &runtime->card->dapm; int ret_val; - mfld_codec = runtime->codec; - /* default is earpiece pin, userspace sets it explcitly */ snd_soc_dapm_disable_pin(dapm, "Headphones"); /* default is lineout NC, userspace sets it explcitly */ @@ -254,7 +255,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_disable_pin(dapm, "LINEINR"); /* Headset and button jack detection */ - ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack", + ret_val = snd_soc_jack_new(runtime->codec, "Intel(R) MID Audio Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack); if (ret_val) { @@ -275,6 +276,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) return ret_val; } + mfld_codec = runtime->codec; + /* we want to check if anything is inserted at boot, * so send a fake event to codec and it will read adc * to find if anything is there or not */ @@ -359,8 +362,6 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data) { struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; - if (mfld_jack.codec == NULL) - return IRQ_HANDLED; mfld_jack_check(mc_drv_ctx->interrupt_status); return IRQ_HANDLED; -- GitLab From 970939964c26db4643f58d4e84487821962e0b65 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:17 +0100 Subject: [PATCH 0174/1910] ASoC: Allow to register jacks at the card level Jacks are typically card level elements, but are currently registered with a CODEC. When it was originally introduced snd_soc_jack_new() took a snd_soc_card as its parameter, but at that time DAPM was only implemented at the CODEC level and there was only one CODEC per card. This made it clear which CODEC to use for the jack DAPM operations. But the multi-component patchset added support for having multiple CODECs per card and with it the API was updated to register jacks with a specific CODEC instance instead. Subsequently DAPM support at the card level has been introduced, but the snd_soc_jack_new() API has so remained unchanged. This leaves us with the issue that the DAPM pins that are managed by the jack detection logic usually are part of the card DAPM context but are accessed through a CODEC DAPM context. Currently this works fine, but might break in the future if we take a more hierarchical approach to DAPM contexts. Furthermore with componentization progressing systems that do not register a snd_soc_codec might appear, while these system may still want to able to register a jack. This patch addresses these issues by adding a new function called snd_soc_card_jack_new() that can be used to register jacks with the card rather than a CODEC. This new function is mostly identical to snd_soc_jack_new() except that it additionally allows to directly specify the DAPM pins associated with the jack. This was done since most users of snd_soc_jack_new() typically call snd_soc_jack_add_pins() right after it, which is not necessary with the new API and allows to reduce the amount of boiler plate code. The old snd_soc_jack_new() is re-implemented as a wrapper around snd_soc_card_jack_new(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 28 +++++++++++++++++++++++++--- sound/soc/soc-jack.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..99d9ce272209 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); /* Jack reporting */ -int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, - struct snd_soc_jack *jack); +int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, + unsigned int num_pins); + void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask); int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, struct snd_soc_jack_pin *pins); @@ -659,7 +661,7 @@ struct snd_soc_jack_gpio { struct snd_soc_jack { struct mutex mutex; struct snd_jack *jack; - struct snd_soc_codec *codec; + struct snd_soc_card *card; struct list_head pins; int status; struct blocking_notifier_head notifier; @@ -1482,6 +1484,26 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform( return snd_soc_component_to_platform(snd_soc_kcontrol_component(kcontrol)); } +/** + * snd_soc_jack_new - Create a new jack + * @codec: ASoC CODEC + * @id: an identifying string for this jack + * @type: a bitmask of enum snd_jack_type values that can be detected by + * this jack + * @jack: structure to use for the jack + * + * Creates a new jack object. + * + * Returns zero if successful, or a negative error code on failure. + * On success jack will be initialised. + */ +static inline int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, + int type, struct snd_soc_jack *jack) +{ + return snd_soc_card_jack_new(codec->component.card, id, type, jack, + NULL, 0); +} + int snd_soc_util_init(void); void snd_soc_util_exit(void); diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 4380dcc064a5..9f60c25c4568 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -22,30 +22,42 @@ #include /** - * snd_soc_jack_new - Create a new jack - * @codec: ASoC codec + * snd_soc_card_jack_new - Create a new jack + * @card: ASoC card * @id: an identifying string for this jack * @type: a bitmask of enum snd_jack_type values that can be detected by * this jack * @jack: structure to use for the jack + * @pins: Array of jack pins to be added to the jack or NULL + * @num_pins: Number of elements in the @pins array * * Creates a new jack object. * * Returns zero if successful, or a negative error code on failure. * On success jack will be initialised. */ -int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, - struct snd_soc_jack *jack) +int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, + unsigned int num_pins) { + int ret; + mutex_init(&jack->mutex); - jack->codec = codec; + jack->card = card; INIT_LIST_HEAD(&jack->pins); INIT_LIST_HEAD(&jack->jack_zones); BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); - return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack); + ret = snd_jack_new(card->snd_card, id, type, &jack->jack); + if (ret) + return ret; + + if (num_pins) + return snd_soc_jack_add_pins(jack, num_pins, pins); + + return 0; } -EXPORT_SYMBOL_GPL(snd_soc_jack_new); +EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); /** * snd_soc_jack_report - Report the current status for a jack @@ -63,7 +75,6 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new); */ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) { - struct snd_soc_codec *codec; struct snd_soc_dapm_context *dapm; struct snd_soc_jack_pin *pin; unsigned int sync = 0; @@ -74,8 +85,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) if (!jack) return; - codec = jack->codec; - dapm = &codec->dapm; + dapm = &jack->card->dapm; mutex_lock(&jack->mutex); @@ -175,12 +185,12 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!pins[i].pin) { - dev_err(jack->codec->dev, "ASoC: No name for pin %d\n", + dev_err(jack->card->dev, "ASoC: No name for pin %d\n", i); return -EINVAL; } if (!pins[i].mask) { - dev_err(jack->codec->dev, "ASoC: No mask for pin %d" + dev_err(jack->card->dev, "ASoC: No mask for pin %d" " (%s)\n", i, pins[i].pin); return -EINVAL; } @@ -260,7 +270,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) static irqreturn_t gpio_handler(int irq, void *data) { struct snd_soc_jack_gpio *gpio = data; - struct device *dev = gpio->jack->codec->component.card->dev; + struct device *dev = gpio->jack->card->dev; trace_snd_soc_jack_irq(gpio->name); @@ -299,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { if (!gpios[i].name) { - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: No name for gpio at index %d\n", i); ret = -EINVAL; goto undo; @@ -320,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, } else { /* legacy GPIO number */ if (!gpio_is_valid(gpios[i].gpio)) { - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: Invalid gpio %d\n", gpios[i].gpio); ret = -EINVAL; @@ -350,7 +360,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (gpios[i].wake) { ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1); if (ret != 0) - dev_err(jack->codec->dev, + dev_err(jack->card->dev, "ASoC: Failed to mark GPIO at index %d as wake source: %d\n", i, ret); } -- GitLab From 386669fcec85a16cb81cd19236abe76abe0f1fc1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:18 +0100 Subject: [PATCH 0175/1910] ASoC: simple-card: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f7c6734bd5da..b8ee47b7ba9c 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -176,11 +176,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return ret; if (gpio_is_valid(priv->gpio_hp_det)) { - snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE, - &simple_card_hp_jack); - snd_soc_jack_add_pins(&simple_card_hp_jack, - ARRAY_SIZE(simple_card_hp_jack_pins), - simple_card_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", + SND_JACK_HEADPHONE, + &simple_card_hp_jack, + simple_card_hp_jack_pins, + ARRAY_SIZE(simple_card_hp_jack_pins)); simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; @@ -189,11 +189,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) } if (gpio_is_valid(priv->gpio_mic_det)) { - snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE, - &simple_card_mic_jack); - snd_soc_jack_add_pins(&simple_card_mic_jack, - ARRAY_SIZE(simple_card_mic_jack_pins), - simple_card_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + &simple_card_mic_jack, + simple_card_mic_jack_pins, + ARRAY_SIZE(simple_card_mic_jack_pins)); simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, -- GitLab From 27cb64b474516421001932d966ca3184795d4e29 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:19 +0100 Subject: [PATCH 0176/1910] ASoC: imx-es8328: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index f8cf10e16ce9..20e7400e2611 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -53,9 +53,9 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) /* Headphone jack detection */ if (gpio_is_valid(data->jack_gpio)) { - ret = snd_soc_jack_new(rtd->codec, "Headphone", - SND_JACK_HEADPHONE | SND_JACK_BTN_0, - &headset_jack); + ret = snd_soc_card_jack_new(rtd->card, "Headphone", + SND_JACK_HEADPHONE | SND_JACK_BTN_0, + &headset_jack, NULL, 0); if (ret) return ret; -- GitLab From 47ec96d4ca7e4a7b9b8b115a10d59e89f794ef95 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:20 +0100 Subject: [PATCH 0177/1910] ASoC: wm1133-ev: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/fsl/wm1133-ev1.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index a958937ab405..0653aa83c927 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -205,16 +205,14 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; /* Headphone jack detection */ - snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE); /* Microphone jack detection */ - snd_soc_jack_new(codec, "Microphone", - SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack); - snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), - mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Microphone", + SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack, + mic_jack_pins, ARRAY_SIZE(mic_jack_pins)); wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE, SND_JACK_BTN_0); -- GitLab From 85c85e5d6d579a5ff8b5471c4e753946eedbf788 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:21 +0100 Subject: [PATCH 0178/1910] ASoC: broadwell: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/broadwell.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 9cf7d01479ad..9effa3da982f 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -80,15 +80,9 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; int ret = 0; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset); - - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&broadwell_headset, - ARRAY_SIZE(broadwell_headset_pins), - broadwell_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset, + broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins)); if (ret) return ret; -- GitLab From e0f7dd9d88f4c151aeca45d290e171d907249888 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:22 +0100 Subject: [PATCH 0179/1910] ASoC: byt-max98090: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/byt-max98090.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index 9832afe7d22c..d8b1f038da1c 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c @@ -84,7 +84,6 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = { static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) { int ret; - struct snd_soc_codec *codec = runtime->codec; struct snd_soc_card *card = runtime->card; struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card); struct snd_soc_jack *jack = &drv->jack; @@ -100,13 +99,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime) } /* Enable jack detection */ - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET, jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(runtime->card, "Headset", + SND_JACK_LINEOUT | SND_JACK_HEADSET, jack, + hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; -- GitLab From fb1edb4b68a829619bcd50a0c23c557000d0d638 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:23 +0100 Subject: [PATCH 0180/1910] ASoC: cht_bsw_rt5645: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5645.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index bd29617a9ab9..0bfca2192ca0 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -169,17 +169,17 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } - ret = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, - &ctx->hp_jack); + ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack", + SND_JACK_HEADPHONE, &ctx->hp_jack, + NULL, 0); if (ret) { dev_err(runtime->dev, "HP jack creation failed %d\n", ret); return ret; } - ret = snd_soc_jack_new(codec, "Mic Jack", - SND_JACK_MICROPHONE, - &ctx->mic_jack); + ret = snd_soc_card_jack_new(runtime->card, "Mic Jack", + SND_JACK_MICROPHONE, &ctx->mic_jack, + NULL, 0); if (ret) { dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); return ret; -- GitLab From af13cbc1a288d3921f1af739da84371e6c53aea3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:24 +0100 Subject: [PATCH 0181/1910] ASoC: mfld_machine: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/mfld_machine.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index d22b44db824e..49c09a0add79 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c @@ -255,20 +255,15 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) snd_soc_dapm_disable_pin(dapm, "LINEINR"); /* Headset and button jack detection */ - ret_val = snd_soc_jack_new(runtime->codec, "Intel(R) MID Audio Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1, &mfld_jack); + ret_val = snd_soc_card_jack_new(runtime->card, + "Intel(R) MID Audio Jack", SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack, + mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins)); if (ret_val) { pr_err("jack creation failed\n"); return ret_val; } - ret_val = snd_soc_jack_add_pins(&mfld_jack, - ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins); - if (ret_val) { - pr_err("adding jack pins failed\n"); - return ret_val; - } ret_val = snd_soc_jack_add_zones(&mfld_jack, ARRAY_SIZE(mfld_zones), mfld_zones); if (ret_val) { -- GitLab From df8c66189dd42f719c75800a526bdc901f300f41 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:25 +0100 Subject: [PATCH 0182/1910] ASoC: ams-deltea: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/omap/ams-delta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 706613077c15..16cc95fa4573 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -479,8 +479,8 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) /* Add hook switch - can be used to control the codec from userspace * even if line discipline fails */ - ret = snd_soc_jack_new(rtd->codec, "hook_switch", - SND_JACK_HEADSET, &ams_delta_hook_switch); + ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET, + &ams_delta_hook_switch, NULL, 0); if (ret) dev_warn(card->dev, "Failed to allocate resources for hook switch, " -- GitLab From 25649592cfa6c210c9f86670472b864782c8d677 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:26 +0100 Subject: [PATCH 0183/1910] ASoC: omap-abe-twl6040: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-abe-twl6040.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index b9c65f1ad5a8..0843a68f277c 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -182,17 +182,17 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) /* Headset jack detection only if it is supported */ if (priv->jack_detection) { - ret = snd_soc_jack_new(codec, "Headset Jack", - SND_JACK_HEADSET, &hs_jack); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, &hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; - ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); } - return ret; + return 0; } static const struct snd_soc_dapm_route dmic_audio_map[] = { -- GitLab From da21cf6d65283680247da74c3d03f7e5cdfb40d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:27 +0100 Subject: [PATCH 0184/1910] ASoC: omap-twl4030: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-twl4030.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index fb1f6bb87cd4..3673ada43bfb 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -170,14 +170,10 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) if (priv->jack_detect > 0) { hs_jack_gpios[0].gpio = priv->jack_detect; - ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &priv->hs_jack); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&priv->hs_jack, - ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, &priv->hs_jack, + hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) return ret; -- GitLab From 753d45e6b886c93a2a8a88eddaca345643a87f4e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:28 +0100 Subject: [PATCH 0185/1910] ASoC: rx51: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/omap/rx51.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 7f299357c2d2..c2ddf0fbfa28 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -311,9 +311,9 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) } /* AV jack detection */ - err = snd_soc_jack_new(codec, "AV Jack", - SND_JACK_HEADSET | SND_JACK_VIDEOOUT, - &rx51_av_jack); + err = snd_soc_card_jack_new(rtd->card, "AV Jack", + SND_JACK_HEADSET | SND_JACK_VIDEOOUT, + &rx51_av_jack, NULL, 0); if (err) { dev_err(card->dev, "Failed to add AV Jack\n"); return err; -- GitLab From f7a4433b498384f0e300c51b654910f3e03b5ca6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:29 +0100 Subject: [PATCH 0186/1910] ASoC: hx4700: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/pxa/hx4700.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index 73eb5ddf9753..9f8be7cd567e 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -126,17 +126,12 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = { */ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; int err; /* Jack detection API stuff */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin), - hs_jack_pin); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin, + ARRAY_SIZE(hs_jack_pin)); if (err) return err; -- GitLab From bc1e2e06a07ad4c0c021165b34fa8259bdf4d8c6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:30 +0100 Subject: [PATCH 0187/1910] ASoC: palm27x: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/pxa/palm27x.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 910336c5ebeb..c20bbc042425 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -75,17 +75,12 @@ static struct snd_soc_card palm27x_asoc; static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; int err; /* Jack detection API stuff */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &hs_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (err) return err; -- GitLab From 3b14125bc553a0fe091a5d43a22be41cdc43b156 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:31 +0100 Subject: [PATCH 0188/1910] ASoC: ttc-dkb: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/pxa/ttc-dkb.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index 5001dbb9b257..1753c7d9e760 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -78,15 +78,12 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_codec *codec = rtd->codec; /* Headset jack detection */ - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE - | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, - &hs_jack); - snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); - snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, - &mic_jack); - snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), - mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, + &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins)); + snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE, + &mic_jack, mic_jack_pins, + ARRAY_SIZE(mic_jack_pins)); /* headphone, microphone detection & headset short detection */ pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, -- GitLab From d30d141f9cb7eb9fb3f03af11146dc0d2b393ff2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:32 +0100 Subject: [PATCH 0189/1910] ASoC: z2: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/pxa/z2.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index 76ccb172d0a7..bcbfbe8303f7 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c @@ -143,13 +143,9 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "MONO1"); /* Jack detection API stuff */ - ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &hs_jack); - if (ret) - goto err; - - ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), - hs_jack_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, + &hs_jack, hs_jack_pins, + ARRAY_SIZE(hs_jack_pins)); if (ret) goto err; -- GitLab From dfe11f282c61808f7140d9dd741f7e54cf97cda6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:33 +0100 Subject: [PATCH 0190/1910] ASoC: h1980_uda1380: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/h1940_uda1380.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index 59b044255b78..c72e9fb26658 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c @@ -162,13 +162,8 @@ static struct platform_device *s3c24xx_snd_device; static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &hp_jack); - - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); -- GitLab From 39ec5109d6089e1acd04b51b9df5349f5b8a7f5c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:34 +0100 Subject: [PATCH 0191/1910] ASoC: littlemill: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/littlemill.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 141519c21e21..31a820eb0ac3 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -260,12 +260,12 @@ static int littlemill_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_MECHANICAL | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | - SND_JACK_BTN_4 | SND_JACK_BTN_5, - &littlemill_headset); + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_MECHANICAL | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | + SND_JACK_BTN_4 | SND_JACK_BTN_5, + &littlemill_headset, NULL, 0); if (ret) return ret; -- GitLab From f97e0eacf2b5d9c1a470e53df60519d555ac5a75 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:35 +0100 Subject: [PATCH 0192/1910] ASoC: lowland: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/lowland.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 243dea7ba38f..5f156093101e 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -56,16 +56,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET | - SND_JACK_BTN_0, - &lowland_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&lowland_headset, - ARRAY_SIZE(lowland_headset_pins), - lowland_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0, + &lowland_headset, lowland_headset_pins, + ARRAY_SIZE(lowland_headset_pins)); if (ret) return ret; -- GitLab From e9c9a723eea5102fa6adedf454e02fff6201a3c3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:36 +0100 Subject: [PATCH 0193/1910] ASoC: rx1950_uda1380: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/rx1950_uda1380.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 873f2cb4bebe..35e37c457f1f 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c @@ -211,13 +211,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &hp_jack); - - snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), - hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); -- GitLab From 55b2ed2d9dd8c611837f34ca29df881eb0a1de8d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:37 +0100 Subject: [PATCH 0194/1910] ASoC: smartq: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/smartq_wm8987.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index 8291d2a5f152..dfbe2db1c407 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c @@ -151,13 +151,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); /* Headphone jack detection */ - err = snd_soc_jack_new(codec, "Headphone Jack", - SND_JACK_HEADPHONE, &smartq_jack); - if (err) - return err; - - err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), - smartq_jack_pins); + err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &smartq_jack, + smartq_jack_pins, + ARRAY_SIZE(smartq_jack_pins)); if (err) return err; -- GitLab From 663976ad478b50664353fdf19a5a3dcad3cb4e22 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:38 +0100 Subject: [PATCH 0195/1910] ASoC: speyside: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/speyside.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 5ec7c52282f2..2dcb988bdff2 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -153,16 +153,10 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd) pr_err("Failed to request HP_SEL GPIO: %d\n", ret); gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_LINEOUT | SND_JACK_HEADSET | - SND_JACK_BTN_0, - &speyside_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&speyside_headset, - ARRAY_SIZE(speyside_headset_pins), - speyside_headset_pins); + ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | + SND_JACK_HEADSET | SND_JACK_BTN_0, + &speyside_headset, speyside_headset_pins, + ARRAY_SIZE(speyside_headset_pins)); if (ret) return ret; -- GitLab From 3fd94f37da000a2b562a3f4e6c553b7ab1ad9e19 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:39 +0100 Subject: [PATCH 0196/1910] ASoC: tobermory: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/tobermory.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 9c80506527c4..85ccfb7188cb 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -179,15 +179,10 @@ static int tobermory_late_probe(struct snd_soc_card *card) if (ret < 0) return ret; - ret = snd_soc_jack_new(codec, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &tobermory_headset); - if (ret) - return ret; - - ret = snd_soc_jack_add_pins(&tobermory_headset, - ARRAY_SIZE(tobermory_headset_pins), - tobermory_headset_pins); + ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | + SND_JACK_BTN_0, &tobermory_headset, + tobermory_headset_pins, + ARRAY_SIZE(tobermory_headset_pins)); if (ret) return ret; -- GitLab From 12cc6d1dca4d3a9e929090cb0cf9ef452f414518 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:40 +0100 Subject: [PATCH 0197/1910] ASoC: tegra_alc5632: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_alc5632.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 769aca2fc5f5..6dcd06a966c7 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -106,11 +106,10 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, - &tegra_alc5632_hs_jack); - snd_soc_jack_add_pins(&tegra_alc5632_hs_jack, - ARRAY_SIZE(tegra_alc5632_hs_jack_pins), - tegra_alc5632_hs_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, + &tegra_alc5632_hs_jack, + tegra_alc5632_hs_jack_pins, + ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; -- GitLab From d020e77c61b8a9d563d205cfcec7e71090d1377d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:41 +0100 Subject: [PATCH 0198/1910] ASoC: tegra_max98090: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_max98090.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index af3fb997b752..6760f0ebc133 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -141,16 +141,14 @@ static const struct snd_kcontrol_new tegra_max98090_controls[] = { static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card); if (gpio_is_valid(machine->gpio_hp_det)) { - snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, - &tegra_max98090_hp_jack); - snd_soc_jack_add_pins(&tegra_max98090_hp_jack, - ARRAY_SIZE(tegra_max98090_hp_jack_pins), - tegra_max98090_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", + SND_JACK_HEADPHONE, + &tegra_max98090_hp_jack, + tegra_max98090_hp_jack_pins, + ARRAY_SIZE(tegra_max98090_hp_jack_pins)); tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det; snd_soc_jack_add_gpios(&tegra_max98090_hp_jack, @@ -159,11 +157,11 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) } if (gpio_is_valid(machine->gpio_mic_det)) { - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_max98090_mic_jack); - snd_soc_jack_add_pins(&tegra_max98090_mic_jack, - ARRAY_SIZE(tegra_max98090_mic_jack_pins), - tegra_max98090_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, + &tegra_max98090_mic_jack, + tegra_max98090_mic_jack_pins, + ARRAY_SIZE(tegra_max98090_mic_jack_pins)); tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det; snd_soc_jack_add_gpios(&tegra_max98090_mic_jack, -- GitLab From 00eafe3b1b191c9b2611b74c03e1b573ae257b1e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:42 +0100 Subject: [PATCH 0199/1910] ASoC: tegra_rt5640: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_rt5640.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index ed759a3076b8..773daecaa5e8 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -108,15 +108,11 @@ static const struct snd_kcontrol_new tegra_rt5640_controls[] = { static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, - &tegra_rt5640_hp_jack); - snd_soc_jack_add_pins(&tegra_rt5640_hp_jack, - ARRAY_SIZE(tegra_rt5640_hp_jack_pins), - tegra_rt5640_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE, + &tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins, + ARRAY_SIZE(tegra_rt5640_hp_jack_pins)); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; -- GitLab From 783b1e7948010ded40eba784b558d86d72ae2ef4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:43 +0100 Subject: [PATCH 0200/1910] ASoC: tegra_rt5677: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_rt5677.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index e4cf978a6e3a..68d8b67e79c1 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -146,10 +146,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm = &codec->dapm; struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &tegra_rt5677_hp_jack); - snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1, - &tegra_rt5677_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE, + &tegra_rt5677_hp_jack, + &tegra_rt5677_hp_jack_pins, 1); if (gpio_is_valid(machine->gpio_hp_det)) { tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det; @@ -158,10 +157,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) } - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_rt5677_mic_jack); - snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1, - &tegra_rt5677_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_rt5677_mic_jack, + &tegra_rt5677_mic_jack_pins, 1); if (gpio_is_valid(machine->gpio_mic_present)) { tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present; -- GitLab From 7ba8cbb2f0fd9ff232fa19159e2646bf64135126 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:44 +0100 Subject: [PATCH 0201/1910] ASoC: tegra_wm8903: Register jacks at the card level The jacks are card level elements so use snd_soc_card_jack_new() instead of snd_soc_jack_new() to register them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_wm8903.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e52420dae2b4..4a95b70f0cf0 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -177,21 +177,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) if (gpio_is_valid(machine->gpio_hp_det)) { tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det; - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, - &tegra_wm8903_hp_jack); - snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, - ARRAY_SIZE(tegra_wm8903_hp_jack_pins), - tegra_wm8903_hp_jack_pins); + snd_soc_card_jack_new(rtd->card, "Headphone Jack", + SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack, + tegra_wm8903_hp_jack_pins, + ARRAY_SIZE(tegra_wm8903_hp_jack_pins)); snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, 1, &tegra_wm8903_hp_jack_gpio); } - snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, - &tegra_wm8903_mic_jack); - snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, - ARRAY_SIZE(tegra_wm8903_mic_jack_pins), - tegra_wm8903_mic_jack_pins); + snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_wm8903_mic_jack, + tegra_wm8903_mic_jack_pins, + ARRAY_SIZE(tegra_wm8903_mic_jack_pins)); wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, 0); -- GitLab From 77c71765ef78f87dd901fcb4c751908e835a3b2e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 4 Mar 2015 10:33:45 +0100 Subject: [PATCH 0202/1910] ASoC: Remove snd_soc_jack_new() There are no users of snd_soc_jack_new() left and new users should use snd_soc_card_jack_new() instead. So remove the function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 99d9ce272209..40b3ee96f317 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1484,26 +1484,6 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform( return snd_soc_component_to_platform(snd_soc_kcontrol_component(kcontrol)); } -/** - * snd_soc_jack_new - Create a new jack - * @codec: ASoC CODEC - * @id: an identifying string for this jack - * @type: a bitmask of enum snd_jack_type values that can be detected by - * this jack - * @jack: structure to use for the jack - * - * Creates a new jack object. - * - * Returns zero if successful, or a negative error code on failure. - * On success jack will be initialised. - */ -static inline int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, - int type, struct snd_soc_jack *jack) -{ - return snd_soc_card_jack_new(codec->component.card, id, type, jack, - NULL, 0); -} - int snd_soc_util_init(void); void snd_soc_util_exit(void); -- GitLab From 4c03a5ebc7f75e98b32591d1d2c6758c811dcbef Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Mar 2015 16:45:17 +0200 Subject: [PATCH 0203/1910] ASoC: davinci: Select SND_EDMA_SOC when SND_DAVINCI_SOC is enabled edma-pcm going to replace davinci-pcm as platform driver for daVinci platform. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 2b81ca418d2a..eae4e229f341 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,10 +1,11 @@ config SND_DAVINCI_SOC tristate "SoC Audio for TI DAVINCI" depends on ARCH_DAVINCI + select SND_EDMA_SOC config SND_EDMA_SOC tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)" - depends on SOC_AM33XX || SOC_AM43XX + depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M here if you want audio support for TI SoC which uses eDMA. -- GitLab From 257ade78b6019cf1570c1239894a7a6a549768e1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Mar 2015 16:45:18 +0200 Subject: [PATCH 0204/1910] ASoC: davinci-i2s: Convert to use edma-pcm The edma-pcm can replace the old davinci-pcm as platform driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 67 +++++++++++++-------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 15fb28fc8e1b..56cb4d95637d 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -23,8 +23,9 @@ #include #include #include +#include -#include "davinci-pcm.h" +#include "edma-pcm.h" #include "davinci-i2s.h" @@ -122,7 +123,8 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = { struct davinci_mcbsp_dev { struct device *dev; - struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; + int dma_request[2]; void __iomem *base; #define MOD_DSP_A 0 #define MOD_DSP_B 1 @@ -419,8 +421,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); - struct davinci_pcm_dma_params *dma_params = - &dev->dma_params[substream->stream]; struct snd_interval *i = NULL; int mcbsp_word_length, master; unsigned int rcr, xcr, srgr, clk_div, freq, framesize; @@ -532,8 +532,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } } - dma_params->acnt = dma_params->data_type = data_type[fmt]; - dma_params->fifo_level = 0; mcbsp_word_length = asp_word_length[fmt]; switch (master) { @@ -600,15 +598,6 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static int davinci_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); - return 0; -} - static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -620,7 +609,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .startup = davinci_i2s_startup, .shutdown = davinci_i2s_shutdown, .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, @@ -630,7 +618,18 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { }; +static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); + + dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + + return 0; +} + static struct snd_soc_dai_driver davinci_i2s_dai = { + .probe = davinci_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, @@ -651,11 +650,9 @@ static const struct snd_soc_component_driver davinci_i2s_component = { static int davinci_i2s_probe(struct platform_device *pdev) { - struct snd_platform_data *pdata = pdev->dev.platform_data; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea, *res; - enum dma_event_q asp_chan_q = EVENTQ_0; - enum dma_event_q ram_chan_q = EVENTQ_1; + int *dma; int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -676,22 +673,6 @@ static int davinci_i2s_probe(struct platform_device *pdev) GFP_KERNEL); if (!dev) return -ENOMEM; - if (pdata) { - dev->enable_channel_combine = pdata->enable_channel_combine; - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size = - pdata->sram_size_playback; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = - pdata->sram_size_capture; - dev->clk_input_pin = pdata->clk_input_pin; - dev->i2s_accurate_sck = pdata->i2s_accurate_sck; - asp_chan_q = pdata->asp_chan_q; - ram_chan_q = pdata->ram_chan_q; - } - - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q; dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) @@ -705,10 +686,10 @@ static int davinci_i2s_probe(struct platform_device *pdev) goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); /* first TX, then RX */ @@ -718,7 +699,9 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENXIO; goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start; + dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; + *dma = res->start; + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!res) { @@ -726,9 +709,11 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENXIO; goto err_release_clk; } - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; - dev->dev = &pdev->dev; + dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; + *dma = res->start; + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma; + dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, @@ -736,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) if (ret != 0) goto err_release_clk; - ret = davinci_soc_platform_register(&pdev->dev); + ret = edma_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); goto err_unregister_component; -- GitLab From 62731d33c41d95914a0a796f319924e22e7ea411 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Mar 2015 16:45:19 +0200 Subject: [PATCH 0205/1910] ASoC: davinci-vcif: Convert to use edma-pcm The edma-pcm can replace the old davinci-pcm as platform driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-vcif.c | 55 ++++++++++++++------------------ 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index 5bee04279ebe..fabd05f24aeb 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -33,8 +33,9 @@ #include #include #include +#include -#include "davinci-pcm.h" +#include "edma-pcm.h" #include "davinci-i2s.h" #define MOD_REG_BIT(val, mask, set) do { \ @@ -47,7 +48,8 @@ struct davinci_vcif_dev { struct davinci_vc *davinci_vc; - struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; + int dma_request[2]; }; static void davinci_vcif_start(struct snd_pcm_substream *substream) @@ -93,8 +95,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, { struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai); struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; - struct davinci_pcm_dma_params *dma_params = - &davinci_vcif_dev->dma_params[substream->stream]; u32 w; /* Restart the codec before setup */ @@ -113,16 +113,12 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, /* Determine xfer data type */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: - dma_params->data_type = 0; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | DAVINCI_VC_CTRL_WD_UNSIGNED, 1); break; case SNDRV_PCM_FORMAT_S8: - dma_params->data_type = 1; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_WD_BITS_8, 1); @@ -130,8 +126,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, DAVINCI_VC_CTRL_WD_UNSIGNED, 0); break; case SNDRV_PCM_FORMAT_S16_LE: - dma_params->data_type = 2; - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | @@ -142,8 +136,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - dma_params->acnt = dma_params->data_type; - writel(w, davinci_vc->base + DAVINCI_VC_CTRL); return 0; @@ -172,24 +164,25 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static int davinci_vcif_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); - - snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); - return 0; -} - #define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000 static const struct snd_soc_dai_ops davinci_vcif_dai_ops = { - .startup = davinci_vcif_startup, .trigger = davinci_vcif_trigger, .hw_params = davinci_vcif_hw_params, }; +static int davinci_vcif_dai_probe(struct snd_soc_dai *dai) +{ + struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); + + dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + + return 0; +} + static struct snd_soc_dai_driver davinci_vcif_dai = { + .probe = davinci_vcif_dai_probe, .playback = { .channels_min = 1, .channels_max = 2, @@ -225,16 +218,16 @@ static int davinci_vcif_probe(struct platform_device *pdev) /* DMA tx params */ davinci_vcif_dev->davinci_vc = davinci_vc; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = - davinci_vc->davinci_vcif.dma_tx_channel; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = - davinci_vc->davinci_vcif.dma_tx_addr; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = + &davinci_vc->davinci_vcif.dma_tx_channel; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = + davinci_vc->davinci_vcif.dma_tx_addr; /* DMA rx params */ - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = - davinci_vc->davinci_vcif.dma_rx_channel; - davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = - davinci_vc->davinci_vcif.dma_rx_addr; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = + &davinci_vc->davinci_vcif.dma_rx_channel; + davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = + davinci_vc->davinci_vcif.dma_rx_addr; dev_set_drvdata(&pdev->dev, davinci_vcif_dev); @@ -245,7 +238,7 @@ static int davinci_vcif_probe(struct platform_device *pdev) return ret; } - ret = davinci_soc_platform_register(&pdev->dev); + ret = edma_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "register PCM failed: %d\n", ret); snd_soc_unregister_component(&pdev->dev); -- GitLab From 9759e7ef53138c5ab46ea516ad08977eb5770393 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Mar 2015 16:45:20 +0200 Subject: [PATCH 0206/1910] ASoC: davinci-mcasp: Deprecate the use of davinci-pcm in favor of edma-pcm The edma-pcm performs as good as the old davinci-pcm and it's use does not require the 'ping-pong' mode of davinci-pcm, which was introduced to overcome under/over flow issues when using davinci-pcm. Keep the SND_DAVINCI_SOC config option to select the SND_EDMA_SOC to avoid regression in audio support. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 15 +++--- sound/soc/davinci/davinci-mcasp.c | 87 +++++++------------------------ 2 files changed, 27 insertions(+), 75 deletions(-) diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index eae4e229f341..3736d9aabc56 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,15 +1,16 @@ config SND_DAVINCI_SOC - tristate "SoC Audio for TI DAVINCI" + tristate depends on ARCH_DAVINCI select SND_EDMA_SOC config SND_EDMA_SOC - tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)" + tristate "SoC Audio for Texas Instruments chips using eDMA" depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M here if you want audio support for TI SoC which uses eDMA. The following line of SoCs are supported by this platform driver: + - daVinci devices - AM335x - AM437x/AM438x @@ -18,7 +19,7 @@ config SND_DAVINCI_SOC_I2S config SND_DAVINCI_SOC_MCASP tristate "Multichannel Audio Serial Port (McASP) support" - depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC + depends on SND_OMAP_SOC || SND_EDMA_SOC help Say Y or M here if you want to have support for McASP IP found in various Texas Instruments SoCs like: @@ -46,7 +47,7 @@ config SND_AM33XX_SOC_EVM config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" - depends on SND_DAVINCI_SOC && I2C + depends on SND_EDMA_SOC && I2C depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM select SND_DAVINCI_SOC_GENERIC_EVM help @@ -74,7 +75,7 @@ endchoice config SND_DM6467_SOC_EVM tristate "SoC Audio support for DaVinci DM6467 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM select SND_SOC_SPDIF @@ -83,7 +84,7 @@ config SND_DM6467_SOC_EVM config SND_DA830_SOC_EVM tristate "SoC Audio support for DA830/OMAP-L137 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help @@ -92,7 +93,7 @@ config SND_DA830_SOC_EVM config SND_DA850_SOC_EVM tristate "SoC Audio support for DA850/OMAP-L138 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C + depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C select SND_DAVINCI_SOC_GENERIC_EVM help Say Y if you want to add support for SoC audio on TI diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 031c1fb44ae7..0c882995a357 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include #include -#include "davinci-pcm.h" #include "edma-pcm.h" #include "davinci-mcasp.h" @@ -65,7 +65,6 @@ struct davinci_mcasp_context { }; struct davinci_mcasp { - struct davinci_pcm_dma_params dma_params[2]; struct snd_dmaengine_dai_dma_data dma_data[2]; void __iomem *base; u32 fifo_base; @@ -82,6 +81,7 @@ struct davinci_mcasp { u16 bclk_lrclk_ratio; int streams; u32 irq_request[2]; + int dma_request[2]; int sysclk_freq; bool bclk_master; @@ -643,7 +643,6 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int period_words, int channels) { - struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream]; struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream]; int i; u8 tx_ser = 0; @@ -711,10 +710,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, * For example if three serializers are enabled the DMA * need to transfer three words per DMA request. */ - dma_params->fifo_level = active_serializers; dma_data->maxburst = active_serializers; } else { - dma_params->fifo_level = 0; dma_data->maxburst = 0; } return 0; @@ -746,7 +743,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, /* Configure the burst size for platform drivers */ if (numevt == 1) numevt = 0; - dma_params->fifo_level = numevt; dma_data->maxburst = numevt; return 0; @@ -872,8 +868,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); - struct davinci_pcm_dma_params *dma_params = - &mcasp->dma_params[substream->stream]; int word_length; int channels = params_channels(params); int period_size = params_period_size(params); @@ -914,31 +908,26 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: - dma_params->data_type = 1; word_length = 8; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: - dma_params->data_type = 2; word_length = 16; break; case SNDRV_PCM_FORMAT_U24_3LE: case SNDRV_PCM_FORMAT_S24_3LE: - dma_params->data_type = 3; word_length = 24; break; case SNDRV_PCM_FORMAT_U24_LE: case SNDRV_PCM_FORMAT_S24_LE: - dma_params->data_type = 4; word_length = 24; break; case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: - dma_params->data_type = 4; word_length = 32; break; @@ -947,11 +936,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level) - dma_params->acnt = 4; - else - dma_params->acnt = dma_params->data_type; - davinci_config_channel_size(mcasp, word_length); if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) @@ -1055,17 +1039,8 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - if (mcasp->version >= MCASP_VERSION_3) { - /* Using dmaengine PCM */ - dai->playback_dma_data = - &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; - dai->capture_dma_data = - &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; - } else { - /* Using davinci-pcm */ - dai->playback_dma_data = mcasp->dma_params; - dai->capture_dma_data = mcasp->dma_params; - } + dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; return 0; } @@ -1184,28 +1159,24 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { .tx_dma_offset = 0x400, .rx_dma_offset = 0x400, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_1, }; static struct davinci_mcasp_pdata da830_mcasp_pdata = { .tx_dma_offset = 0x2000, .rx_dma_offset = 0x2000, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_2, }; static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { .tx_dma_offset = 0, .rx_dma_offset = 0, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_3, }; static struct davinci_mcasp_pdata dra7_mcasp_pdata = { .tx_dma_offset = 0x200, .rx_dma_offset = 0x284, - .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_4, }; @@ -1382,12 +1353,12 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( static int davinci_mcasp_probe(struct platform_device *pdev) { - struct davinci_pcm_dma_params *dma_params; struct snd_dmaengine_dai_dma_data *dma_data; struct resource *mem, *ioarea, *res, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; + int *dma; int irq; int ret; @@ -1521,59 +1492,45 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) mcasp->dat_port = true; - dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; - dma_params->asp_chan_q = pdata->asp_chan_q; - dma_params->ram_chan_q = pdata->ram_chan_q; - dma_params->sram_pool = pdata->sram_pool; - dma_params->sram_size = pdata->sram_size_playback; if (dat) - dma_params->dma_addr = dat->start; + dma_data->addr = dat->start; else - dma_params->dma_addr = mem->start + pdata->tx_dma_offset; - - /* Unconditional dmaengine stuff */ - dma_data->addr = dma_params->dma_addr; + dma_data->addr = mem->start + pdata->tx_dma_offset; + dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) - dma_params->channel = res->start; + *dma = res->start; else - dma_params->channel = pdata->tx_dma_channel; + *dma = pdata->tx_dma_channel; /* dmaengine filter data for DT and non-DT boot */ if (pdev->dev.of_node) dma_data->filter_data = "tx"; else - dma_data->filter_data = &dma_params->channel; + dma_data->filter_data = dma; /* RX is not valid in DIT mode */ if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { - dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; - dma_params->asp_chan_q = pdata->asp_chan_q; - dma_params->ram_chan_q = pdata->ram_chan_q; - dma_params->sram_pool = pdata->sram_pool; - dma_params->sram_size = pdata->sram_size_capture; if (dat) - dma_params->dma_addr = dat->start; + dma_data->addr = dat->start; else - dma_params->dma_addr = mem->start + pdata->rx_dma_offset; - - /* Unconditional dmaengine stuff */ - dma_data->addr = dma_params->dma_addr; + dma_data->addr = mem->start + pdata->rx_dma_offset; + dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE]; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (res) - dma_params->channel = res->start; + *dma = res->start; else - dma_params->channel = pdata->rx_dma_channel; + *dma = pdata->rx_dma_channel; /* dmaengine filter data for DT and non-DT boot */ if (pdev->dev.of_node) dma_data->filter_data = "rx"; else - dma_data->filter_data = &dma_params->channel; + dma_data->filter_data = dma; } if (mcasp->version < MCASP_VERSION_3) { @@ -1596,17 +1553,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) goto err; switch (mcasp->version) { -#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \ - (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ - IS_MODULE(CONFIG_SND_DAVINCI_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - ret = davinci_soc_platform_register(&pdev->dev); - break; -#endif #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \ IS_MODULE(CONFIG_SND_EDMA_SOC)) + case MCASP_VERSION_1: + case MCASP_VERSION_2: case MCASP_VERSION_3: ret = edma_pcm_platform_register(&pdev->dev); break; -- GitLab From 4da4608c91308d0d15dd022074724446c15710dc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Mar 2015 16:45:21 +0200 Subject: [PATCH 0207/1910] ASoC: davinci: Remove unused davinci-pcm platform driver All DAI drivers has been converted to use edma-pcm instead of davinci-pcm and the driver can be removed from the tree. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/Makefile | 2 - sound/soc/davinci/davinci-pcm.c | 861 -------------------------------- sound/soc/davinci/davinci-pcm.h | 41 -- 3 files changed, 904 deletions(-) delete mode 100644 sound/soc/davinci/davinci-pcm.c delete mode 100644 sound/soc/davinci/davinci-pcm.h diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index 09bf2ba92d38..f883933c1a19 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -1,11 +1,9 @@ # DAVINCI Platform Support -snd-soc-davinci-objs := davinci-pcm.o snd-soc-edma-objs := edma-pcm.o snd-soc-davinci-i2s-objs := davinci-i2s.o snd-soc-davinci-mcasp-objs:= davinci-mcasp.o snd-soc-davinci-vcif-objs:= davinci-vcif.o -obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c deleted file mode 100644 index 7809e9d935fc..000000000000 --- a/sound/soc/davinci/davinci-pcm.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * ALSA PCM interface for the TI DAVINCI processor - * - * Author: Vladimir Barinov, - * Copyright: (C) 2007 MontaVista Software, Inc., - * added SRAM ping/pong (C) 2008 Troy Kisky - * - * This program is free software; you can 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "davinci-pcm.h" - -#ifdef DEBUG -static void print_buf_info(int slot, char *name) -{ - struct edmacc_param p; - if (slot < 0) - return; - edma_read_slot(slot, &p); - printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n", - name, slot, p.opt, p.src, p.a_b_cnt, p.dst); - printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n", - p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt); -} -#else -static void print_buf_info(int slot, char *name) -{ -} -#endif - -static struct snd_pcm_hardware pcm_hardware_playback = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| - SNDRV_PCM_INFO_BATCH), - .buffer_bytes_max = 128 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8 * 1024, - .periods_min = 16, - .periods_max = 255, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware pcm_hardware_capture = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH), - .buffer_bytes_max = 128 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8 * 1024, - .periods_min = 16, - .periods_max = 255, - .fifo_size = 0, -}; - -/* - * How ping/pong works.... - * - * Playback: - * ram_params - copys 2*ping_size from start of SDRAM to iram, - * links to ram_link2 - * ram_link2 - copys rest of SDRAM to iram in ping_size units, - * links to ram_link - * ram_link - copys entire SDRAM to iram in ping_size uints, - * links to self - * - * asp_params - same as asp_link[0] - * asp_link[0] - copys from lower half of iram to asp port - * links to asp_link[1], triggers iram copy event on completion - * asp_link[1] - copys from upper half of iram to asp port - * links to asp_link[0], triggers iram copy event on completion - * triggers interrupt only needed to let upper SOC levels update position - * in stream on completion - * - * When playback is started: - * ram_params started - * asp_params started - * - * Capture: - * ram_params - same as ram_link, - * links to ram_link - * ram_link - same as playback - * links to self - * - * asp_params - same as playback - * asp_link[0] - same as playback - * asp_link[1] - same as playback - * - * When capture is started: - * asp_params started - */ -struct davinci_runtime_data { - spinlock_t lock; - int period; /* current DMA period */ - int asp_channel; /* Master DMA channel */ - int asp_link[2]; /* asp parameter link channel, ping/pong */ - struct davinci_pcm_dma_params *params; /* DMA params */ - int ram_channel; - int ram_link; - int ram_link2; - struct edmacc_param asp_params; - struct edmacc_param ram_params; -}; - -static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; -} -/* - * Not used with ping/pong - */ -static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int period_size; - unsigned int dma_offset; - dma_addr_t dma_pos; - dma_addr_t src, dst; - unsigned short src_bidx, dst_bidx; - unsigned short src_cidx, dst_cidx; - unsigned int data_type; - unsigned short acnt; - unsigned int count; - unsigned int fifo_level; - - period_size = snd_pcm_lib_period_bytes(substream); - dma_offset = prtd->period * period_size; - dma_pos = runtime->dma_addr + dma_offset; - fifo_level = prtd->params->fifo_level; - - pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " - "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos, - period_size); - - data_type = prtd->params->data_type; - count = period_size / data_type; - if (fifo_level) - count /= fifo_level; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - src = dma_pos; - dst = prtd->params->dma_addr; - src_bidx = data_type; - dst_bidx = 4; - src_cidx = data_type * fifo_level; - dst_cidx = 0; - } else { - src = prtd->params->dma_addr; - dst = dma_pos; - src_bidx = 0; - dst_bidx = data_type; - src_cidx = 0; - dst_cidx = data_type * fifo_level; - } - - acnt = prtd->params->acnt; - edma_set_src(prtd->asp_link[0], src, INCR, W8BIT); - edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT); - - edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx); - edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx); - - if (!fifo_level) - edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0, - ASYNC); - else - edma_set_transfer_params(prtd->asp_link[0], acnt, - fifo_level, - count, fifo_level, - ABSYNC); -} - -static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) -{ - struct snd_pcm_substream *substream = data; - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - print_buf_info(prtd->ram_channel, "i ram_channel"); - pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status); - - if (unlikely(ch_status != EDMA_DMA_COMPLETE)) - return; - - if (snd_pcm_running(substream)) { - spin_lock(&prtd->lock); - if (prtd->ram_channel < 0) { - /* No ping/pong must fix up link dma data*/ - davinci_pcm_enqueue_dma(substream); - } - davinci_pcm_period_elapsed(substream); - spin_unlock(&prtd->lock); - snd_pcm_period_elapsed(substream); - } -} - -#ifdef CONFIG_GENERIC_ALLOCATOR -static int allocate_sram(struct snd_pcm_substream *substream, - struct gen_pool *sram_pool, unsigned size, - struct snd_pcm_hardware *ppcm) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - struct snd_dma_buffer *iram_dma = NULL; - dma_addr_t iram_phys = 0; - void *iram_virt = NULL; - - if (buf->private_data || !size) - return 0; - - ppcm->period_bytes_max = size; - iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys); - if (!iram_virt) - goto exit1; - iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); - if (!iram_dma) - goto exit2; - iram_dma->area = iram_virt; - iram_dma->addr = iram_phys; - memset(iram_dma->area, 0, size); - iram_dma->bytes = size; - buf->private_data = iram_dma; - return 0; -exit2: - if (iram_virt) - gen_pool_free(sram_pool, (unsigned)iram_virt, size); -exit1: - return -ENOMEM; -} - -static void davinci_free_sram(struct snd_pcm_substream *substream, - struct snd_dma_buffer *iram_dma) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct gen_pool *sram_pool = prtd->params->sram_pool; - - gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); -} -#else -static int allocate_sram(struct snd_pcm_substream *substream, - struct gen_pool *sram_pool, unsigned size, - struct snd_pcm_hardware *ppcm) -{ - return 0; -} - -static void davinci_free_sram(struct snd_pcm_substream *substream, - struct snd_dma_buffer *iram_dma) -{ -} -#endif - -/* - * Only used with ping/pong. - * This is called after runtime->dma_addr, period_bytes and data_type are valid - */ -static int ping_pong_dma_setup(struct snd_pcm_substream *substream) -{ - unsigned short ram_src_cidx, ram_dst_cidx; - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - struct snd_dma_buffer *iram_dma = - (struct snd_dma_buffer *)substream->dma_buffer.private_data; - struct davinci_pcm_dma_params *params = prtd->params; - unsigned int data_type = params->data_type; - unsigned int acnt = params->acnt; - /* divide by 2 for ping/pong */ - unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1; - unsigned int fifo_level = prtd->params->fifo_level; - unsigned int count; - if ((data_type == 0) || (data_type > 4)) { - printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type); - return -EINVAL; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dma_addr_t asp_src_pong = iram_dma->addr + ping_size; - ram_src_cidx = ping_size; - ram_dst_cidx = -ping_size; - edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT); - - edma_set_src_index(prtd->asp_link[0], data_type, - data_type * fifo_level); - edma_set_src_index(prtd->asp_link[1], data_type, - data_type * fifo_level); - - edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); - } else { - dma_addr_t asp_dst_pong = iram_dma->addr + ping_size; - ram_src_cidx = -ping_size; - ram_dst_cidx = ping_size; - edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT); - - edma_set_dest_index(prtd->asp_link[0], data_type, - data_type * fifo_level); - edma_set_dest_index(prtd->asp_link[1], data_type, - data_type * fifo_level); - - edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT); - } - - if (!fifo_level) { - count = ping_size / data_type; - edma_set_transfer_params(prtd->asp_link[0], acnt, count, - 1, 0, ASYNC); - edma_set_transfer_params(prtd->asp_link[1], acnt, count, - 1, 0, ASYNC); - } else { - count = ping_size / (data_type * fifo_level); - edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, - count, fifo_level, ABSYNC); - edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level, - count, fifo_level, ABSYNC); - } - - edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx); - edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx); - edma_set_transfer_params(prtd->ram_link, ping_size, 2, - runtime->periods, 2, ASYNC); - - /* init master params */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - edma_read_slot(prtd->ram_link, &prtd->ram_params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - struct edmacc_param p_ram; - /* Copy entire iram buffer before playback started */ - prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1); - /* 0 dst_bidx */ - prtd->ram_params.src_dst_bidx = (ping_size << 1); - /* 0 dst_cidx */ - prtd->ram_params.src_dst_cidx = (ping_size << 1); - prtd->ram_params.ccnt = 1; - - /* Skip 1st period */ - edma_read_slot(prtd->ram_link, &p_ram); - p_ram.src += (ping_size << 1); - p_ram.ccnt -= 1; - edma_write_slot(prtd->ram_link2, &p_ram); - /* - * When 1st started, ram -> iram dma channel will fill the - * entire iram. Then, whenever a ping/pong asp buffer finishes, - * 1/2 iram will be filled. - */ - prtd->ram_params.link_bcntrld = - EDMA_CHAN_SLOT(prtd->ram_link2) << 5; - } - return 0; -} - -/* 1 asp tx or rx channel using 2 parameter channels - * 1 ram to/from iram channel using 1 parameter channel - * - * Playback - * ram copy channel kicks off first, - * 1st ram copy of entire iram buffer completion kicks off asp channel - * asp tcc always kicks off ram copy of 1/2 iram buffer - * - * Record - * asp channel starts, tcc kicks off ram copy - */ -static int request_ping_pong(struct snd_pcm_substream *substream, - struct davinci_runtime_data *prtd, - struct snd_dma_buffer *iram_dma) -{ - dma_addr_t asp_src_ping; - dma_addr_t asp_dst_ping; - int ret; - struct davinci_pcm_dma_params *params = prtd->params; - - /* Request ram master channel */ - ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, - davinci_pcm_dma_irq, substream, - prtd->params->ram_chan_q); - if (ret < 0) - goto exit1; - - /* Request ram link channel */ - ret = prtd->ram_link = edma_alloc_slot( - EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit2; - - ret = prtd->asp_link[1] = edma_alloc_slot( - EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit3; - - prtd->ram_link2 = -1; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ret = prtd->ram_link2 = edma_alloc_slot( - EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit4; - } - /* circle ping-pong buffers */ - edma_link(prtd->asp_link[0], prtd->asp_link[1]); - edma_link(prtd->asp_link[1], prtd->asp_link[0]); - /* circle ram buffers */ - edma_link(prtd->ram_link, prtd->ram_link); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - asp_src_ping = iram_dma->addr; - asp_dst_ping = params->dma_addr; /* fifo */ - } else { - asp_src_ping = params->dma_addr; /* fifo */ - asp_dst_ping = iram_dma->addr; - } - /* ping */ - edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT); - edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT); - edma_set_src_index(prtd->asp_link[0], 0, 0); - edma_set_dest_index(prtd->asp_link[0], 0, 0); - - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); - prtd->asp_params.opt |= TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); - edma_write_slot(prtd->asp_link[0], &prtd->asp_params); - - /* pong */ - edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT); - edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT); - edma_set_src_index(prtd->asp_link[1], 0, 0); - edma_set_dest_index(prtd->asp_link[1], 0, 0); - - edma_read_slot(prtd->asp_link[1], &prtd->asp_params); - prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); - /* interrupt after every pong completion */ - prtd->asp_params.opt |= TCINTEN | TCCHEN | - EDMA_TCC(prtd->ram_channel & 0x3f); - edma_write_slot(prtd->asp_link[1], &prtd->asp_params); - - /* ram */ - edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT); - edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT); - pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u," - "for asp:%u %u %u\n", __func__, - prtd->ram_channel, prtd->ram_link, prtd->ram_link2, - prtd->asp_channel, prtd->asp_link[0], - prtd->asp_link[1]); - return 0; -exit4: - edma_free_channel(prtd->asp_link[1]); - prtd->asp_link[1] = -1; -exit3: - edma_free_channel(prtd->ram_link); - prtd->ram_link = -1; -exit2: - edma_free_channel(prtd->ram_channel); - prtd->ram_channel = -1; -exit1: - return ret; -} - -static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) -{ - struct snd_dma_buffer *iram_dma; - struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct davinci_pcm_dma_params *params = prtd->params; - int ret; - - if (!params) - return -ENODEV; - - /* Request asp master DMA channel */ - ret = prtd->asp_channel = edma_alloc_channel(params->channel, - davinci_pcm_dma_irq, substream, - prtd->params->asp_chan_q); - if (ret < 0) - goto exit1; - - /* Request asp link channels */ - ret = prtd->asp_link[0] = edma_alloc_slot( - EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); - if (ret < 0) - goto exit2; - - iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data; - if (iram_dma) { - if (request_ping_pong(substream, prtd, iram_dma) == 0) - return 0; - printk(KERN_WARNING "%s: dma channel allocation failed," - "not using sram\n", __func__); - } - - /* Issue transfer completion IRQ when the channel completes a - * transfer, then always reload from the same slot (by a kind - * of loopback link). The completion IRQ handler will update - * the reload slot with a new buffer. - * - * REVISIT save p_ram here after setting up everything except - * the buffer and its length (ccnt) ... use it as a template - * so davinci_pcm_enqueue_dma() takes less time in IRQ. - */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - prtd->asp_params.opt |= TCINTEN | - EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); - prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5; - edma_write_slot(prtd->asp_link[0], &prtd->asp_params); - return 0; -exit2: - edma_free_channel(prtd->asp_channel); - prtd->asp_channel = -1; -exit1: - return ret; -} - -static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - spin_lock(&prtd->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - edma_start(prtd->asp_channel); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - prtd->ram_channel >= 0) { - /* copy 1st iram buffer */ - edma_start(prtd->ram_channel); - } - break; - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - edma_resume(prtd->asp_channel); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - edma_pause(prtd->asp_channel); - break; - default: - ret = -EINVAL; - break; - } - - spin_unlock(&prtd->lock); - - return ret; -} - -static int davinci_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct davinci_runtime_data *prtd = substream->runtime->private_data; - - davinci_pcm_period_reset(substream); - if (prtd->ram_channel >= 0) { - int ret = ping_pong_dma_setup(substream); - if (ret < 0) - return ret; - - edma_write_slot(prtd->ram_channel, &prtd->ram_params); - edma_write_slot(prtd->asp_channel, &prtd->asp_params); - - print_buf_info(prtd->ram_channel, "ram_channel"); - print_buf_info(prtd->ram_link, "ram_link"); - print_buf_info(prtd->ram_link2, "ram_link2"); - print_buf_info(prtd->asp_channel, "asp_channel"); - print_buf_info(prtd->asp_link[0], "asp_link[0]"); - print_buf_info(prtd->asp_link[1], "asp_link[1]"); - - /* - * There is a phase offset of 2 periods between the position - * used by dma setup and the position reported in the pointer - * function. - * - * The phase offset, when not using ping-pong buffers, is due to - * the two consecutive calls to davinci_pcm_enqueue_dma() below. - * - * Whereas here, with ping-pong buffers, the phase is due to - * there being an entire buffer transfer complete before the - * first dma completion event triggers davinci_pcm_dma_irq(). - */ - davinci_pcm_period_elapsed(substream); - davinci_pcm_period_elapsed(substream); - - return 0; - } - davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); - - /* Copy self-linked parameter RAM entry into master channel */ - edma_read_slot(prtd->asp_link[0], &prtd->asp_params); - edma_write_slot(prtd->asp_channel, &prtd->asp_params); - davinci_pcm_enqueue_dma(substream); - davinci_pcm_period_elapsed(substream); - - return 0; -} - -static snd_pcm_uframes_t -davinci_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - unsigned int offset; - int asp_count; - unsigned int period_size = snd_pcm_lib_period_bytes(substream); - - /* - * There is a phase offset of 2 periods between the position used by dma - * setup and the position reported in the pointer function. Either +2 in - * the dma setup or -2 here in the pointer function (with wrapping, - * both) accounts for this offset -- choose the latter since it makes - * the first-time setup clearer. - */ - spin_lock(&prtd->lock); - asp_count = prtd->period - 2; - spin_unlock(&prtd->lock); - - if (asp_count < 0) - asp_count += runtime->periods; - asp_count *= period_size; - - offset = bytes_to_frames(runtime, asp_count); - if (offset >= runtime->buffer_size) - offset = 0; - - return offset; -} - -static int davinci_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd; - struct snd_pcm_hardware *ppcm; - int ret = 0; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_pcm_dma_params *pa; - struct davinci_pcm_dma_params *params; - - pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - if (!pa) - return -ENODEV; - params = &pa[substream->stream]; - - ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - &pcm_hardware_playback : &pcm_hardware_capture; - allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); - snd_soc_set_runtime_hwparams(substream, ppcm); - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - - prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - prtd->params = params; - prtd->asp_channel = -1; - prtd->asp_link[0] = prtd->asp_link[1] = -1; - prtd->ram_channel = -1; - prtd->ram_link = -1; - prtd->ram_link2 = -1; - - runtime->private_data = prtd; - - ret = davinci_pcm_dma_request(substream); - if (ret) { - printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n"); - kfree(prtd); - } - - return ret; -} - -static int davinci_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct davinci_runtime_data *prtd = runtime->private_data; - - if (prtd->ram_channel >= 0) - edma_stop(prtd->ram_channel); - if (prtd->asp_channel >= 0) - edma_stop(prtd->asp_channel); - if (prtd->asp_link[0] >= 0) - edma_unlink(prtd->asp_link[0]); - if (prtd->asp_link[1] >= 0) - edma_unlink(prtd->asp_link[1]); - if (prtd->ram_link >= 0) - edma_unlink(prtd->ram_link); - - if (prtd->asp_link[0] >= 0) - edma_free_slot(prtd->asp_link[0]); - if (prtd->asp_link[1] >= 0) - edma_free_slot(prtd->asp_link[1]); - if (prtd->asp_channel >= 0) - edma_free_channel(prtd->asp_channel); - if (prtd->ram_link >= 0) - edma_free_slot(prtd->ram_link); - if (prtd->ram_link2 >= 0) - edma_free_slot(prtd->ram_link2); - if (prtd->ram_channel >= 0) - edma_free_channel(prtd->ram_channel); - - kfree(prtd); - - return 0; -} - -static int davinci_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - return snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); -} - -static int davinci_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int davinci_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -static struct snd_pcm_ops davinci_pcm_ops = { - .open = davinci_pcm_open, - .close = davinci_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = davinci_pcm_hw_params, - .hw_free = davinci_pcm_hw_free, - .prepare = davinci_pcm_prepare, - .trigger = davinci_pcm_trigger, - .pointer = davinci_pcm_pointer, - .mmap = davinci_pcm_mmap, -}; - -static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream, - size_t size) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " - "size=%d\n", (void *) buf->area, (void *) buf->addr, size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static void davinci_pcm_free(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - struct snd_dma_buffer *iram_dma; - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - iram_dma = buf->private_data; - if (iram_dma) { - davinci_free_sram(substream, iram_dma); - kfree(iram_dma); - } - } -} - -static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - int ret; - - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { - ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK, - pcm_hardware_playback.buffer_bytes_max); - if (ret) - return ret; - } - - if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE, - pcm_hardware_capture.buffer_bytes_max); - if (ret) - return ret; - } - - return 0; -} - -static struct snd_soc_platform_driver davinci_soc_platform = { - .ops = &davinci_pcm_ops, - .pcm_new = davinci_pcm_new, - .pcm_free = davinci_pcm_free, -}; - -int davinci_soc_platform_register(struct device *dev) -{ - return devm_snd_soc_register_platform(dev, &davinci_soc_platform); -} -EXPORT_SYMBOL_GPL(davinci_soc_platform_register); - -MODULE_AUTHOR("Vladimir Barinov"); -MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h deleted file mode 100644 index 0fe2346a9aa2..000000000000 --- a/sound/soc/davinci/davinci-pcm.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ALSA PCM interface for the TI DAVINCI processor - * - * Author: Vladimir Barinov, - * Copyright: (C) 2007 MontaVista Software, Inc., - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _DAVINCI_PCM_H -#define _DAVINCI_PCM_H - -#include -#include -#include - -struct davinci_pcm_dma_params { - int channel; /* sync dma channel ID */ - unsigned short acnt; - dma_addr_t dma_addr; /* device physical address for DMA */ - unsigned sram_size; - struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */ - enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ - enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ - unsigned char data_type; /* xfer data type */ - unsigned char convert_mono_stereo; - unsigned int fifo_level; -}; - -#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC) -int davinci_soc_platform_register(struct device *dev); -#else -static inline int davinci_soc_platform_register(struct device *dev) -{ - return 0; -} -#endif /* CONFIG_SND_DAVINCI_SOC */ - -#endif -- GitLab From 6742e15cf92a8dc3065843a627952ed518e08267 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 3 Mar 2015 13:28:53 +0200 Subject: [PATCH 0208/1910] ASoC: omap-pcm: Allow only formats with 1, 2, and 4 byte physical size sDMA support only transfer elements with 1, 2, and 4 byte physical size. Initialize the pcm driver accordingly. Signed-off-by: Jyri Sarha Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-pcm.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index f4b05bc23e4b..e49ee2383a88 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -39,7 +39,7 @@ #define pcm_omap1510() 0 #endif -static const struct snd_pcm_hardware omap_pcm_hardware = { +static struct snd_pcm_hardware omap_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | @@ -53,6 +53,24 @@ static const struct snd_pcm_hardware omap_pcm_hardware = { .buffer_bytes_max = 128 * 1024, }; +/* sDMA supports only 1, 2, and 4 byte transfer elements. */ +static void omap_pcm_limit_supported_formats(void) +{ + int i; + + for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + switch (snd_pcm_format_physical_width(i)) { + case 8: + case 16: + case 32: + omap_pcm_hardware.formats |= (1LL << i); + break; + default: + break; + } + } +} + /* this may get called several times by oss emulation */ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -235,6 +253,7 @@ static struct snd_soc_platform_driver omap_soc_platform = { int omap_pcm_platform_register(struct device *dev) { + omap_pcm_limit_supported_formats(); return devm_snd_soc_register_platform(dev, &omap_soc_platform); } EXPORT_SYMBOL_GPL(omap_pcm_platform_register); -- GitLab From 2bf9eba14340a53776a742f2c8a0bfbd9c86d259 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 3 Mar 2015 18:31:29 +0800 Subject: [PATCH 0209/1910] ASoC: rt5670: Fix the speaker mono output issue We need to set left/right control for the speaker amp to get stereo output on speaker. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0632b7458a53..592f961b5de5 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2700,6 +2700,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_write(rt5670->regmap, RT5670_RESET, 0); + regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val); + if (val >= 4) + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980); + else + regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00); + ret = regmap_register_patch(rt5670->regmap, init_list, ARRAY_SIZE(init_list)); if (ret != 0) -- GitLab From bbed297d373471c8e4c3183bf67472a768576664 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Sun, 22 Feb 2015 16:43:21 +0000 Subject: [PATCH 0210/1910] ASoC: wm8804: Split out bus drivers Simplify dependencies by using new style split out bus interfaces. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 18 ++++- sound/soc/codecs/Makefile | 4 + sound/soc/codecs/wm8804-i2c.c | 64 ++++++++++++++++ sound/soc/codecs/wm8804-spi.c | 56 ++++++++++++++ sound/soc/codecs/wm8804.c | 139 ++++------------------------------ sound/soc/codecs/wm8804.h | 7 ++ 6 files changed, 162 insertions(+), 126 deletions(-) create mode 100644 sound/soc/codecs/wm8804-i2c.c create mode 100644 sound/soc/codecs/wm8804-spi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 064e6c18e109..1d17988df796 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8770 if SPI_MASTER select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8782 - select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8804_I2C if I2C + select SND_SOC_WM8804_SPI if SPI_MASTER select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C @@ -744,8 +745,19 @@ config SND_SOC_WM8782 tristate config SND_SOC_WM8804 - tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" - depends on SND_SOC_I2C_AND_SPI + tristate + +config SND_SOC_WM8804_I2C + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C" + depends on I2C + select SND_SOC_WM8804 + select REGMAP_I2C + +config SND_SOC_WM8804_SPI + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI" + depends on SPI_MASTER + select SND_SOC_WM8804 + select REGMAP_SPI config SND_SOC_WM8900 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69b8666d187a..7acb6c174cb4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o snd-soc-wm8776-objs := wm8776.o snd-soc-wm8782-objs := wm8782.o snd-soc-wm8804-objs := wm8804.o +snd-soc-wm8804-i2c-objs := wm8804-i2c.o +snd-soc-wm8804-spi-objs := wm8804-spi.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8904-objs := wm8904.o @@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o +obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o +obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c new file mode 100644 index 000000000000..5bd4af2b4059 --- /dev/null +++ b/sound/soc/codecs/wm8804-i2c.c @@ -0,0 +1,64 @@ +/* + * wm8804-i2c.c -- WM8804 S/PDIF transceiver driver - I2C + * + * Copyright 2015 Cirrus Logic Inc + * + * Author: Charles Keepax + * + * This program is free software; you can 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 +#include +#include + +#include "wm8804.h" + +static int wm8804_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return wm8804_probe(&i2c->dev, regmap); +} + +static int wm8804_i2c_remove(struct i2c_client *i2c) +{ + wm8804_remove(&i2c->dev); + return 0; +} + +static const struct i2c_device_id wm8804_i2c_id[] = { + { "wm8804", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); + +static const struct of_device_id wm8804_of_match[] = { + { .compatible = "wlf,wm8804", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8804_of_match); + +static struct i2c_driver wm8804_i2c_driver = { + .driver = { + .name = "wm8804", + .owner = THIS_MODULE, + .of_match_table = wm8804_of_match, + }, + .probe = wm8804_i2c_probe, + .remove = wm8804_i2c_remove, + .id_table = wm8804_i2c_id +}; + +module_i2c_driver(wm8804_i2c_driver); + +MODULE_DESCRIPTION("ASoC WM8804 driver - I2C"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c new file mode 100644 index 000000000000..287e11e90794 --- /dev/null +++ b/sound/soc/codecs/wm8804-spi.c @@ -0,0 +1,56 @@ +/* + * wm8804-spi.c -- WM8804 S/PDIF transceiver driver - SPI + * + * Copyright 2015 Cirrus Logic Inc + * + * Author: Charles Keepax + * + * This program is free software; you can 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 +#include +#include + +#include "wm8804.h" + +static int wm8804_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return wm8804_probe(&spi->dev, regmap); +} + +static int wm8804_spi_remove(struct spi_device *spi) +{ + wm8804_remove(&spi->dev); + return 0; +} + +static const struct of_device_id wm8804_of_match[] = { + { .compatible = "wlf,wm8804", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8804_of_match); + +static struct spi_driver wm8804_spi_driver = { + .driver = { + .name = "wm8804", + .owner = THIS_MODULE, + .of_match_table = wm8804_of_match, + }, + .probe = wm8804_spi_probe, + .remove = wm8804_spi_remove +}; + +module_spi_driver(wm8804_spi_driver); + +MODULE_DESCRIPTION("ASoC WM8804 driver - SPI"); +MODULE_AUTHOR("Charles Keepax "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index b2b0e68f707e..b5a04fc5060f 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -15,10 +15,7 @@ #include #include #include -#include #include -#include -#include #include #include #include @@ -518,7 +515,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm8804_remove(struct snd_soc_codec *codec) +static int wm8804_codec_remove(struct snd_soc_codec *codec) { struct wm8804_priv *wm8804; int i; @@ -531,7 +528,7 @@ static int wm8804_remove(struct snd_soc_codec *codec) return 0; } -static int wm8804_probe(struct snd_soc_codec *codec) +static int wm8804_codec_probe(struct snd_soc_codec *codec) { struct wm8804_priv *wm8804; int i, id1, id2, ret; @@ -649,8 +646,8 @@ static struct snd_soc_dai_driver wm8804_dai = { }; static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { - .probe = wm8804_probe, - .remove = wm8804_remove, + .probe = wm8804_codec_probe, + .remove = wm8804_codec_remove, .set_bias_level = wm8804_set_bias_level, .idle_bias_off = true, @@ -658,13 +655,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .num_controls = ARRAY_SIZE(wm8804_snd_controls), }; -static const struct of_device_id wm8804_of_match[] = { - { .compatible = "wlf,wm8804", }, - { } -}; -MODULE_DEVICE_TABLE(of, wm8804_of_match); - -static const struct regmap_config wm8804_regmap_config = { +const struct regmap_config wm8804_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -675,128 +666,30 @@ static const struct regmap_config wm8804_regmap_config = { .reg_defaults = wm8804_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), }; +EXPORT_SYMBOL_GPL(wm8804_regmap_config); -#if defined(CONFIG_SPI_MASTER) -static int wm8804_spi_probe(struct spi_device *spi) +int wm8804_probe(struct device *dev, struct regmap *regmap) { struct wm8804_priv *wm8804; - int ret; - wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL); + wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL); if (!wm8804) return -ENOMEM; - wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); - if (IS_ERR(wm8804->regmap)) { - ret = PTR_ERR(wm8804->regmap); - return ret; - } - - spi_set_drvdata(spi, wm8804); + dev_set_drvdata(dev, wm8804); - ret = snd_soc_register_codec(&spi->dev, - &soc_codec_dev_wm8804, &wm8804_dai, 1); - - return ret; -} - -static int wm8804_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} - -static struct spi_driver wm8804_spi_driver = { - .driver = { - .name = "wm8804", - .owner = THIS_MODULE, - .of_match_table = wm8804_of_match, - }, - .probe = wm8804_spi_probe, - .remove = wm8804_spi_remove -}; -#endif - -#if IS_ENABLED(CONFIG_I2C) -static int wm8804_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8804_priv *wm8804; - int ret; - - wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL); - if (!wm8804) - return -ENOMEM; + wm8804->regmap = regmap; - wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); - if (IS_ERR(wm8804->regmap)) { - ret = PTR_ERR(wm8804->regmap); - return ret; - } - - i2c_set_clientdata(i2c, wm8804); - - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8804, &wm8804_dai, 1); - return ret; -} - -static int wm8804_i2c_remove(struct i2c_client *i2c) -{ - snd_soc_unregister_codec(&i2c->dev); - return 0; -} - -static const struct i2c_device_id wm8804_i2c_id[] = { - { "wm8804", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); - -static struct i2c_driver wm8804_i2c_driver = { - .driver = { - .name = "wm8804", - .owner = THIS_MODULE, - .of_match_table = wm8804_of_match, - }, - .probe = wm8804_i2c_probe, - .remove = wm8804_i2c_remove, - .id_table = wm8804_i2c_id -}; -#endif - -static int __init wm8804_modinit(void) -{ - int ret = 0; - -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8804_i2c_driver); - if (ret) { - printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n", - ret); - } -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8804_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n", - ret); - } -#endif - return ret; + return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, + &wm8804_dai, 1); } -module_init(wm8804_modinit); +EXPORT_SYMBOL_GPL(wm8804_probe); -static void __exit wm8804_exit(void) +void wm8804_remove(struct device *dev) { -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8804_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8804_spi_driver); -#endif + snd_soc_unregister_codec(dev); } -module_exit(wm8804_exit); +EXPORT_SYMBOL_GPL(wm8804_remove); MODULE_DESCRIPTION("ASoC WM8804 driver"); MODULE_AUTHOR("Dimitris Papastamos "); diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h index e72d4f4ba6b1..a39a2563dc67 100644 --- a/sound/soc/codecs/wm8804.h +++ b/sound/soc/codecs/wm8804.h @@ -13,6 +13,8 @@ #ifndef _WM8804_H #define _WM8804_H +#include + /* * Register values. */ @@ -62,4 +64,9 @@ #define WM8804_MCLKDIV_256FS 0 #define WM8804_MCLKDIV_128FS 1 +extern const struct regmap_config wm8804_regmap_config; + +int wm8804_probe(struct device *dev, struct regmap *regmap); +void wm8804_remove(struct device *dev); + #endif /* _WM8804_H */ -- GitLab From 6f2c9348095ae1a489abafe2ab3db7deca406e49 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Sun, 22 Feb 2015 16:43:22 +0000 Subject: [PATCH 0211/1910] ASoC: wm8804: Merge CODEC probe and bus probe All of the things in the CODEC probe, such as getting the regulators and verifying the chip ID, are better done in bus probe. It is better to fail during bus probe if this is the wrong chip and all resource allocation should be done in the bus probe anyway. This patch merges the CODEC probe into bus probe. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 180 +++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 98 deletions(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index b5a04fc5060f..1bd4ace29594 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -182,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg) } } -static int wm8804_reset(struct snd_soc_codec *codec) +static int wm8804_reset(struct wm8804_priv *wm8804) { - return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0); + return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0); } static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -515,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm8804_codec_remove(struct snd_soc_codec *codec) -{ - struct wm8804_priv *wm8804; - int i; - - wm8804 = snd_soc_codec_get_drvdata(codec); - - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) - regulator_unregister_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); - return 0; -} - -static int wm8804_codec_probe(struct snd_soc_codec *codec) -{ - struct wm8804_priv *wm8804; - int i, id1, id2, ret; - - wm8804 = snd_soc_codec_get_drvdata(codec); - - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) - wm8804->supplies[i].supply = wm8804_supply_names[i]; - - ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), - wm8804->supplies); - if (ret) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; - wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; - - /* This should really be moved into the regulator core */ - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { - ret = regulator_register_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); - if (ret != 0) { - dev_err(codec->dev, - "Failed to register regulator notifier: %d\n", - ret); - } - } - - ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), - wm8804->supplies); - if (ret) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); - return ret; - } - - id1 = snd_soc_read(codec, WM8804_RST_DEVID1); - if (id1 < 0) { - dev_err(codec->dev, "Failed to read device ID: %d\n", id1); - ret = id1; - goto err_reg_enable; - } - - id2 = snd_soc_read(codec, WM8804_DEVID2); - if (id2 < 0) { - dev_err(codec->dev, "Failed to read device ID: %d\n", id2); - ret = id2; - goto err_reg_enable; - } - - id2 = (id2 << 8) | id1; - - if (id2 != 0x8805) { - dev_err(codec->dev, "Invalid device ID: %#x\n", id2); - ret = -EINVAL; - goto err_reg_enable; - } - - ret = snd_soc_read(codec, WM8804_DEVREV); - if (ret < 0) { - dev_err(codec->dev, "Failed to read device revision: %d\n", - ret); - goto err_reg_enable; - } - dev_info(codec->dev, "revision %c\n", ret + 'A'); - - ret = wm8804_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); - goto err_reg_enable; - } - - return 0; - -err_reg_enable: - regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); - return ret; -} - static const struct snd_soc_dai_ops wm8804_dai_ops = { .hw_params = wm8804_hw_params, .set_fmt = wm8804_set_fmt, @@ -646,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = { }; static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { - .probe = wm8804_codec_probe, - .remove = wm8804_codec_remove, .set_bias_level = wm8804_set_bias_level, .idle_bias_off = true, @@ -671,6 +575,8 @@ EXPORT_SYMBOL_GPL(wm8804_regmap_config); int wm8804_probe(struct device *dev, struct regmap *regmap) { struct wm8804_priv *wm8804; + unsigned int id1, id2; + int i, ret; wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL); if (!wm8804) @@ -680,13 +586,91 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) wm8804->regmap = regmap; + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) + wm8804->supplies[i].supply = wm8804_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies), + wm8804->supplies); + if (ret) { + dev_err(dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; + wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; + + /* This should really be moved into the regulator core */ + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { + ret = regulator_register_notifier(wm8804->supplies[i].consumer, + &wm8804->disable_nb[i]); + if (ret != 0) { + dev_err(dev, + "Failed to register regulator notifier: %d\n", + ret); + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), + wm8804->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + goto err_reg_enable; + } + + ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); + if (ret < 0) { + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto err_reg_enable; + } + + ret = regmap_read(regmap, WM8804_DEVID2, &id2); + if (ret < 0) { + dev_err(dev, "Failed to read device ID: %d\n", ret); + goto err_reg_enable; + } + + id2 = (id2 << 8) | id1; + + if (id2 != 0x8805) { + dev_err(dev, "Invalid device ID: %#x\n", id2); + ret = -EINVAL; + goto err_reg_enable; + } + + ret = regmap_read(regmap, WM8804_DEVREV, &id1); + if (ret < 0) { + dev_err(dev, "Failed to read device revision: %d\n", + ret); + goto err_reg_enable; + } + dev_info(dev, "revision %c\n", id1 + 'A'); + + ret = wm8804_reset(wm8804); + if (ret < 0) { + dev_err(dev, "Failed to issue reset: %d\n", ret); + goto err_reg_enable; + } + return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, &wm8804_dai, 1); + +err_reg_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); + return ret; } EXPORT_SYMBOL_GPL(wm8804_probe); void wm8804_remove(struct device *dev) { + struct wm8804_priv *wm8804; + int i; + + wm8804 = dev_get_drvdata(dev); + + for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) + regulator_unregister_notifier(wm8804->supplies[i].consumer, + &wm8804->disable_nb[i]); + snd_soc_unregister_codec(dev); } EXPORT_SYMBOL_GPL(wm8804_remove); -- GitLab From 6afda7f5075440f6737d953ab00fc82efb6cabae Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 5 Mar 2015 16:55:21 +0200 Subject: [PATCH 0212/1910] ASoC: davinci-mcasp: Allow complete shutdown of McASP when not in use Rearrange the pm_runtime_get/put_sync calls so the IP will be turned off when it is not in use. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0c882995a357..33cea0728cd2 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -62,6 +62,7 @@ struct davinci_mcasp_context { u32 config_regs[ARRAY_SIZE(context_regs)]; u32 afifo_regs[2]; /* for read/write fifo control registers */ u32 *xrsr_regs; /* for serializer configuration */ + bool pm_state; }; struct davinci_mcasp { @@ -519,7 +520,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); } out: - pm_runtime_put_sync(mcasp->dev); + pm_runtime_put(mcasp->dev); return ret; } @@ -528,6 +529,7 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + pm_runtime_get_sync(mcasp->dev); switch (div_id) { case 0: /* MCLK divider */ mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, @@ -553,6 +555,7 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, return -EINVAL; } + pm_runtime_put(mcasp->dev); return 0; } @@ -567,6 +570,7 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + pm_runtime_get_sync(mcasp->dev); if (dir == SND_SOC_CLOCK_OUT) { mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); @@ -579,6 +583,7 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, mcasp->sysclk_freq = freq; + pm_runtime_put(mcasp->dev); return 0; } @@ -1053,6 +1058,10 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) u32 reg; int i; + context->pm_state = pm_runtime_enabled(mcasp->dev) + if (!context->pm_state) + pm_runtime_get_sync(mcasp->dev); + for (i = 0; i < ARRAY_SIZE(context_regs); i++) context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); @@ -1069,6 +1078,8 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) context->xrsr_regs[i] = mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i)); + pm_runtime_put_sync(mcasp->dev); + return 0; } @@ -1079,6 +1090,8 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) u32 reg; int i; + pm_runtime_get_sync(mcasp->dev); + for (i = 0; i < ARRAY_SIZE(context_regs); i++) mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); @@ -1095,6 +1108,9 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), context->xrsr_regs[i]); + if (!context->pm_state) + pm_runtime_put_sync(mcasp->dev); + return 0; } #else @@ -1398,13 +1414,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); - if (IS_ERR_VALUE(ret)) { - dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - pm_runtime_disable(&pdev->dev); - return ret; - } - mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!mcasp->base) { dev_err(&pdev->dev, "ioremap failed\n"); @@ -1584,14 +1593,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) return 0; err: - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; } static int davinci_mcasp_remove(struct platform_device *pdev) { - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; -- GitLab From 0be9653a02830637ed385d99bf898d456e8eae8f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:39:21 +0000 Subject: [PATCH 0213/1910] ASoC: wm8804: Use new devres regulator_register_notifier This is more idiomatic and also fixes an issue where the notifiers were being leaked if probe failed. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 1bd4ace29594..7804ddf53a04 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -601,8 +601,10 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { - ret = regulator_register_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); + struct regulator *regulator = wm8804->supplies[i].consumer; + + ret = devm_regulator_register_notifier(regulator, + &wm8804->disable_nb[i]); if (ret != 0) { dev_err(dev, "Failed to register regulator notifier: %d\n", @@ -662,15 +664,6 @@ EXPORT_SYMBOL_GPL(wm8804_probe); void wm8804_remove(struct device *dev) { - struct wm8804_priv *wm8804; - int i; - - wm8804 = dev_get_drvdata(dev); - - for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) - regulator_unregister_notifier(wm8804->supplies[i].consumer, - &wm8804->disable_nb[i]); - snd_soc_unregister_codec(dev); } EXPORT_SYMBOL_GPL(wm8804_remove); -- GitLab From fcf638f9953eb7f3b97fad7e970ae59dcdbd70c1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:39:22 +0000 Subject: [PATCH 0214/1910] ASoC: wm8804: Fix small issues in probe error paths This patch fixes some small issues on the probe error paths. Firstly, fail probe if we can't register the regulator notifiers as this will cause the cache to never be synchronised which will result in odd behaviour if the regulators are controllable. Secondly, we don't need to call regulator_bulk_disable if the enable fails, because the regulator core will handle this clean up for us. Finally, we need to disable the regulators if snd_soc_register_codecs fails. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 7804ddf53a04..f44da83f50dc 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -609,6 +609,7 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) dev_err(dev, "Failed to register regulator notifier: %d\n", ret); + return ret; } } @@ -616,7 +617,7 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) wm8804->supplies); if (ret) { dev_err(dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_enable; + return ret; } ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); @@ -653,8 +654,14 @@ int wm8804_probe(struct device *dev, struct regmap *regmap) goto err_reg_enable; } - return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, - &wm8804_dai, 1); + ret = snd_soc_register_codec(dev, &soc_codec_dev_wm8804, + &wm8804_dai, 1); + if (ret < 0) { + dev_err(dev, "Failed to register CODEC: %d\n", ret); + goto err_reg_enable; + } + + return 0; err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); -- GitLab From 45ad3e67f663af3f7988552165e8b8ebddde0ac7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:42:51 +0000 Subject: [PATCH 0215/1910] ASoC: wm8804: Update DT binding document to cover regulator supplies Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8804.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/wm8804.txt b/Documentation/devicetree/bindings/sound/wm8804.txt index 4d3a56f38adc..10ef07606b84 100644 --- a/Documentation/devicetree/bindings/sound/wm8804.txt +++ b/Documentation/devicetree/bindings/sound/wm8804.txt @@ -10,6 +10,9 @@ Required properties: - reg : the I2C address of the device for I2C, the chip select number for SPI. + - PVDD-supply, DVDD-supply : Power supplies for the device, as covered + in Documentation/devicetree/bindings/regulator/regulator.txt + Example: codec: wm8804@1a { -- GitLab From 012baec5c1eaab7ad98b461eb7afae2faf79dbea Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 5 Mar 2015 03:37:39 +0800 Subject: [PATCH 0216/1910] ASoC: tegra: fix platform_no_drv_owner.cocci warnings sound/soc/tegra/tegra_rt5677.c:334:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Anatol Pomozov Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_rt5677.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index e4cf978a6e3a..4453566405ef 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -331,7 +331,6 @@ static const struct of_device_id tegra_rt5677_of_match[] = { static struct platform_driver tegra_rt5677_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = tegra_rt5677_of_match, }, -- GitLab From cd59f13823ae65a16b7c99fdd338ebac0c6487f2 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:53 -0800 Subject: [PATCH 0217/1910] ASoC: qcom: add LPASS header files Add the LPASS header files for ipq806x SOC. This includes the register definitions for the ipq806x LPAIF, and the structure definition for the driver data. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-ipq806x.h | 172 +++++++++++++++++++++++++++ sound/soc/qcom/lpass.h | 51 ++++++++ 2 files changed, 223 insertions(+) create mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h create mode 100644 sound/soc/qcom/lpass.h diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-ipq806x.h new file mode 100644 index 000000000000..dc423b888842 --- /dev/null +++ b/sound/soc/qcom/lpass-lpaif-ipq806x.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS + */ + +#ifndef __LPASS_LPAIF_H__ +#define __LPASS_LPAIF_H__ + +#define LPAIF_BANK_OFFSET 0x1000 + +/* LPAIF I2S */ + +#define LPAIF_I2SCTL_REG_BASE 0x0010 +#define LPAIF_I2SCTL_REG_STRIDE 0x4 +#define LPAIF_I2SCTL_REG_ADDR(addr, port) \ + (LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port))) + +enum lpaif_i2s_ports { + LPAIF_I2S_PORT_MIN = 0, + + LPAIF_I2S_PORT_CODEC_SPK = 0, + LPAIF_I2S_PORT_CODEC_MIC = 1, + LPAIF_I2S_PORT_SEC_SPK = 2, + LPAIF_I2S_PORT_SEC_MIC = 3, + LPAIF_I2S_PORT_MI2S = 4, + + LPAIF_I2S_PORT_MAX = 4, + LPAIF_I2S_PORT_NUM = 5, +}; + +#define LPAIF_I2SCTL_REG(port) LPAIF_I2SCTL_REG_ADDR(0x0, (port)) + +#define LPAIF_I2SCTL_LOOPBACK_MASK 0x8000 +#define LPAIF_I2SCTL_LOOPBACK_SHIFT 15 +#define LPAIF_I2SCTL_LOOPBACK_DISABLE (0 << LPAIF_I2SCTL_LOOPBACK_SHIFT) +#define LPAIF_I2SCTL_LOOPBACK_ENABLE (1 << LPAIF_I2SCTL_LOOPBACK_SHIFT) + +#define LPAIF_I2SCTL_SPKEN_MASK 0x4000 +#define LPAIF_I2SCTL_SPKEN_SHIFT 14 +#define LPAIF_I2SCTL_SPKEN_DISABLE (0 << LPAIF_I2SCTL_SPKEN_SHIFT) +#define LPAIF_I2SCTL_SPKEN_ENABLE (1 << LPAIF_I2SCTL_SPKEN_SHIFT) + +#define LPAIF_I2SCTL_SPKMODE_MASK 0x3C00 +#define LPAIF_I2SCTL_SPKMODE_SHIFT 10 +#define LPAIF_I2SCTL_SPKMODE_NONE (0 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_SD0 (1 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_SD1 (2 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_SD2 (3 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_SD3 (4 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_QUAD01 (5 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_QUAD23 (6 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_6CH (7 << LPAIF_I2SCTL_SPKMODE_SHIFT) +#define LPAIF_I2SCTL_SPKMODE_8CH (8 << LPAIF_I2SCTL_SPKMODE_SHIFT) + +#define LPAIF_I2SCTL_SPKMONO_MASK 0x0200 +#define LPAIF_I2SCTL_SPKMONO_SHIFT 9 +#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT) +#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT) + +#define LPAIF_I2SCTL_WSSRC_MASK 0x0004 +#define LPAIF_I2SCTL_WSSRC_SHIFT 2 +#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT) +#define LPAIF_I2SCTL_WSSRC_EXTERNAL (1 << LPAIF_I2SCTL_WSSRC_SHIFT) + +#define LPAIF_I2SCTL_BITWIDTH_MASK 0x0003 +#define LPAIF_I2SCTL_BITWIDTH_SHIFT 0 +#define LPAIF_I2SCTL_BITWIDTH_16 (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT) +#define LPAIF_I2SCTL_BITWIDTH_24 (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT) +#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT) + +/* LPAIF IRQ */ + +#define LPAIF_IRQ_REG_BASE 0x3000 +#define LPAIF_IRQ_REG_STRIDE 0x1000 +#define LPAIF_IRQ_REG_ADDR(addr, port) \ + (LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port))) + +enum lpaif_irq_ports { + LPAIF_IRQ_PORT_MIN = 0, + + LPAIF_IRQ_PORT_HOST = 0, + LPAIF_IRQ_PORT_ADSP = 1, + + LPAIF_IRQ_PORT_MAX = 2, + LPAIF_IRQ_PORT_NUM = 3, +}; + +#define LPAIF_IRQEN_REG(port) LPAIF_IRQ_REG_ADDR(0x0, (port)) +#define LPAIF_IRQSTAT_REG(port) LPAIF_IRQ_REG_ADDR(0x4, (port)) +#define LPAIF_IRQCLEAR_REG(port) LPAIF_IRQ_REG_ADDR(0xC, (port)) + +#define LPAIF_IRQ_BITSTRIDE 3 +#define LPAIF_IRQ_PER(chan) (1 << (LPAIF_IRQ_BITSTRIDE * (chan))) +#define LPAIF_IRQ_XRUN(chan) (2 << (LPAIF_IRQ_BITSTRIDE * (chan))) +#define LPAIF_IRQ_ERR(chan) (4 << (LPAIF_IRQ_BITSTRIDE * (chan))) +#define LPAIF_IRQ_ALL(chan) (7 << (LPAIF_IRQ_BITSTRIDE * (chan))) + +/* LPAIF DMA */ + +#define LPAIF_RDMA_REG_BASE 0x6000 +#define LPAIF_RDMA_REG_STRIDE 0x1000 +#define LPAIF_RDMA_REG_ADDR(addr, chan) \ + (LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan))) + +enum lpaif_dma_channels { + LPAIF_RDMA_CHAN_MIN = 0, + + LPAIF_RDMA_CHAN_MI2S = 0, + LPAIF_RDMA_CHAN_PCM0 = 1, + LPAIF_RDMA_CHAN_PCM1 = 2, + + LPAIF_RDMA_CHAN_MAX = 4, + LPAIF_RDMA_CHAN_NUM = 5, +}; + +#define LPAIF_RDMACTL_REG(chan) LPAIF_RDMA_REG_ADDR(0x00, (chan)) +#define LPAIF_RDMABASE_REG(chan) LPAIF_RDMA_REG_ADDR(0x04, (chan)) +#define LPAIF_RDMABUFF_REG(chan) LPAIF_RDMA_REG_ADDR(0x08, (chan)) +#define LPAIF_RDMACURR_REG(chan) LPAIF_RDMA_REG_ADDR(0x0C, (chan)) +#define LPAIF_RDMAPER_REG(chan) LPAIF_RDMA_REG_ADDR(0x10, (chan)) + +#define LPAIF_RDMACTL_BURSTEN_MASK 0x800 +#define LPAIF_RDMACTL_BURSTEN_SHIFT 11 +#define LPAIF_RDMACTL_BURSTEN_SINGLE (0 << LPAIF_RDMACTL_BURSTEN_SHIFT) +#define LPAIF_RDMACTL_BURSTEN_INCR4 (1 << LPAIF_RDMACTL_BURSTEN_SHIFT) + +#define LPAIF_RDMACTL_WPSCNT_MASK 0x700 +#define LPAIF_RDMACTL_WPSCNT_SHIFT 8 +#define LPAIF_RDMACTL_WPSCNT_ONE (0 << LPAIF_RDMACTL_WPSCNT_SHIFT) +#define LPAIF_RDMACTL_WPSCNT_TWO (1 << LPAIF_RDMACTL_WPSCNT_SHIFT) +#define LPAIF_RDMACTL_WPSCNT_THREE (2 << LPAIF_RDMACTL_WPSCNT_SHIFT) +#define LPAIF_RDMACTL_WPSCNT_FOUR (3 << LPAIF_RDMACTL_WPSCNT_SHIFT) +#define LPAIF_RDMACTL_WPSCNT_SIX (5 << LPAIF_RDMACTL_WPSCNT_SHIFT) +#define LPAIF_RDMACTL_WPSCNT_EIGHT (7 << LPAIF_RDMACTL_WPSCNT_SHIFT) + +#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 +#define LPAIF_RDMACTL_AUDINTF_SHIFT 4 +#define LPAIF_RDMACTL_AUDINTF_NONE (0 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_CODEC (1 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_PCM (2 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_SEC_I2S (3 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_MI2S (4 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_HDMI (5 << LPAIF_RDMACTL_AUDINTF_SHIFT) +#define LPAIF_RDMACTL_AUDINTF_SEC_PCM (7 << LPAIF_RDMACTL_AUDINTF_SHIFT) + +#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E +#define LPAIF_RDMACTL_FIFOWM_SHIFT 1 +#define LPAIF_RDMACTL_FIFOWM_1 (0 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_2 (1 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_3 (2 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_4 (3 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_5 (4 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_6 (5 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_7 (6 << LPAIF_RDMACTL_FIFOWM_SHIFT) +#define LPAIF_RDMACTL_FIFOWM_8 (7 << LPAIF_RDMACTL_FIFOWM_SHIFT) + +#define LPAIF_RDMACTL_ENABLE_MASK 0x1 +#define LPAIF_RDMACTL_ENABLE_SHIFT 0 +#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) +#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) + +#endif /* __LPASS_LPAIF_H__ */ diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h new file mode 100644 index 000000000000..5c99b3dace86 --- /dev/null +++ b/sound/soc/qcom/lpass.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * lpass.h - Definitions for the QTi LPASS + */ + +#ifndef __LPASS_H__ +#define __LPASS_H__ + +#include +#include +#include +#include + +#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 + +/* Both the CPU DAI and platform drivers will access this data */ +struct lpass_data { + + /* AHB-I/X bus clocks inside the low-power audio subsystem (LPASS) */ + struct clk *ahbix_clk; + + /* MI2S system clock */ + struct clk *mi2s_osr_clk; + + /* MI2S bit clock (derived from system clock by a divider */ + struct clk *mi2s_bit_clk; + + /* low-power audio interface (LPAIF) registers */ + void __iomem *lpaif; + + /* regmap backed by the low-power audio interface (LPAIF) registers */ + struct regmap *lpaif_map; + + /* interrupts from the low-power audio interface (LPAIF) */ + int lpaif_irq; +}; + +/* register the platform driver from the CPU DAI driver */ +int asoc_qcom_lpass_platform_register(struct platform_device *); + +#endif /* __LPASS_H__ */ -- GitLab From 80beab8e1d86d7da843e6c3e439bbca5320c568d Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:54 -0800 Subject: [PATCH 0218/1910] ASoC: qcom: Add LPASS CPU DAI driver Add the CPU DAI driver for the Qualcomm Technologies low-power audio subsystem (LPASS). Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 510 +++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 sound/soc/qcom/lpass-cpu.c diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c new file mode 100644 index 000000000000..d5167131787f --- /dev/null +++ b/sound/soc/qcom/lpass-cpu.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-lpaif-ipq806x.h" +#include "lpass.h" + +static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_set_rate(drvdata->mi2s_osr_clk, freq); + if (ret) + dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n", + __func__, freq, ret); + + return ret; +} + +static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = clk_prepare_enable(drvdata->mi2s_osr_clk); + if (ret) { + dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n", + __func__, ret); + return ret; + } + + ret = clk_prepare_enable(drvdata->mi2s_bit_clk); + if (ret) { + dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n", + __func__, ret); + clk_disable_unprepare(drvdata->mi2s_osr_clk); + return ret; + } + + return 0; +} + +static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(drvdata->mi2s_bit_clk); + clk_disable_unprepare(drvdata->mi2s_osr_clk); +} + +static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + snd_pcm_format_t format = params_format(params); + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + unsigned int regval; + int bitwidth, ret; + + bitwidth = snd_pcm_format_width(format); + if (bitwidth < 0) { + dev_err(dai->dev, "%s() invalid bit width given: %d\n", + __func__, bitwidth); + return bitwidth; + } + + regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | + LPAIF_I2SCTL_WSSRC_INTERNAL; + + switch (bitwidth) { + case 16: + regval |= LPAIF_I2SCTL_BITWIDTH_16; + break; + case 24: + regval |= LPAIF_I2SCTL_BITWIDTH_24; + break; + case 32: + regval |= LPAIF_I2SCTL_BITWIDTH_32; + break; + default: + dev_err(dai->dev, "%s() invalid bitwidth given: %d\n", + __func__, bitwidth); + return -EINVAL; + } + + switch (channels) { + case 1: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_MONO; + break; + case 2: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 4: + regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 6: + regval |= LPAIF_I2SCTL_SPKMODE_6CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 8: + regval |= LPAIF_I2SCTL_SPKMODE_8CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + default: + dev_err(dai->dev, "%s() invalid channels given: %u\n", + __func__, channels); + return -EINVAL; + } + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval); + if (ret) { + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + return ret; + } + + ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2); + if (ret) { + dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", + __func__, rate * bitwidth * 2, ret); + return ret; + } + + return 0; +} + +static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); + if (ret) + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + + return ret; +} + +static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), + LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); + if (ret) + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + + return ret; +} + +static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), + LPAIF_I2SCTL_SPKEN_MASK, + LPAIF_I2SCTL_SPKEN_ENABLE); + if (ret) + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), + LPAIF_I2SCTL_SPKEN_MASK, + LPAIF_I2SCTL_SPKEN_DISABLE); + if (ret) + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + break; + } + + return ret; +} + +static struct snd_soc_dai_ops lpass_cpu_dai_ops = { + .set_sysclk = lpass_cpu_daiops_set_sysclk, + .startup = lpass_cpu_daiops_startup, + .shutdown = lpass_cpu_daiops_shutdown, + .hw_params = lpass_cpu_daiops_hw_params, + .hw_free = lpass_cpu_daiops_hw_free, + .prepare = lpass_cpu_daiops_prepare, + .trigger = lpass_cpu_daiops_trigger, +}; + +static int lpass_cpu_dai_probe(struct snd_soc_dai *dai) +{ + struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); + int ret; + + /* ensure audio hardware is disabled */ + ret = regmap_write(drvdata->lpaif_map, + LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); + if (ret) + dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", + __func__, ret); + + return ret; +} + +static struct snd_soc_dai_driver lpass_cpu_dai_driver = { + .playback = { + .stream_name = "lpass-cpu-playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .probe = &lpass_cpu_dai_probe, + .ops = &lpass_cpu_dai_ops, +}; + +static const struct snd_soc_component_driver lpass_cpu_comp_driver = { + .name = "lpass-cpu", +}; + +static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) + if (reg == LPAIF_I2SCTL_REG(i)) + return true; + + for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { + if (reg == LPAIF_IRQEN_REG(i)) + return true; + if (reg == LPAIF_IRQCLEAR_REG(i)) + return true; + } + + for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { + if (reg == LPAIF_RDMACTL_REG(i)) + return true; + if (reg == LPAIF_RDMABASE_REG(i)) + return true; + if (reg == LPAIF_RDMABUFF_REG(i)) + return true; + if (reg == LPAIF_RDMAPER_REG(i)) + return true; + } + + return false; +} + +static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) + if (reg == LPAIF_I2SCTL_REG(i)) + return true; + + for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { + if (reg == LPAIF_IRQEN_REG(i)) + return true; + if (reg == LPAIF_IRQSTAT_REG(i)) + return true; + } + + for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { + if (reg == LPAIF_RDMACTL_REG(i)) + return true; + if (reg == LPAIF_RDMABASE_REG(i)) + return true; + if (reg == LPAIF_RDMABUFF_REG(i)) + return true; + if (reg == LPAIF_RDMACURR_REG(i)) + return true; + if (reg == LPAIF_RDMAPER_REG(i)) + return true; + } + + return false; +} + +static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) + if (reg == LPAIF_IRQSTAT_REG(i)) + return true; + + for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) + if (reg == LPAIF_RDMACURR_REG(i)) + return true; + + return false; +} + +static const struct regmap_config lpass_cpu_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX), + .writeable_reg = lpass_cpu_regmap_writeable, + .readable_reg = lpass_cpu_regmap_readable, + .volatile_reg = lpass_cpu_regmap_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static int lpass_cpu_parse_of(struct device *dev) +{ + struct device_node *dsp_of_node; + + dsp_of_node = of_get_child_by_name(dev->of_node, "qcom,adsp"); + if (!dsp_of_node) { + dev_err(dev, "%s() error getting qcom,adsp sub-node\n", + __func__); + return -EINVAL; + } + + if (of_device_is_available(dsp_of_node)) { + dev_err(dev, "%s() DSP exists and holds audio resources\n", + __func__); + return -EBUSY; + } + + return 0; +} + +static int lpass_cpu_platform_probe(struct platform_device *pdev) +{ + struct lpass_data *drvdata; + struct resource *res; + int ret; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + platform_set_drvdata(pdev, drvdata); + + ret = lpass_cpu_parse_of(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "%s() error getting DT node info: %d\n", + __func__, ret); + return ret; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); + if (!res) { + dev_err(&pdev->dev, "%s() error getting resource\n", __func__); + return -ENODEV; + } + + drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR((void const __force *)drvdata->lpaif)) { + dev_err(&pdev->dev, "%s() error mapping reg resource: %ld\n", + __func__, + PTR_ERR((void const __force *)drvdata->lpaif)); + return PTR_ERR((void const __force *)drvdata->lpaif); + } + + drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, + &lpass_cpu_regmap_config); + if (IS_ERR(drvdata->lpaif_map)) { + dev_err(&pdev->dev, "%s() error initializing regmap: %ld\n", + __func__, PTR_ERR(drvdata->lpaif_map)); + return PTR_ERR(drvdata->lpaif_map); + } + + drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk"); + if (IS_ERR(drvdata->mi2s_osr_clk)) { + dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n", + __func__, PTR_ERR(drvdata->mi2s_osr_clk)); + return PTR_ERR(drvdata->mi2s_osr_clk); + } + + drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk"); + if (IS_ERR(drvdata->mi2s_bit_clk)) { + dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n", + __func__, PTR_ERR(drvdata->mi2s_bit_clk)); + return PTR_ERR(drvdata->mi2s_bit_clk); + } + + drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk"); + if (IS_ERR(drvdata->ahbix_clk)) { + dev_err(&pdev->dev, "%s() error getting ahbix-clk: %ld\n", + __func__, PTR_ERR(drvdata->ahbix_clk)); + return PTR_ERR(drvdata->ahbix_clk); + } + + ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY); + if (ret) { + dev_err(&pdev->dev, "%s() error setting rate on ahbix_clk: %d\n", + __func__, ret); + return ret; + } + dev_dbg(&pdev->dev, "%s() set ahbix_clk rate to %lu\n", __func__, + clk_get_rate(drvdata->ahbix_clk)); + + ret = clk_prepare_enable(drvdata->ahbix_clk); + if (ret) { + dev_err(&pdev->dev, "%s() error enabling ahbix_clk: %d\n", + __func__, ret); + return ret; + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1); + if (ret) { + dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n", + __func__, ret); + goto err_clk; + } + + ret = asoc_qcom_lpass_platform_register(pdev); + if (ret) { + dev_err(&pdev->dev, "%s() error registering platform driver: %d\n", + __func__, ret); + goto err_clk; + } + + return 0; + +err_clk: + clk_disable_unprepare(drvdata->ahbix_clk); + return ret; +} + +static int lpass_cpu_platform_remove(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + clk_disable_unprepare(drvdata->ahbix_clk); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id lpass_cpu_device_id[] = { + { .compatible = "qcom,lpass-cpu" }, + {} +}; +MODULE_DEVICE_TABLE(of, lpass_cpu_device_id); +#endif + +static struct platform_driver lpass_cpu_platform_driver = { + .driver = { + .name = "lpass-cpu", + .of_match_table = of_match_ptr(lpass_cpu_device_id), + }, + .probe = lpass_cpu_platform_probe, + .remove = lpass_cpu_platform_remove, +}; +module_platform_driver(lpass_cpu_platform_driver); + +MODULE_DESCRIPTION("QTi LPASS CPU Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From c5c8635a04711c7a7aca82f90e6b1e6df1c057be Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:55 -0800 Subject: [PATCH 0219/1910] ASoC: qcom: Add LPASS platform driver Add platform driver for the Qualcomm Technologies low-power audio subsystem (LPASS) ports. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 526 ++++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) create mode 100644 sound/soc/qcom/lpass-platform.c diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c new file mode 100644 index 000000000000..2fa6280dfb23 --- /dev/null +++ b/sound/soc/qcom/lpass-platform.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-lpaif-ipq806x.h" +#include "lpass.h" + +#define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024) +#define LPASS_PLATFORM_PERIODS 2 + +static struct snd_pcm_hardware lpass_platform_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = LPASS_PLATFORM_BUFFER_SIZE, + .period_bytes_max = LPASS_PLATFORM_BUFFER_SIZE / + LPASS_PLATFORM_PERIODS, + .period_bytes_min = LPASS_PLATFORM_BUFFER_SIZE / + LPASS_PLATFORM_PERIODS, + .periods_min = LPASS_PLATFORM_PERIODS, + .periods_max = LPASS_PLATFORM_PERIODS, + .fifo_size = 0, +}; + +static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + int ret; + + snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); + + runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(soc_runtime->dev, "%s() setting constraints failed: %d\n", + __func__, ret); + return -EINVAL; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; +} + +static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + snd_pcm_format_t format = params_format(params); + unsigned int channels = params_channels(params); + unsigned int regval; + int bitwidth; + int ret; + + bitwidth = snd_pcm_format_width(format); + if (bitwidth < 0) { + dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n", + __func__, bitwidth); + return bitwidth; + } + + regval = LPAIF_RDMACTL_BURSTEN_INCR4 | + LPAIF_RDMACTL_AUDINTF_MI2S | + LPAIF_RDMACTL_FIFOWM_8; + + switch (bitwidth) { + case 16: + switch (channels) { + case 1: + case 2: + regval |= LPAIF_RDMACTL_WPSCNT_ONE; + break; + case 4: + regval |= LPAIF_RDMACTL_WPSCNT_TWO; + break; + case 6: + regval |= LPAIF_RDMACTL_WPSCNT_THREE; + break; + case 8: + regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + break; + default: + dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", + __func__, bitwidth, channels); + return -EINVAL; + } + break; + case 24: + case 32: + switch (channels) { + case 1: + regval |= LPAIF_RDMACTL_WPSCNT_ONE; + break; + case 2: + regval |= LPAIF_RDMACTL_WPSCNT_TWO; + break; + case 4: + regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + break; + case 6: + regval |= LPAIF_RDMACTL_WPSCNT_SIX; + break; + case 8: + regval |= LPAIF_RDMACTL_WPSCNT_EIGHT; + break; + default: + dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", + __func__, bitwidth, channels); + return -EINVAL; + } + break; + default: + dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", + __func__, bitwidth, channels); + return -EINVAL; + } + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + int ret; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0); + if (ret) + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + + return ret; +} + +static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + int ret; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), + runtime->dma_addr); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S), + (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S), + (snd_pcm_lib_period_bytes(substream) >> 2) - 1); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), + LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* clear status before enabling interrupts */ + ret = regmap_write(drvdata->lpaif_map, + LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), + LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S)); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), + LPAIF_RDMACTL_ENABLE_MASK, + LPAIF_RDMACTL_ENABLE_ON); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), + LPAIF_RDMACTL_ENABLE_MASK, + LPAIF_RDMACTL_ENABLE_OFF); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_update_bits(drvdata->lpaif_map, + LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", + __func__, ret); + return ret; + } + break; + } + + return 0; +} + +static snd_pcm_uframes_t lpass_platform_pcmops_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + unsigned int base_addr, curr_addr; + int ret; + + ret = regmap_read(drvdata->lpaif_map, + LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr); + if (ret) { + dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", + __func__, ret); + return ret; + } + + ret = regmap_read(drvdata->lpaif_map, + LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr); + if (ret) { + dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", + __func__, ret); + return ret; + } + + return bytes_to_frames(substream->runtime, curr_addr - base_addr); +} + +static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_coherent(substream->pcm->card->dev, vma, + runtime->dma_area, runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops lpass_platform_pcm_ops = { + .open = lpass_platform_pcmops_open, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = lpass_platform_pcmops_hw_params, + .hw_free = lpass_platform_pcmops_hw_free, + .prepare = lpass_platform_pcmops_prepare, + .trigger = lpass_platform_pcmops_trigger, + .pointer = lpass_platform_pcmops_pointer, + .mmap = lpass_platform_pcmops_mmap, +}; + +static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) +{ + struct snd_pcm_substream *substream = data; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + unsigned int interrupts; + irqreturn_t ret = IRQ_NONE; + int rv; + + rv = regmap_read(drvdata->lpaif_map, + LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts); + if (rv) { + dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n", + __func__, rv); + return IRQ_NONE; + } + interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S); + + if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) { + rv = regmap_write(drvdata->lpaif_map, + LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)); + if (rv) { + dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", + __func__, rv); + return IRQ_NONE; + } + snd_pcm_period_elapsed(substream); + ret = IRQ_HANDLED; + } + + if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) { + rv = regmap_write(drvdata->lpaif_map, + LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)); + if (rv) { + dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", + __func__, rv); + return IRQ_NONE; + } + dev_warn(soc_runtime->dev, "%s() xrun warning\n", __func__); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + ret = IRQ_HANDLED; + } + + if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) { + rv = regmap_write(drvdata->lpaif_map, + LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST), + LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)); + if (rv) { + dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n", + __func__, rv); + return IRQ_NONE; + } + dev_err(soc_runtime->dev, "%s() bus access error\n", __func__); + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + ret = IRQ_HANDLED; + } + + return ret; +} + +static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, + struct snd_soc_pcm_runtime *soc_runtime) +{ + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = soc_runtime->dev; + buf->private_data = NULL; + buf->area = dma_alloc_coherent(soc_runtime->dev, size, &buf->addr, + GFP_KERNEL); + if (!buf->area) { + dev_err(soc_runtime->dev, "%s: Could not allocate DMA buffer\n", + __func__); + return -ENOMEM; + } + buf->bytes = size; + + return 0; +} + +static void lpass_platform_free_buffer(struct snd_pcm_substream *substream, + struct snd_soc_pcm_runtime *soc_runtime) +{ + struct snd_dma_buffer *buf = &substream->dma_buffer; + + if (buf->area) { + dma_free_coherent(soc_runtime->dev, buf->bytes, buf->area, + buf->addr); + } + buf->area = NULL; +} + +static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) +{ + struct snd_pcm *pcm = soc_runtime->pcm; + struct snd_pcm_substream *substream = + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct lpass_data *drvdata = + snd_soc_platform_get_drvdata(soc_runtime->platform); + int ret; + + soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32); + soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask; + + ret = lpass_platform_alloc_buffer(substream, soc_runtime); + if (ret) + return ret; + + ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq, + lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING, + "lpass-irq-lpaif", substream); + if (ret) { + dev_err(soc_runtime->dev, "%s() irq request failed: %d\n", + __func__, ret); + goto err_buf; + } + + /* ensure audio hardware is disabled */ + ret = regmap_write(drvdata->lpaif_map, + LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n", + __func__, ret); + return ret; + } + ret = regmap_write(drvdata->lpaif_map, + LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0); + if (ret) { + dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + __func__, ret); + return ret; + } + + return 0; + +err_buf: + lpass_platform_free_buffer(substream, soc_runtime); + return ret; +} + +static void lpass_platform_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream = + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + + lpass_platform_free_buffer(substream, soc_runtime); +} + +static struct snd_soc_platform_driver lpass_platform_driver = { + .pcm_new = lpass_platform_pcm_new, + .pcm_free = lpass_platform_pcm_free, + .ops = &lpass_platform_pcm_ops, +}; + +int asoc_qcom_lpass_platform_register(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); + if (drvdata->lpaif_irq < 0) { + dev_err(&pdev->dev, "%s() error getting irq handle: %d\n", + __func__, drvdata->lpaif_irq); + return -ENODEV; + } + + return devm_snd_soc_register_platform(&pdev->dev, + &lpass_platform_driver); +} +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register); + +MODULE_DESCRIPTION("QTi LPASS Platform Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 8dd72c42d38e62b82d7e3c47173b502d851c48ad Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:51 -0800 Subject: [PATCH 0220/1910] ASoC: qcom: Document LPASS CPU bindings Add documentation to the sound directory of the device-tree bindings for the QTi LPASS CPU DAI device. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- .../bindings/sound/qcom,lpass-cpu.txt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt new file mode 100644 index 000000000000..e7c6e9321863 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt @@ -0,0 +1,49 @@ +* Qualcomm Technologies LPASS CPU DAI + +This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS). + +Required properties: + +- compatible : "qcom,lpass-cpu" +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : A list which must include the following entries: + * "ahbix-clk" + * "mi2s-osr-clk" + * "mi2s-bit-clk" +- interrupts : Must contain an entry for each entry in + interrupt-names. +- interrupt-names : A list which must include the following entries: + * "lpass-irq-lpaif" +- pinctrl-N : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. +- pinctrl-names : Must contain a "default" entry. +- reg : Must contain an address for each entry in reg-names. +- reg-names : A list which must include the following entries: + * "lpass-lpaif" + +Required subnodes: + +- qcom,adsp : Audio DSP sub-node + +Optional Audio DSP subnode properties: + +- status : "disabled" indicates the adsp is not available. + +Example: + +lpass@28100000 { + compatible = "qcom,lpass-cpu"; + clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>; + clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk"; + interrupts = <0 85 1>; + interrupt-names = "lpass-irq-lpaif"; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&mi2s_default>; + pinctrl-1 = <&mi2s_idle>; + reg = <0x28100000 0x10000>; + reg-names = "lpass-lpaif"; + qcom,adsp { + status = "disabled"; + }; +}; -- GitLab From 2d800897e868ba561733ecffb30d840cbe5c86d4 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Tue, 3 Mar 2015 16:21:50 -0800 Subject: [PATCH 0221/1910] MAINTAINERS: Add QCOM audio ASoC maintainer Add maintainers for the Qualcomm Technologies sound drivers. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddc5a8cf9a8a..9514b794b74d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5254,6 +5254,13 @@ F: drivers/char/ipmi/ F: include/linux/ipmi* F: include/uapi/linux/ipmi* +QCOM AUDIO (ASoC) DRIVERS +M: Patrick Lai +M: Banajit Goswami +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Supported +F: sound/soc/qcom/ + IPS SCSI RAID DRIVER M: Adaptec OEM Raid Solutions L: linux-scsi@vger.kernel.org -- GitLab From 6da2517ddb03cb12c6e8bbe449b5ed1b51878642 Mon Sep 17 00:00:00 2001 From: "jmlatten@linux.vnet.ibm.com" Date: Fri, 20 Feb 2015 18:11:24 -0600 Subject: [PATCH 0222/1910] tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send Problem: When IMA and VTPM are both enabled in kernel config, kernel hangs during bootup on LE OS. Why?: IMA calls tpm_pcr_read() which results in tpm_ibmvtpm_send and tpm_ibmtpm_recv getting called. A trace showed that tpm_ibmtpm_recv was hanging. Resolution: tpm_ibmtpm_recv was hanging because tpm_ibmvtpm_send was sending CRQ message that probably did not make much sense to phype because of Endianness. The fix below sends correctly converted CRQ for LE. This was not caught before because it seems IMA is not enabled by default in kernel config and IMA exercises this particular code path in vtpm. Tested with IMA and VTPM enabled in kernel config and VTPM enabled on both a BE OS and a LE OS ppc64 lpar. This exercised CRQ and TPM command code paths in vtpm. Patch is against Peter's tpmdd tree on github which included Vicky's previous vtpm le patches. Signed-off-by: Joy Latten Cc: # eb71f8a5e33f: "Added Little Endian support to vtpm module" Cc: Reviewed-by: Ashley Lai Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_ibmvtpm.c | 10 +++++----- drivers/char/tpm/tpm_ibmvtpm.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index b1e53e3aece5..42ffa5e7a1e0 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -124,7 +124,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm; struct ibmvtpm_crq crq; - u64 *word = (u64 *) &crq; + __be64 *word = (__be64 *)&crq; int rc; ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); @@ -145,11 +145,11 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_TPM_COMMAND; - crq.len = (u16)count; - crq.data = ibmvtpm->rtce_dma_handle; + crq.len = cpu_to_be16(count); + crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); - rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]), - cpu_to_be64(word[1])); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), + be64_to_cpu(word[1])); if (rc != H_SUCCESS) { dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); rc = 0; diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index f595f14426bf..6af92890518f 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h @@ -22,9 +22,9 @@ struct ibmvtpm_crq { u8 valid; u8 msg; - u16 len; - u32 data; - u64 reserved; + __be16 len; + __be32 data; + __be64 reserved; } __attribute__((packed, aligned(8))); struct ibmvtpm_crq_queue { -- GitLab From d972b0523fa99358b2a0bafd85fe913b5d4b150a Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Sun, 1 Mar 2015 23:55:47 +0200 Subject: [PATCH 0223/1910] tpm: fix call order in tpm-chip.c - tpm_dev_add_device(): cdev_add() must be done before uevent is propagated in order to avoid races. - tpm_chip_register(): tpm_dev_add_device() must be done as the last step before exposing device to the user space in order to avoid races. In addition clarified description in tpm_chip_register(). Fixes: 313d21eeab92 ("tpm: device class for tpm") Fixes: afb5abc262e9 ("tpm: two-phase chip management functions") Signed-off-by: Jarkko Sakkinen Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-chip.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 1d278ccd751f..e096e9cddb40 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -140,24 +140,24 @@ static int tpm_dev_add_device(struct tpm_chip *chip) { int rc; - rc = device_add(&chip->dev); + rc = cdev_add(&chip->cdev, chip->dev.devt, 1); if (rc) { dev_err(&chip->dev, - "unable to device_register() %s, major %d, minor %d, err=%d\n", + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", chip->devname, MAJOR(chip->dev.devt), MINOR(chip->dev.devt), rc); + device_unregister(&chip->dev); return rc; } - rc = cdev_add(&chip->cdev, chip->dev.devt, 1); + rc = device_add(&chip->dev); if (rc) { dev_err(&chip->dev, - "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + "unable to device_register() %s, major %d, minor %d, err=%d\n", chip->devname, MAJOR(chip->dev.devt), MINOR(chip->dev.devt), rc); - device_unregister(&chip->dev); return rc; } @@ -174,27 +174,17 @@ static void tpm_dev_del_device(struct tpm_chip *chip) * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. * - * Creates a character device for the TPM chip and adds sysfs interfaces for - * the device, PPI and TCPA. As the last step this function adds the - * chip to the list of TPM chips available for use. + * Creates a character device for the TPM chip and adds sysfs attributes for + * the device. As the last step this function adds the chip to the list of TPM + * chips available for in-kernel use. * - * NOTE: This function should be only called after the chip initialization - * is complete. - * - * Called from tpm_.c probe function only for devices - * the driver has determined it should claim. Prior to calling - * this function the specific probe function has called pci_enable_device - * upon errant exit from this function specific probe function should call - * pci_disable_device + * This function should be only called after the chip initialization is + * complete. */ int tpm_chip_register(struct tpm_chip *chip) { int rc; - rc = tpm_dev_add_device(chip); - if (rc) - return rc; - /* Populate sysfs for TPM1 devices. */ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { rc = tpm_sysfs_add_device(chip); @@ -208,6 +198,10 @@ int tpm_chip_register(struct tpm_chip *chip) chip->bios_dir = tpm_bios_log_setup(chip->devname); } + rc = tpm_dev_add_device(chip); + if (rc) + return rc; + /* Make the chip available. */ spin_lock(&driver_lock); list_add_rcu(&chip->list, &tpm_chip_list); -- GitLab From 66e618857ca46433741bf97ceca1b425387400b1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Mar 2015 09:07:32 +0200 Subject: [PATCH 0224/1910] ASoC: davinci-mcasp: Fix compilation error Introduced by commit: 6afda7f50754 ASoC: davinci-mcasp: Allow complete shutdown of McASP when not in use I'm really sorry for this... Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 33cea0728cd2..d40b392b3da2 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1058,7 +1058,7 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) u32 reg; int i; - context->pm_state = pm_runtime_enabled(mcasp->dev) + context->pm_state = pm_runtime_enabled(mcasp->dev); if (!context->pm_state) pm_runtime_get_sync(mcasp->dev); -- GitLab From f641ddddc3ad139a91b9a1f9cea84ea657f75a6b Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 3 Mar 2015 08:21:33 -0500 Subject: [PATCH 0225/1910] crypto: talitos - Simplify per-channel initialization There were multiple loops in a row, for each separate step of the initialization of the channels. Simplify to a single loop. Signed-off-by: Martin Hicks Acked-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index ebbae8d3ce0d..20ae97a919df 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2706,20 +2706,16 @@ static int talitos_probe(struct platform_device *ofdev) goto err_out; } + priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); + for (i = 0; i < priv->num_channels; i++) { priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1); if (!priv->irq[1] || !(i & 1)) priv->chan[i].reg += TALITOS_CH_BASE_OFFSET; - } - for (i = 0; i < priv->num_channels; i++) { spin_lock_init(&priv->chan[i].head_lock); spin_lock_init(&priv->chan[i].tail_lock); - } - priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); - - for (i = 0; i < priv->num_channels; i++) { priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) * priv->fifo_len, GFP_KERNEL); if (!priv->chan[i].fifo) { @@ -2727,11 +2723,10 @@ static int talitos_probe(struct platform_device *ofdev) err = -ENOMEM; goto err_out; } - } - for (i = 0; i < priv->num_channels; i++) atomic_set(&priv->chan[i].submit_count, -(priv->chfifo_len - 1)); + } dma_set_mask(dev, DMA_BIT_MASK(36)); -- GitLab From b3988618e0463cf9af30ac1b42b2601993be7c70 Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Tue, 3 Mar 2015 08:21:34 -0500 Subject: [PATCH 0226/1910] crypto: talitos - Remove MD5_BLOCK_SIZE This is properly defined in the md5 header file. Signed-off-by: Martin Hicks Acked-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 20ae97a919df..857414afa29a 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -637,8 +637,6 @@ static void talitos_unregister_rng(struct device *dev) #define TALITOS_MAX_KEY_SIZE 96 #define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ -#define MD5_BLOCK_SIZE 64 - struct talitos_ctx { struct device *dev; int ch; @@ -2195,7 +2193,7 @@ static struct talitos_alg_template driver_algs[] = { .halg.base = { .cra_name = "md5", .cra_driver_name = "md5-talitos", - .cra_blocksize = MD5_BLOCK_SIZE, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, } @@ -2285,7 +2283,7 @@ static struct talitos_alg_template driver_algs[] = { .halg.base = { .cra_name = "hmac(md5)", .cra_driver_name = "hmac-md5-talitos", - .cra_blocksize = MD5_BLOCK_SIZE, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, } -- GitLab From 8e2e2769042f08eb49f630b5db87fce03696a415 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Mar 2015 10:19:30 +0100 Subject: [PATCH 0227/1910] crypto: ux500 - Update error message for dmaengine_prep_slave_sg() API Commit 7e933d3b1e25b250 ("crypto: ux500: use dmaengine_prep_slave_sg API") changed the code to use the new API, but forgot to update an error message. Signed-off-by: Geert Uytterhoeven Signed-off-by: Herbert Xu --- drivers/crypto/ux500/hash/hash_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index 187a8fd7eee7..5f5f360628fc 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -184,7 +184,7 @@ static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg, direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT); if (!desc) { dev_err(ctx->device->dev, - "%s: device_prep_slave_sg() failed!\n", __func__); + "%s: dmaengine_prep_slave_sg() failed!\n", __func__); return -EFAULT; } -- GitLab From 259d317f8d584503c5e3c43bbb96d80149390939 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 4 Mar 2015 12:42:13 -0800 Subject: [PATCH 0228/1910] hwrng: iproc-rng200 - Add device tree bindings Documents the IPROC random number generator device tree bindings used in some Broadcom chipsets. Reviewed-by: Ray Jui Signed-off-by: Scott Branden Signed-off-by: Herbert Xu --- .../devicetree/bindings/hwrng/brcm,iproc-rng200.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt diff --git a/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt b/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt new file mode 100644 index 000000000000..e25a456664b9 --- /dev/null +++ b/Documentation/devicetree/bindings/hwrng/brcm,iproc-rng200.txt @@ -0,0 +1,12 @@ +HWRNG support for the iproc-rng200 driver + +Required properties: +- compatible : "brcm,iproc-rng200" +- reg : base address and size of control register block + +Example: + +rng { + compatible = "brcm,iproc-rng200"; + reg = <0x18032000 0x28>; +}; -- GitLab From c83d45d5685f63e02f4b038e20450a28232d4da2 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 4 Mar 2015 12:42:14 -0800 Subject: [PATCH 0229/1910] hwrng: iproc-rng200 - Add Broadcom IPROC RNG driver This adds a driver for random number generator present on Broadcom IPROC devices. Reviewed-by: Ray Jui Signed-off-by: Scott Branden Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 13 ++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/iproc-rng200.c | 254 ++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 drivers/char/hw_random/iproc-rng200.c diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index de57b38809c7..f48cf11c655e 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -101,6 +101,19 @@ config HW_RANDOM_BCM2835 If unsure, say Y. +config HW_RANDOM_IPROC_RNG200 + tristate "Broadcom iProc RNG200 support" + depends on ARCH_BCM_IPROC + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the RNG200 + hardware found on the Broadcom iProc SoCs. + + To compile this driver as a module, choose M here: the + module will be called iproc-rng200 + + If unsure, say Y. + config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" depends on X86_32 && PCI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 0b4cd57f4e24..055bb01510ad 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c new file mode 100644 index 000000000000..276cb8a93bac --- /dev/null +++ b/drivers/char/hw_random/iproc-rng200.c @@ -0,0 +1,254 @@ +/* +* Copyright (C) 2015 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +/* + * DESCRIPTION: The Broadcom iProc RNG200 Driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define RNG_CTRL_OFFSET 0x00 +#define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF +#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 +#define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000 + +#define RNG_SOFT_RESET_OFFSET 0x04 +#define RNG_SOFT_RESET 0x00000001 + +#define RBG_SOFT_RESET_OFFSET 0x08 +#define RBG_SOFT_RESET 0x00000001 + +#define RNG_INT_STATUS_OFFSET 0x18 +#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000 +#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000 +#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020 +#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001 + +#define RNG_FIFO_DATA_OFFSET 0x20 + +#define RNG_FIFO_COUNT_OFFSET 0x24 +#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF + +struct iproc_rng200_dev { + void __iomem *base; +}; + +static void iproc_rng200_restart(void __iomem *rng_base) +{ + uint32_t val; + + /* Disable RBG */ + val = ioread32(rng_base + RNG_CTRL_OFFSET); + val &= ~RNG_CTRL_RNG_RBGEN_MASK; + val |= RNG_CTRL_RNG_RBGEN_DISABLE; + iowrite32(val, rng_base + RNG_CTRL_OFFSET); + + /* Clear all interrupt status */ + iowrite32(0xFFFFFFFFUL, rng_base + RNG_INT_STATUS_OFFSET); + + /* Reset RNG and RBG */ + val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET); + val |= RBG_SOFT_RESET; + iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET); + + val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET); + val |= RNG_SOFT_RESET; + iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET); + + val = ioread32(rng_base + RNG_SOFT_RESET_OFFSET); + val &= ~RNG_SOFT_RESET; + iowrite32(val, rng_base + RNG_SOFT_RESET_OFFSET); + + val = ioread32(rng_base + RBG_SOFT_RESET_OFFSET); + val &= ~RBG_SOFT_RESET; + iowrite32(val, rng_base + RBG_SOFT_RESET_OFFSET); + + /* Enable RBG */ + val = ioread32(rng_base + RNG_CTRL_OFFSET); + val &= ~RNG_CTRL_RNG_RBGEN_MASK; + val |= RNG_CTRL_RNG_RBGEN_ENABLE; + iowrite32(val, rng_base + RNG_CTRL_OFFSET); +} + +static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max, + bool wait) +{ + uint32_t status; + uint32_t num_remaining = max; + struct iproc_rng200_dev *priv = (struct iproc_rng200_dev *)rng->priv; + + #define MAX_RESETS_PER_READ 1 + uint32_t num_resets = 0; + + #define MAX_IDLE_TIME (1 * HZ) + unsigned long idle_endtime = jiffies + MAX_IDLE_TIME; + + while ((num_remaining > 0) && time_before(jiffies, idle_endtime)) { + + /* Is RNG sane? If not, reset it. */ + status = ioread32(priv->base + RNG_INT_STATUS_OFFSET); + if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK | + RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) { + + if (num_resets >= MAX_RESETS_PER_READ) + return max - num_remaining; + + iproc_rng200_restart(priv->base); + num_resets++; + } + + /* Are there any random numbers available? */ + if ((ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) & + RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) { + + if (num_remaining >= sizeof(uint32_t)) { + /* Buffer has room to store entire word */ + *(uint32_t *)buf = ioread32(priv->base + + RNG_FIFO_DATA_OFFSET); + buf += sizeof(uint32_t); + num_remaining -= sizeof(uint32_t); + } else { + /* Buffer can only store partial word */ + uint32_t rnd_number = ioread32(priv->base + + RNG_FIFO_DATA_OFFSET); + memcpy(buf, &rnd_number, num_remaining); + buf += num_remaining; + num_remaining = 0; + } + + /* Reset the IDLE timeout */ + idle_endtime = jiffies + MAX_IDLE_TIME; + } else { + if (!wait) + /* Cannot wait, return immediately */ + return max - num_remaining; + + /* Can wait, give others chance to run */ + usleep_range(min(num_remaining * 10, 500U), 500); + } + } + + return max - num_remaining; +} + +static int iproc_rng200_init(struct hwrng *rng) +{ + uint32_t val; + struct iproc_rng200_dev *priv; + + priv = (struct iproc_rng200_dev *)rng->priv; + + /* Setup RNG. */ + val = ioread32(priv->base + RNG_CTRL_OFFSET); + val &= ~RNG_CTRL_RNG_RBGEN_MASK; + val |= RNG_CTRL_RNG_RBGEN_ENABLE; + iowrite32(val, priv->base + RNG_CTRL_OFFSET); + + return 0; +} + +static void iproc_rng200_cleanup(struct hwrng *rng) +{ + uint32_t val; + struct iproc_rng200_dev *priv; + + priv = (struct iproc_rng200_dev *)rng->priv; + + /* Disable RNG hardware */ + val = ioread32(priv->base + RNG_CTRL_OFFSET); + val &= ~RNG_CTRL_RNG_RBGEN_MASK; + val |= RNG_CTRL_RNG_RBGEN_DISABLE; + iowrite32(val, priv->base + RNG_CTRL_OFFSET); +} + +static struct hwrng iproc_rng200_ops = { + .name = "iproc-rng200", + .read = iproc_rng200_read, + .init = iproc_rng200_init, + .cleanup = iproc_rng200_cleanup, +}; + +static int iproc_rng200_probe(struct platform_device *pdev) +{ + struct iproc_rng200_dev *priv; + struct resource *res; + struct device *dev = &pdev->dev; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct iproc_rng200_dev), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + iproc_rng200_ops.priv = (unsigned long)priv; + platform_set_drvdata(pdev, priv); + + /* Map peripheral */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get rng resources\n"); + return -EINVAL; + } + + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) { + dev_err(dev, "failed to remap rng regs\n"); + return PTR_ERR(priv->base); + } + + /* Register driver */ + ret = hwrng_register(&iproc_rng200_ops); + if (ret) { + dev_err(dev, "hwrng registration failed\n"); + return ret; + } + + dev_info(dev, "hwrng registered\n"); + + return 0; +} + +static int iproc_rng200_remove(struct platform_device *pdev) +{ + /* Unregister driver */ + hwrng_unregister(&iproc_rng200_ops); + + return 0; +} + +static const struct of_device_id iproc_rng200_of_match[] = { + { .compatible = "brcm,iproc-rng200", }, + {}, +}; +MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); + +static struct platform_driver iproc_rng200_driver = { + .driver = { + .name = "iproc-rng200", + .of_match_table = iproc_rng200_of_match, + }, + .probe = iproc_rng200_probe, + .remove = iproc_rng200_remove, +}; +module_platform_driver(iproc_rng200_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("iProc RNG200 Random Number Generator driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From d6482288aadcf19e348cbccff7a605790a3b3875 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Fri, 6 Mar 2015 16:59:00 +0100 Subject: [PATCH 0230/1910] ALSA: ac97: Add VT1613 AC97 codec support Patch to add an VT1613 AC97 codec support. This codec has additional DC offset removal control, headphone output and no video input. Signed-off-by: Maciej Szmigiero Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 1 + sound/pci/ac97/ac97_patch.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 5ee2f17c287c..5bca1a33fed6 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -177,6 +177,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)] { 0x54584e03, 0xffffffff, "TLV320AIC27", NULL, NULL }, { 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL }, +{ 0x56494120, 0xfffffff0, "VIA1613", patch_vt1613, NULL }, { 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF { 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF { 0x56494182, 0xffffffff, "VIA1618", patch_vt1618, NULL }, diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ceaac1c41906..eca22100f70d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3351,6 +3351,39 @@ static int patch_cm9780(struct snd_ac97 *ac97) return 0; } +/* + * VIA VT1613 codec + */ +static const struct snd_kcontrol_new snd_ac97_controls_vt1613[] = { +AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), +}; + +static int patch_vt1613_specific(struct snd_ac97 *ac97) +{ + int err; + + err = patch_build_controls(ac97, &snd_ac97_controls_vt1613[0], + ARRAY_SIZE(snd_ac97_controls_vt1613)); + if (err) + return err; + + return 0; +}; + +static const struct snd_ac97_build_ops patch_vt1613_ops = { + .build_specific = patch_vt1613_specific +}; + +static int patch_vt1613(struct snd_ac97 *ac97) +{ + ac97->build_ops = &patch_vt1613_ops; + + ac97->flags |= AC97_HAS_NO_VIDEO; + ac97->caps |= AC97_BC_HEADPHONE; + + return 0; +} + /* * VIA VT1616 codec */ -- GitLab From 5371fc0ecdf55b6811ade8a198de8ace2f4e5861 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 6 Mar 2015 13:41:42 -0300 Subject: [PATCH 0231/1910] ALSA: ac97: ac97_patch: Simplify patch_vt1613_specific() We can simplify the code by returning patch_build_controls() directly. Signed-off-by: Fabio Estevam Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index eca22100f70d..f4234edb878c 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3360,14 +3360,8 @@ AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), static int patch_vt1613_specific(struct snd_ac97 *ac97) { - int err; - - err = patch_build_controls(ac97, &snd_ac97_controls_vt1613[0], - ARRAY_SIZE(snd_ac97_controls_vt1613)); - if (err) - return err; - - return 0; + return patch_build_controls(ac97, &snd_ac97_controls_vt1613[0], + ARRAY_SIZE(snd_ac97_controls_vt1613)); }; static const struct snd_ac97_build_ops patch_vt1613_ops = { -- GitLab From 3d4cf65e2db58f927ca3cd13b0074b8fe5124659 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 25 Feb 2015 16:42:12 +0100 Subject: [PATCH 0232/1910] ASoC: omap: fix up SND_OMAP_SOC_OMAP_ABE_TWL6040 dependency The change to enable OMAP5 support on this platform was a little too eager in adding a 'select' for a particular clock driver that might not be enabled in all configurations, which in turn leads to a build error: warning: (SND_OMAP_SOC_OMAP_ABE_TWL6040) selects COMMON_CLK_PALMAS which has unmet direct dependencies (COMMON_CLK && MFD_PALMAS) drivers/built-in.o: In function `palmas_clks_probe': drivers/clk/clk-palmas.c:228: undefined reference to `palmas_ext_control_req_config' I do not see a strong dependency here, so it's probably better to drop this select and to avoid adding more complexity here. Fixes: 5163c1eede8e9 ("ASoC: omap: Kconfig: Support for omap5-uevm analog audio") Signed-off-by: Arnd Bergmann Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index e7c78b0406b5..6768e4f7d7d0 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -105,7 +105,7 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040 select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 select SND_SOC_DMIC - select COMMON_CLK_PALMAS if SOC_OMAP5 + select COMMON_CLK_PALMAS if MFD_PALMAS help Say Y if you want to add support for SoC audio on OMAP boards using ABE and twl6040 codec. This driver currently supports: -- GitLab From 5af76d5c0882435241841186b054262407e9eabb Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Fri, 27 Feb 2015 12:52:26 +0800 Subject: [PATCH 0233/1910] ASoC: rt286: correct the OR to AND Here it should be AND(&) to check the status. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 16723b167fbf..49c44a77b518 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -397,7 +397,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) if (jack) { /* enable IRQ */ - if (rt286->jack->status | SND_JACK_HEADPHONE) + if (rt286->jack->status & SND_JACK_HEADPHONE) snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1"); regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2); /* Send an initial empty report */ -- GitLab From 1a5ab21c2e0f3d6b25ee9f7ca3429fac57027f76 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Fri, 27 Feb 2015 12:54:29 +0800 Subject: [PATCH 0234/1910] ASoC: Intel: Add suspend_pre and resume_post for Broadwell snd_soc_card For broadwell machine, we need do some machine related setting before suspend and after resume, e.g. disable/enable jack detection, here adding snd_soc_card suspend_pre and resume_post for this task. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/broadwell.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index fba2ef5dac42..af5d73070f60 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -225,6 +225,32 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { }, }; +static int broadwell_suspend(struct snd_soc_card *card){ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-INT343A:00")) { + dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); + rt286_mic_detect(codec, NULL); + break; + } + } + return 0; +} + +static int broadwell_resume(struct snd_soc_card *card){ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-INT343A:00")) { + dev_dbg(codec->dev, "enabling jack detect for resume.\n"); + rt286_mic_detect(codec, &broadwell_headset); + break; + } + } + return 0; +} + /* broadwell audio machine driver for WPT + RT286S */ static struct snd_soc_card broadwell_rt286 = { .name = "broadwell-rt286", @@ -238,6 +264,8 @@ static struct snd_soc_card broadwell_rt286 = { .dapm_routes = broadwell_rt286_map, .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), .fully_routed = true, + .suspend_pre = broadwell_suspend, + .resume_post = broadwell_resume, }; static int broadwell_audio_probe(struct platform_device *pdev) -- GitLab From 0aed11244360c24c854a263eac0293acef2abd03 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 24 Feb 2015 00:54:16 +0000 Subject: [PATCH 0235/1910] dmaengine: export symbol of of_dma_request_slave_channel() Current DMAEngine implementation of DT bindings can't support DT subnode. This patch export symbols of of_dma_request_slave_channel() for subnode DMA DT bingings. ex) rcar_sound: rcar_sound@ec500000 { ... rcar_sound,dvc { dvc0: dvc@0 { dmas = <&audma0 0xbc>; dma-names = "tx"; }; dvc1: dvc@1 { dmas = <&audma0 0xbe>; dma-names = "tx"; }; }; ... }; Signed-off-by: Kuninori Morimoto Acked-by: Vinod Koul Signed-off-by: Mark Brown --- drivers/dma/of-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index ca31f1b45366..cbd4a8aff120 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -194,6 +194,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, return ERR_PTR(ret_no_channel); } +EXPORT_SYMBOL_GPL(of_dma_request_slave_channel); /** * of_dma_simple_xlate - Simple DMA engine translation function -- GitLab From c303cf0895ad927f5e9b8a5f8ed1c6b8c96a500f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:22:37 +0000 Subject: [PATCH 0236/1910] ASoC: rsnd: remove SH-DMA-BASE specific implementation Renesas R-Car sound had SH-DMA-BASE specific implementation before, but, now, it is no longer needed. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 - sound/soc/sh/rcar/rsnd.h | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1b53605f7154..0b14d3762cff 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -94,7 +94,6 @@ * */ #include -#include #include "rsnd.h" #define RSND_RATES SNDRV_PCM_RATE_8000_96000 diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e7914bd610e2..5ffde9b8955d 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -171,7 +171,6 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod); * R-Car DMA */ struct rsnd_dma { - struct sh_dmae_slave slave; struct dma_chan *chan; enum dma_transfer_direction dir; dma_addr_t addr; -- GitLab From 4715219ecef50cf79d7784545bf5bb4664bb800d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:23:08 +0000 Subject: [PATCH 0237/1910] ASoC: rsnd: remove un-needed parameter from rsnd_dma_init() It can get DMA direction via rsnd_dai_stream. Remove un-needed is_play from rsnd_dma_init(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++++-- sound/soc/sh/rcar/rsnd.h | 16 +--------------- sound/soc/sh/rcar/src.c | 1 - sound/soc/sh/rcar/ssi.c | 1 - 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0b14d3762cff..1edf4dc41c70 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -311,13 +311,15 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } } -int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, - int is_play, int id) +int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) { struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg; + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); char dma_name[DMA_NAME_SIZE]; dma_cap_mask_t mask; int ret; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5ffde9b8955d..93a1a256f37c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -179,8 +179,7 @@ struct rsnd_dma { void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dma *dma); int rsnd_dma_available(struct rsnd_dma *dma); -int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, - int is_play, int id); +int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); void rsnd_dma_quit(struct rsnd_priv *priv, struct rsnd_dma *dma); @@ -413,19 +412,6 @@ struct rsnd_priv { #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) -#define rsnd_info_is_playback(priv, type) \ -({ \ - struct rcar_snd_info *info = rsnd_priv_to_info(priv); \ - int i, is_play = 0; \ - for (i = 0; i < info->dai_info_nr; i++) { \ - if (info->dai_info[i].playback.type == (type)->info) { \ - is_play = 1; \ - break; \ - } \ - } \ - is_play; \ -}) - /* * rsnd_kctrl */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 81c182b4bad5..7fb879871a8e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -713,7 +713,6 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, ret = rsnd_dma_init(priv, rsnd_mod_to_dma(mod), - rsnd_info_is_playback(priv, src), src->info->dma_id); if (ret) goto rsnd_src_probe_gen2_fail; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 9e7b627c08e2..57e737c7046b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -478,7 +478,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, ret = rsnd_dma_init( priv, rsnd_mod_to_dma(mod), - rsnd_info_is_playback(priv, ssi), dma_id); if (ret) goto rsnd_ssi_dma_probe_fail; -- GitLab From 9c706ab29f33b9562f570d1e99e21955d898dc85 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:23:39 +0000 Subject: [PATCH 0238/1910] ASoC: rsnd: remove unused rsnd_dma_available() rsnd_dma_available() is not used. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 5 ----- sound/soc/sh/rcar/rsnd.h | 1 - sound/soc/sh/rcar/src.c | 2 -- sound/soc/sh/rcar/ssi.c | 2 -- 4 files changed, 10 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1edf4dc41c70..1da94bf730d2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -222,11 +222,6 @@ void rsnd_dma_start(struct rsnd_dma *dma) dma_async_issue_pending(dma->chan); } -int rsnd_dma_available(struct rsnd_dma *dma) -{ - return !!dma->chan; -} - #define DMA_NAME_SIZE 16 #define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 93a1a256f37c..cb12861a1f3c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -178,7 +178,6 @@ struct rsnd_dma { void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dma *dma); -int rsnd_dma_available(struct rsnd_dma *dma); int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); void rsnd_dma_quit(struct rsnd_priv *priv, struct rsnd_dma *dma); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 7fb879871a8e..f12c8b3aa475 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -30,8 +30,6 @@ struct rsnd_src { #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) -#define rsnd_src_dma_available(src) \ - rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod)) #define for_each_rsnd_src(pos, priv, i) \ for ((i) = 0; \ diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 57e737c7046b..fcc77ea369b9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -80,8 +80,6 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_dma_available(ssi) \ - rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) -- GitLab From 8a2ff4262ca611c38b31fec0af65be656d934f52 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:24:06 +0000 Subject: [PATCH 0239/1910] ASoC: rsnd: remove un-needed parameter from rsnd_dma_quit() priv is not used on rsnd_dma_quit() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 5 ++--- sound/soc/sh/rcar/rsnd.h | 3 +-- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1da94bf730d2..7db686d0cbd8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -358,7 +358,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) return 0; rsnd_dma_init_err: - rsnd_dma_quit(priv, dma); + rsnd_dma_quit(dma); rsnd_dma_channel_err: /* @@ -370,8 +370,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) return -EAGAIN; } -void rsnd_dma_quit(struct rsnd_priv *priv, - struct rsnd_dma *dma) +void rsnd_dma_quit(struct rsnd_dma *dma) { if (dma->chan) dma_release_channel(dma->chan); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index cb12861a1f3c..6ee97e7f9948 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -179,8 +179,7 @@ struct rsnd_dma { void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dma *dma); int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); -void rsnd_dma_quit(struct rsnd_priv *priv, - struct rsnd_dma *dma); +void rsnd_dma_quit(struct rsnd_dma *dma); /* diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index f12c8b3aa475..e2792056ce24 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -730,7 +730,7 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, static int rsnd_src_remove_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv) { - rsnd_dma_quit(priv, rsnd_mod_to_dma(mod)); + rsnd_dma_quit(rsnd_mod_to_dma(mod)); return 0; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index fcc77ea369b9..a0d902ad5985 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -499,7 +499,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); int irq = ssi->info->irq; - rsnd_dma_quit(priv, rsnd_mod_to_dma(mod)); + rsnd_dma_quit(rsnd_mod_to_dma(mod)); /* PIO will request IRQ again */ devm_free_irq(dev, irq, ssi); -- GitLab From 4ce3b17bd43b4f0136b1d0c7782d06fe9d3addfb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:24:27 +0000 Subject: [PATCH 0240/1910] ASoC: rsnd: tidyup rsnd_dma_to_mod() macro declaration position Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6ee97e7f9948..ec77c9f1a57c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -182,6 +182,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); void rsnd_dma_quit(struct rsnd_dma *dma); +#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) + /* * R-Car sound mod */ @@ -253,7 +255,6 @@ struct rsnd_mod { #define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod))) #define rsnd_mod_to_dma(mod) (&(mod)->dma) -#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) #define rsnd_mod_to_io(mod) ((mod)->io) #define rsnd_mod_id(mod) ((mod)->id) #define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk) -- GitLab From 7277911c87ba85436600f5b7aab15de112416795 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:24:52 +0000 Subject: [PATCH 0241/1910] ASoC: rsnd: enable to get resource by name rsnd driver needs to support Audio DMAC peri peri inside sound driver. getting resource by name is useful for it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index de0685f2abae..d08bcd3dbfbf 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -118,11 +118,12 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, mask, data); } -#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ - _rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf)) +#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ + _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, int id_size, int reg_id, + const char *name, struct rsnd_regmap_field_conf *conf, int conf_size) { @@ -142,7 +143,9 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, regc.val_bits = 32; regc.reg_stride = 4; - res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id); if (!res) return -ENODEV; @@ -368,10 +371,10 @@ static int rsnd_gen2_probe(struct platform_device *pdev, int ret_adg; int ret_ssi; - ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, conf_ssiu); - ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, conf_scu); - ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, conf_ssi); + ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu); + ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu); + ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg); + ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi); if (ret_ssiu < 0 || ret_scu < 0 || ret_adg < 0 || @@ -440,9 +443,9 @@ static int rsnd_gen1_probe(struct platform_device *pdev, int ret_adg; int ret_ssi; - ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, conf_sru); - ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, conf_ssi); + ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru); + ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); + ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); if (ret_sru < 0 || ret_adg < 0 || ret_ssi < 0) -- GitLab From c5212b4556b6bd120b0f4e4ae7c4a1cb9f5efe07 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:25:27 +0000 Subject: [PATCH 0242/1910] ASoC: rsnd: add rsnd_gen_get_phy_addr() to get physical address physical address is required from Audio DMAC peri peri. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 16 +++++++++++----- sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index d08bcd3dbfbf..0da04ed3aabe 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -28,6 +28,7 @@ struct rsnd_gen { struct regmap *regmap[RSND_BASE_MAX]; struct regmap_field *regs[RSND_REG_MAX]; + phys_addr_t res[RSND_REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) @@ -118,6 +119,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, mask, data); } +phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + return gen->res[reg_id]; +} + #define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, @@ -159,6 +167,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, gen->base[reg_id] = base; gen->regmap[reg_id] = regmap; + gen->res[reg_id] = res->start; for (i = 0; i < conf_size; i++) { @@ -216,13 +225,10 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, struct rsnd_mod *mod, int is_play, int is_from) { - struct platform_device *pdev = rsnd_priv_to_pdev(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - dma_addr_t ssi_reg = platform_get_resource(pdev, - IORESOURCE_MEM, RSND_GEN2_SSI)->start; - dma_addr_t src_reg = platform_get_resource(pdev, - IORESOURCE_MEM, RSND_GEN2_SCU)->start; + phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); + phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); int use_src = !!rsnd_io_to_mod_src(io); int use_dvc = !!rsnd_io_to_mod_dvc(io); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ec77c9f1a57c..8a8a4d5d55ef 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -331,6 +331,7 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, struct rsnd_mod *mod, int is_play, int is_from); +phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) -- GitLab From bfe834be9525a82c8a40380c7df8ca3b149e9c93 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:25:55 +0000 Subject: [PATCH 0243/1910] ASoC: rsnd: add dma.c for Audio DMAC / Audio DMAC peri peri Renesas sound driver had been assumed that Audio DMAC / Audio DMAC peri peri are implemented by DMAEngine. But, result of DMA ML discussion, it was concluded that it is not a general purpose DMAC. And it should be moved from current DMAEngine to rsnd driver. So, Audio DMAC peri peri become non DMAEngine. OTOH, ALSA SoC has soc-generic-dmaengine-pcm implementation. but it seems difficult to use this generic implementation on rsnd driver at this point, since it needs to fallback to PIO mode if DMA can't use. and additionally it needs 2 DMAC (= Audio DMAC / Audio DMAC peri peri). These are not "generic" feature. Of course I will try to use this generic dmaengine in the future somehow, but just use current style at this point until it can formally use 2 DMACs. This patch adds new dma.c and moves current dma code to dma.c from core.c. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/core.c | 218 ---------------------------------- sound/soc/sh/rcar/dma.c | 231 +++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 219 deletions(-) create mode 100644 sound/soc/sh/rcar/dma.c diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 9ac536429800..7b204925b8c5 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,2 +1,2 @@ -snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7db686d0cbd8..9beea9ba338a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -160,224 +160,6 @@ void rsnd_mod_init(struct rsnd_mod *mod, mod->clk = clk; } -/* - * rsnd_dma functions - */ -void rsnd_dma_stop(struct rsnd_dma *dma) -{ - dmaengine_terminate_all(dma->chan); -} - -static void rsnd_dma_complete(void *data) -{ - struct rsnd_dma *dma = (struct rsnd_dma *)data; - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - - /* - * Renesas sound Gen1 needs 1 DMAC, - * Gen2 needs 2 DMAC. - * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. - * But, Audio-DMAC-peri-peri doesn't have interrupt, - * and this driver is assuming that here. - * - * If Audio-DMAC-peri-peri has interrpt, - * rsnd_dai_pointer_update() will be called twice, - * ant it will breaks io->byte_pos - */ - - rsnd_dai_pointer_update(io, io->byte_per_period); -} - -void rsnd_dma_start(struct rsnd_dma *dma) -{ - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - struct snd_pcm_substream *substream = io->substream; - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_async_tx_descriptor *desc; - - desc = dmaengine_prep_dma_cyclic(dma->chan, - (dma->addr) ? dma->addr : - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), - dma->dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return; - } - - desc->callback = rsnd_dma_complete; - desc->callback_param = dma; - - if (dmaengine_submit(desc) < 0) { - dev_err(dev, "dmaengine_submit() fail\n"); - return; - } - - dma_async_issue_pending(dma->chan); -} - -#define DMA_NAME_SIZE 16 -#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ -static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) -{ - if (mod) - return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", - rsnd_mod_dma_name(mod), rsnd_mod_id(mod)); - else - return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); - -} - -static void rsnd_dma_of_name(struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to, - char *dma_name) -{ - int index = 0; - - index = _rsnd_dma_of_name(dma_name + index, mod_from); - *(dma_name + index++) = '_'; - index = _rsnd_dma_of_name(dma_name + index, mod_to); -} - -static void rsnd_dma_of_path(struct rsnd_dma *dma, - int is_play, - struct rsnd_mod **mod_from, - struct rsnd_mod **mod_to) -{ - struct rsnd_mod *this = rsnd_dma_to_mod(dma); - struct rsnd_dai_stream *io = rsnd_mod_to_io(this); - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mod[MOD_MAX]; - int i, index; - - - for (i = 0; i < MOD_MAX; i++) - mod[i] = NULL; - - /* - * in play case... - * - * src -> dst - * - * mem -> SSI - * mem -> SRC -> SSI - * mem -> SRC -> DVC -> SSI - */ - mod[0] = NULL; /* for "mem" */ - index = 1; - for (i = 1; i < MOD_MAX; i++) { - if (!src) { - mod[i] = ssi; - } else if (!dvc) { - mod[i] = src; - src = NULL; - } else { - if ((!is_play) && (this == src)) - this = dvc; - - mod[i] = (is_play) ? src : dvc; - i++; - mod[i] = (is_play) ? dvc : src; - src = NULL; - dvc = NULL; - } - - if (mod[i] == this) - index = i; - - if (mod[i] == ssi) - break; - } - - if (is_play) { - *mod_from = mod[index - 1]; - *mod_to = mod[index]; - } else { - *mod_from = mod[index]; - *mod_to = mod[index - 1]; - } -} - -int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_slave_config cfg; - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - int is_play = rsnd_io_is_play(io); - char dma_name[DMA_NAME_SIZE]; - dma_cap_mask_t mask; - int ret; - - if (dma->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); - rsnd_dma_of_name(mod_from, mod_to, dma_name); - - cfg.slave_id = id; - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); - cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - - dev_dbg(dev, "dma : %s %pad -> %pad\n", - dma_name, &cfg.src_addr, &cfg.dst_addr); - - dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, - (void *)id, dev, - dma_name); - if (!dma->chan) { - dev_err(dev, "can't get dma channel\n"); - goto rsnd_dma_channel_err; - } - - ret = dmaengine_slave_config(dma->chan, &cfg); - if (ret < 0) - goto rsnd_dma_init_err; - - dma->addr = is_play ? cfg.src_addr : cfg.dst_addr; - dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - - return 0; - -rsnd_dma_init_err: - rsnd_dma_quit(dma); -rsnd_dma_channel_err: - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; -} - -void rsnd_dma_quit(struct rsnd_dma *dma) -{ - if (dma->chan) - dma_release_channel(dma->chan); - - dma->chan = NULL; -} - /* * settting function */ diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c new file mode 100644 index 000000000000..37acd409e88c --- /dev/null +++ b/sound/soc/sh/rcar/dma.c @@ -0,0 +1,231 @@ +/* + * Renesas R-Car Audio DMAC support + * + * Copyright (C) 2015 Renesas Electronics Corp. + * Copyright (c) 2015 Kuninori Morimoto + * + * This program is free software; you can 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 "rsnd.h" + +static void rsnd_dma_complete(void *data) +{ + struct rsnd_dma *dma = (struct rsnd_dma *)data; + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + + /* + * Renesas sound Gen1 needs 1 DMAC, + * Gen2 needs 2 DMAC. + * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. + * But, Audio-DMAC-peri-peri doesn't have interrupt, + * and this driver is assuming that here. + * + * If Audio-DMAC-peri-peri has interrpt, + * rsnd_dai_pointer_update() will be called twice, + * ant it will breaks io->byte_pos + */ + + rsnd_dai_pointer_update(io, io->byte_per_period); +} + +#define DMA_NAME_SIZE 16 +#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ +static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) +{ + if (mod) + return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", + rsnd_mod_dma_name(mod), rsnd_mod_id(mod)); + else + return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); + +} + +static void rsnd_dma_of_name(struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to, + char *dma_name) +{ + int index = 0; + + index = _rsnd_dma_of_name(dma_name + index, mod_from); + *(dma_name + index++) = '_'; + index = _rsnd_dma_of_name(dma_name + index, mod_to); +} + +void rsnd_dma_stop(struct rsnd_dma *dma) +{ + dmaengine_terminate_all(dma->chan); +} + +void rsnd_dma_start(struct rsnd_dma *dma) +{ + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct snd_pcm_substream *substream = io->substream; + struct device *dev = rsnd_priv_to_dev(priv); + struct dma_async_tx_descriptor *desc; + + desc = dmaengine_prep_dma_cyclic(dma->chan, + (dma->addr) ? dma->addr : + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + dma->dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + + if (!desc) { + dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); + return; + } + + desc->callback = rsnd_dma_complete; + desc->callback_param = dma; + + if (dmaengine_submit(desc) < 0) { + dev_err(dev, "dmaengine_submit() fail\n"); + return; + } + + dma_async_issue_pending(dma->chan); +} + +static void rsnd_dma_of_path(struct rsnd_dma *dma, + int is_play, + struct rsnd_mod **mod_from, + struct rsnd_mod **mod_to); + +int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct dma_slave_config cfg = {}; + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); + char dma_name[DMA_NAME_SIZE]; + dma_cap_mask_t mask; + int ret; + + if (dma->chan) { + dev_err(dev, "it already has dma channel\n"); + return -EIO; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); + rsnd_dma_of_name(mod_from, mod_to, dma_name); + + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); + cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + dev_dbg(dev, "dma : %s %pad -> %pad\n", + dma_name, &cfg.src_addr, &cfg.dst_addr); + + dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)id, dev, + dma_name); + if (!dma->chan) { + dev_err(dev, "can't get dma channel\n"); + goto rsnd_dma_channel_err; + } + + ret = dmaengine_slave_config(dma->chan, &cfg); + if (ret < 0) + goto rsnd_dma_init_err; + + dma->addr = is_play ? cfg.src_addr : cfg.dst_addr; + dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + + return 0; + +rsnd_dma_init_err: + rsnd_dma_quit(dma); +rsnd_dma_channel_err: + + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + return -EAGAIN; +} + +void rsnd_dma_quit(struct rsnd_dma *dma) +{ + if (dma->chan) + dma_release_channel(dma->chan); + + dma->chan = NULL; +} + +static void rsnd_dma_of_path(struct rsnd_dma *dma, + int is_play, + struct rsnd_mod **mod_from, + struct rsnd_mod **mod_to) +{ + struct rsnd_mod *this = rsnd_dma_to_mod(dma); + struct rsnd_dai_stream *io = rsnd_mod_to_io(this); + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mod[MOD_MAX]; + int i, index; + + + for (i = 0; i < MOD_MAX; i++) + mod[i] = NULL; + + /* + * in play case... + * + * src -> dst + * + * mem -> SSI + * mem -> SRC -> SSI + * mem -> SRC -> DVC -> SSI + */ + mod[0] = NULL; /* for "mem" */ + index = 1; + for (i = 1; i < MOD_MAX; i++) { + if (!src) { + mod[i] = ssi; + } else if (!dvc) { + mod[i] = src; + src = NULL; + } else { + if ((!is_play) && (this == src)) + this = dvc; + + mod[i] = (is_play) ? src : dvc; + i++; + mod[i] = (is_play) ? dvc : src; + src = NULL; + dvc = NULL; + } + + if (mod[i] == this) + index = i; + + if (mod[i] == ssi) + break; + } + + if (is_play) { + *mod_from = mod[index - 1]; + *mod_to = mod[index]; + } else { + *mod_from = mod[index]; + *mod_to = mod[index - 1]; + } +} + -- GitLab From 747c71b12ee8357e73a88eb25f569e2a20e80df3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:26:29 +0000 Subject: [PATCH 0244/1910] ASoC: rsnd: move rsnd_gen_dma_addr() from gen.c to dma.c Now, we have dma.c for Audio DMAC / Audio DMAC peri peri. rsnd_gen_dma_addr() should go there. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 120 ++++++++++++++++++++++++++++++++++++++- sound/soc/sh/rcar/gen.c | 110 ----------------------------------- sound/soc/sh/rcar/rsnd.h | 3 - 3 files changed, 117 insertions(+), 116 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 37acd409e88c..188b4634939c 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -32,7 +32,6 @@ static void rsnd_dma_complete(void *data) } #define DMA_NAME_SIZE 16 -#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) { if (mod) @@ -97,6 +96,10 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod **mod_from, struct rsnd_mod **mod_to); +static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from); + int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) { struct device *dev = rsnd_priv_to_dev(priv); @@ -122,8 +125,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) rsnd_dma_of_name(mod_from, mod_to, dma_name); cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); - cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); + cfg.src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); + cfg.dst_addr = rsnd_dma_addr(priv, mod_to, is_play, 0); cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -168,6 +171,117 @@ void rsnd_dma_quit(struct rsnd_dma *dma) dma->chan = NULL; } +/* + * DMA read/write register offset + * + * RSND_xxx_I_N for Audio DMAC input + * RSND_xxx_O_N for Audio DMAC output + * RSND_xxx_I_P for Audio DMAC peri peri input + * RSND_xxx_O_P for Audio DMAC peri peri output + * + * ex) R-Car H2 case + * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out + * SSI : 0xec541000 / 0xec241008 / 0xec24100c + * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 + * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 + * CMD : 0xec500000 / / 0xec008000 0xec308000 + */ +#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) +#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) + +#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) +#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) + +#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) + +#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) +#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) + +#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) +#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) + +#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) +#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) + +static dma_addr_t +rsnd_gen2_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); + phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); + int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); + int use_src = !!rsnd_io_to_mod_src(io); + int use_dvc = !!rsnd_io_to_mod_dvc(io); + int id = rsnd_mod_id(mod); + struct dma_addr { + dma_addr_t out_addr; + dma_addr_t in_addr; + } dma_addrs[3][2][3] = { + /* SRC */ + {{{ 0, 0 }, + /* Capture */ + { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, + { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, + /* Playback */ + {{ 0, 0, }, + { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, + { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } + }, + /* SSI */ + /* Capture */ + {{{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 } }, + /* Playback */ + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) } } + }, + /* SSIU */ + /* Capture */ + {{{ RDMA_SSIU_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 } }, + /* Playback */ + {{ 0, RDMA_SSIU_I_N(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) } } }, + }; + + /* it shouldn't happen */ + if (use_dvc && !use_src) + dev_err(dev, "DVC is selected without SRC\n"); + + /* use SSIU or SSI ? */ + if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) + is_ssi++; + + return (is_from) ? + dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr : + dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; +} + +static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from) +{ + /* + * gen1 uses default DMA addr + */ + if (rsnd_is_gen1(priv)) + return 0; + + if (!mod) + return 0; + + return rsnd_gen2_dma_addr(priv, mod, is_play, is_from); +} + +#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ static void rsnd_dma_of_path(struct rsnd_dma *dma, int is_play, struct rsnd_mod **mod_from, diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0da04ed3aabe..0273724a2668 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -187,116 +187,6 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, return 0; } -/* - * DMA read/write register offset - * - * RSND_xxx_I_N for Audio DMAC input - * RSND_xxx_O_N for Audio DMAC output - * RSND_xxx_I_P for Audio DMAC peri peri input - * RSND_xxx_O_P for Audio DMAC peri peri output - * - * ex) R-Car H2 case - * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out - * SSI : 0xec541000 / 0xec241008 / 0xec24100c - * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 - * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 - * CMD : 0xec500000 / / 0xec008000 0xec308000 - */ -#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) -#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) - -#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) -#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) - -#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) -#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) - -#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) -#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) - -#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) -#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) - -#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) -#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) - -static dma_addr_t -rsnd_gen2_dma_addr(struct rsnd_priv *priv, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); - phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); - int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); - int use_src = !!rsnd_io_to_mod_src(io); - int use_dvc = !!rsnd_io_to_mod_dvc(io); - int id = rsnd_mod_id(mod); - struct dma_addr { - dma_addr_t out_addr; - dma_addr_t in_addr; - } dma_addrs[3][2][3] = { - /* SRC */ - {{{ 0, 0 }, - /* Capture */ - { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, - { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, - /* Playback */ - {{ 0, 0, }, - { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, - { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } - }, - /* SSI */ - /* Capture */ - {{{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, - /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } - }, - /* SSIU */ - /* Capture */ - {{{ RDMA_SSIU_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), 0 } }, - /* Playback */ - {{ 0, RDMA_SSIU_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id) } } }, - }; - - /* it shouldn't happen */ - if (use_dvc && !use_src) - dev_err(dev, "DVC is selected without SRC\n"); - - /* use SSIU or SSI ? */ - if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) - is_ssi++; - - return (is_from) ? - dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr : - dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; -} - -dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - /* - * gen1 uses default DMA addr - */ - if (rsnd_is_gen1(priv)) - return 0; - - if (!mod) - return 0; - - return rsnd_gen2_dma_addr(priv, mod, is_play, is_from); -} - /* * Gen2 */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 8a8a4d5d55ef..a73e94c1d785 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -328,9 +328,6 @@ int rsnd_gen_probe(struct platform_device *pdev, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); -dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, - struct rsnd_mod *mod, - int is_play, int is_from); phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) -- GitLab From 3c68565b6cb68b731b51eb21b59dce901002fc6e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:27:12 +0000 Subject: [PATCH 0245/1910] ASoC: rsnd: enable to care 1st / 2nd DMAC on rsnd_dma_xxx() rsnd driver needs to care about Audio DAMC (via DMAEngine), Audio DMAC peri peri (via local method) on rsnd driver. This patch adds new rsnd_dma_ops and care it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 78 +++++++++++++++++++++++++++------------- sound/soc/sh/rcar/rsnd.h | 12 +++++++ 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 188b4634939c..c911c079fdd0 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -10,7 +10,7 @@ */ #include "rsnd.h" -static void rsnd_dma_complete(void *data) +static void rsnd_dmaen_complete(void *data) { struct rsnd_dma *dma = (struct rsnd_dma *)data; struct rsnd_mod *mod = rsnd_dma_to_mod(dma); @@ -32,7 +32,7 @@ static void rsnd_dma_complete(void *data) } #define DMA_NAME_SIZE 16 -static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) +static int _rsnd_dmaen_of_name(char *dma_name, struct rsnd_mod *mod) { if (mod) return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", @@ -42,23 +42,23 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) } -static void rsnd_dma_of_name(struct rsnd_mod *mod_from, +static void rsnd_dmaen_of_name(struct rsnd_mod *mod_from, struct rsnd_mod *mod_to, char *dma_name) { int index = 0; - index = _rsnd_dma_of_name(dma_name + index, mod_from); + index = _rsnd_dmaen_of_name(dma_name + index, mod_from); *(dma_name + index++) = '_'; - index = _rsnd_dma_of_name(dma_name + index, mod_to); + index = _rsnd_dmaen_of_name(dma_name + index, mod_to); } -void rsnd_dma_stop(struct rsnd_dma *dma) +static void rsnd_dmaen_stop(struct rsnd_dma *dma) { dmaengine_terminate_all(dma->chan); } -void rsnd_dma_start(struct rsnd_dma *dma) +static void rsnd_dmaen_start(struct rsnd_dma *dma) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); @@ -80,7 +80,7 @@ void rsnd_dma_start(struct rsnd_dma *dma) return; } - desc->callback = rsnd_dma_complete; + desc->callback = rsnd_dmaen_complete; desc->callback_param = dma; if (dmaengine_submit(desc) < 0) { @@ -91,22 +91,12 @@ void rsnd_dma_start(struct rsnd_dma *dma) dma_async_issue_pending(dma->chan); } -static void rsnd_dma_of_path(struct rsnd_dma *dma, - int is_play, - struct rsnd_mod **mod_from, - struct rsnd_mod **mod_to); - -static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv, - struct rsnd_mod *mod, - int is_play, int is_from); - -int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) +static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); int is_play = rsnd_io_is_play(io); char dma_name[DMA_NAME_SIZE]; @@ -121,12 +111,11 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); - rsnd_dma_of_name(mod_from, mod_to, dma_name); + rsnd_dmaen_of_name(mod_from, mod_to, dma_name); cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); - cfg.dst_addr = rsnd_dma_addr(priv, mod_to, is_play, 0); + cfg.src_addr = dma->src_addr; + cfg.dst_addr = dma->dst_addr; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -163,7 +152,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) return -EAGAIN; } -void rsnd_dma_quit(struct rsnd_dma *dma) +static void rsnd_dmaen_quit(struct rsnd_dma *dma) { if (dma->chan) dma_release_channel(dma->chan); @@ -171,6 +160,13 @@ void rsnd_dma_quit(struct rsnd_dma *dma) dma->chan = NULL; } +static struct rsnd_dma_ops rsnd_dmaen_ops = { + .start = rsnd_dmaen_start, + .stop = rsnd_dmaen_stop, + .init = rsnd_dmaen_init, + .quit = rsnd_dmaen_quit, +}; + /* * DMA read/write register offset * @@ -343,3 +339,35 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } } +void rsnd_dma_stop(struct rsnd_dma *dma) +{ + dma->ops->stop(dma); +} + +void rsnd_dma_start(struct rsnd_dma *dma) +{ + dma->ops->start(dma); +} + +void rsnd_dma_quit(struct rsnd_dma *dma) +{ + dma->ops->quit(dma); +} + +int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) +{ + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); + + rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); + + dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(priv, mod_to, is_play, 0); + + dma->ops = &rsnd_dmaen_ops; + + return dma->ops->init(priv, dma, id, mod_from, mod_to); +} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a73e94c1d785..c7299f74cf83 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,10 +170,22 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod); /* * R-Car DMA */ +struct rsnd_dma; +struct rsnd_dma_ops { + void (*start)(struct rsnd_dma *dma); + void (*stop)(struct rsnd_dma *dma); + int (*init)(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); + void (*quit)(struct rsnd_dma *dma); +}; + struct rsnd_dma { struct dma_chan *chan; + struct rsnd_dma_ops *ops; enum dma_transfer_direction dir; dma_addr_t addr; + dma_addr_t src_addr; + dma_addr_t dst_addr; }; void rsnd_dma_start(struct rsnd_dma *dma); -- GitLab From 288f392e729dd4d3719c2319c7c3f8d4c820488b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:27:42 +0000 Subject: [PATCH 0246/1910] ASoC: rsnd: add Audio DMAC peri peri support rework Renesas R-Car sound (= rsnd) needs 2 DMAC which are called as Audio DMAC (= 1st DMAC) and Audio DMAC peri peri (2nd DMAC). And rsnd had assumed that 1st / 2nd DMACs are implemented as DMAEngine. But, in result of DMA ML discussion, 2nd DMAC was concluded that it is not a general purpose DMAC (2nd DMAC is for Device to Device inside sound system). Additionally, current DMAEngine can't support Device to Device, and we don't have correct DT bindings for it at this point. So the easiest solution for it is that move it from DMAEngine to rsnd driver. Audio DMAC peri peri is controlled from sound driver without DMAEngine by this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 + sound/soc/sh/rcar/dma.c | 211 ++++++++++++++++++++++++++++++++++++++- sound/soc/sh/rcar/rsnd.h | 11 +- 3 files changed, 221 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9beea9ba338a..3b6e21948c71 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -974,6 +974,7 @@ static int rsnd_probe(struct platform_device *pdev) const struct rsnd_of_data *of_data, struct rsnd_priv *priv) = { rsnd_gen_probe, + rsnd_dma_probe, rsnd_ssi_probe, rsnd_src_probe, rsnd_dvc_probe, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index c911c079fdd0..a01bb8c6b068 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -8,8 +8,29 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include "rsnd.h" +/* + * Audio DMAC peri peri register + */ +#define PDMASAR 0x00 +#define PDMADAR 0x04 +#define PDMACHCR 0x0c + +/* PDMACHCR */ +#define PDMACHCR_DE (1 << 0) + +struct rsnd_dma_ctrl { + void __iomem *base; + int dmapp_num; +}; + +#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) + +/* + * Audio DMAC + */ static void rsnd_dmaen_complete(void *data) { struct rsnd_dma *dma = (struct rsnd_dma *)data; @@ -108,6 +129,8 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, return -EIO; } + dev_dbg(dev, "Audio DMAC init\n"); + dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -167,6 +190,150 @@ static struct rsnd_dma_ops rsnd_dmaen_ops = { .quit = rsnd_dmaen_quit, }; +/* + * Audio DMAC peri peri + */ +static const u8 gen2_id_table_ssiu[] = { + 0x00, /* SSI00 */ + 0x04, /* SSI10 */ + 0x08, /* SSI20 */ + 0x0c, /* SSI3 */ + 0x0d, /* SSI4 */ + 0x0e, /* SSI5 */ + 0x0f, /* SSI6 */ + 0x10, /* SSI7 */ + 0x11, /* SSI8 */ + 0x12, /* SSI90 */ +}; +static const u8 gen2_id_table_scu[] = { + 0x2d, /* SCU_SRCI0 */ + 0x2e, /* SCU_SRCI1 */ + 0x2f, /* SCU_SRCI2 */ + 0x30, /* SCU_SRCI3 */ + 0x31, /* SCU_SRCI4 */ + 0x32, /* SCU_SRCI5 */ + 0x33, /* SCU_SRCI6 */ + 0x34, /* SCU_SRCI7 */ + 0x35, /* SCU_SRCI8 */ + 0x36, /* SCU_SRCI9 */ +}; +static const u8 gen2_id_table_cmd[] = { + 0x37, /* SCU_CMD0 */ + 0x38, /* SCU_CMD1 */ +}; + +static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod) +{ + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + const u8 *entry = NULL; + int id = rsnd_mod_id(mod); + int size = 0; + + if (mod == ssi) { + entry = gen2_id_table_ssiu; + size = ARRAY_SIZE(gen2_id_table_ssiu); + } else if (mod == src) { + entry = gen2_id_table_scu; + size = ARRAY_SIZE(gen2_id_table_scu); + } else if (mod == dvc) { + entry = gen2_id_table_cmd; + size = ARRAY_SIZE(gen2_id_table_cmd); + } + + if (!entry) + return 0xFF; + + if (size <= id) + return 0xFF; + + return entry[id]; +} + +static u32 rsnd_dmapp_get_chcr(struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + return (rsnd_dmapp_get_id(mod_from) << 24) + + (rsnd_dmapp_get_id(mod_to) << 16); +} + +#define rsnd_dmapp_addr(dmac, dma, reg) \ + (dmac->base + 0x20 + (0x10 * dma->dmapp_id) + reg) +static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) +{ + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); + + iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); +} + +static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) +{ + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + + return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); +} + +static void rsnd_dmapp_stop(struct rsnd_dma *dma) +{ + int i; + + rsnd_dmapp_write(dma, 0, PDMACHCR); + + for (i = 0; i < 1024; i++) { + if (0 == rsnd_dmapp_read(dma, PDMACHCR)) + return; + udelay(1); + } +} + +static void rsnd_dmapp_start(struct rsnd_dma *dma) +{ + rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); + rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); + rsnd_dmapp_write(dma, dma->chcr, PDMACHCR); +} + +static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) +{ + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "Audio DMAC peri peri init\n"); + + dma->dmapp_id = dmac->dmapp_num; + dma->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE; + + dmac->dmapp_num++; + + rsnd_dmapp_stop(dma); + + dev_dbg(dev, "id/src/dst/chcr = %d/%x/%x/%08x\n", + dma->dmapp_id, dma->src_addr, dma->dst_addr, dma->chcr); + + return 0; +} + +static struct rsnd_dma_ops rsnd_dmapp_ops = { + .start = rsnd_dmapp_start, + .stop = rsnd_dmapp_stop, + .init = rsnd_dmapp_init, + .quit = rsnd_dmapp_stop, +}; + +/* + * Common DMAC Interface + */ + /* * DMA read/write register offset * @@ -367,7 +534,49 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(priv, mod_to, is_play, 0); - dma->ops = &rsnd_dmaen_ops; + /* for Gen2 */ + if (mod_from && mod_to) + dma->ops = &rsnd_dmapp_ops; + else + dma->ops = &rsnd_dmaen_ops; + + /* for Gen1, overwrite */ + if (rsnd_is_gen1(priv)) + dma->ops = &rsnd_dmaen_ops; return dma->ops->init(priv, dma, id, mod_from, mod_to); } + +int rsnd_dma_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dma_ctrl *dmac; + struct resource *res; + + /* + * for Gen1 + */ + if (rsnd_is_gen1(priv)) + return 0; + + /* + * for Gen2 + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); + dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); + if (!dmac || !res) { + dev_err(dev, "dma allocate failed\n"); + return -ENOMEM; + } + + dmac->dmapp_num = 0; + dmac->base = devm_ioremap_resource(dev, res); + if (IS_ERR(dmac->base)) + return PTR_ERR(dmac->base); + + priv->dma = dmac; + + return 0; +} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c7299f74cf83..9e67142c82bd 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -184,6 +184,8 @@ struct rsnd_dma { struct rsnd_dma_ops *ops; enum dma_transfer_direction dir; dma_addr_t addr; + int dmapp_id; + u32 chcr; dma_addr_t src_addr; dma_addr_t dst_addr; }; @@ -192,7 +194,9 @@ void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dma *dma); int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id); void rsnd_dma_quit(struct rsnd_dma *dma); - +int rsnd_dma_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) @@ -395,6 +399,11 @@ struct rsnd_priv { */ void *adg; + /* + * below value will be filled on rsnd_dma_probe() + */ + void *dma; + /* * below value will be filled on rsnd_ssi_probe() */ -- GitLab From 56f2906ae2d0b48b64a67feef99e3be3b40c3617 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:28:07 +0000 Subject: [PATCH 0247/1910] ASoC: rsnd: remove rsnd_dma::addr DMAEngine for Renesas R-Car driver is used only for Audio DMAC now. rsnd_dma::addr was added to support Audio DMAC peri peri, but it is no longer needed. Let's remove it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 2 -- sound/soc/sh/rcar/rsnd.h | 1 - 2 files changed, 3 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index a01bb8c6b068..c407fd250d2a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -89,7 +89,6 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) struct dma_async_tx_descriptor *desc; desc = dmaengine_prep_dma_cyclic(dma->chan, - (dma->addr) ? dma->addr : substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), @@ -157,7 +156,6 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, if (ret < 0) goto rsnd_dma_init_err; - dma->addr = is_play ? cfg.src_addr : cfg.dst_addr; dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; return 0; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9e67142c82bd..a2954917bfcb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -183,7 +183,6 @@ struct rsnd_dma { struct dma_chan *chan; struct rsnd_dma_ops *ops; enum dma_transfer_direction dir; - dma_addr_t addr; int dmapp_id; u32 chcr; dma_addr_t src_addr; -- GitLab From aaf4fce019ecd55a2d93b6111525deeef300f751 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:28:32 +0000 Subject: [PATCH 0248/1910] ASoC: rsnd: remove rsnd_dma::dir DMAEngine direction can be calculated from rsnd_dai_stream, So, rsnd_dma::dir does not make sense now. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 5 ++--- sound/soc/sh/rcar/rsnd.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index c407fd250d2a..3f1ea58ee144 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -87,12 +87,13 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; + int is_play = rsnd_io_is_play(io); desc = dmaengine_prep_dma_cyclic(dma->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), - dma->dir, + is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -156,8 +157,6 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, if (ret < 0) goto rsnd_dma_init_err; - dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - return 0; rsnd_dma_init_err: diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a2954917bfcb..5d65a4b96743 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -182,7 +182,6 @@ struct rsnd_dma_ops { struct rsnd_dma { struct dma_chan *chan; struct rsnd_dma_ops *ops; - enum dma_transfer_direction dir; int dmapp_id; u32 chcr; dma_addr_t src_addr; -- GitLab From 0d00a52182be985bfae67d407ee81fefe448a0fd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:29:13 +0000 Subject: [PATCH 0249/1910] ASoC: rsnd: use union with rsnd_dmaen / rsnd_dmapp Renesas R-Car needs 2 DMACs.1st DMAC is DMAEngine, and 2nd DMAC is implemented as local code. These 2 DMACs are never shared. We can use union for these. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 40 +++++++++++++++++++++++++--------------- sound/soc/sh/rcar/rsnd.h | 16 ++++++++++++++-- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 3f1ea58ee144..b449763ebd43 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -76,11 +76,14 @@ static void rsnd_dmaen_of_name(struct rsnd_mod *mod_from, static void rsnd_dmaen_stop(struct rsnd_dma *dma) { - dmaengine_terminate_all(dma->chan); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + dmaengine_terminate_all(dmaen->chan); } static void rsnd_dmaen_start(struct rsnd_dma *dma) { + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); @@ -89,7 +92,7 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) struct dma_async_tx_descriptor *desc; int is_play = rsnd_io_is_play(io); - desc = dmaengine_prep_dma_cyclic(dma->chan, + desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), @@ -109,12 +112,13 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) return; } - dma_async_issue_pending(dma->chan); + dma_async_issue_pending(dmaen->chan); } static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; struct rsnd_mod *mod = rsnd_dma_to_mod(dma); @@ -124,7 +128,7 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, dma_cap_mask_t mask; int ret; - if (dma->chan) { + if (dmaen->chan) { dev_err(dev, "it already has dma channel\n"); return -EIO; } @@ -145,15 +149,15 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, dev_dbg(dev, "dma : %s %pad -> %pad\n", dma_name, &cfg.src_addr, &cfg.dst_addr); - dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + dmaen->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, (void *)id, dev, dma_name); - if (!dma->chan) { + if (!dmaen->chan) { dev_err(dev, "can't get dma channel\n"); goto rsnd_dma_channel_err; } - ret = dmaengine_slave_config(dma->chan, &cfg); + ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) goto rsnd_dma_init_err; @@ -174,10 +178,12 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, static void rsnd_dmaen_quit(struct rsnd_dma *dma) { - if (dma->chan) - dma_release_channel(dma->chan); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + if (dmaen->chan) + dma_release_channel(dmaen->chan); - dma->chan = NULL; + dmaen->chan = NULL; } static struct rsnd_dma_ops rsnd_dmaen_ops = { @@ -257,7 +263,8 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_mod *mod_from, } #define rsnd_dmapp_addr(dmac, dma, reg) \ - (dmac->base + 0x20 + (0x10 * dma->dmapp_id) + reg) + (dmac->base + 0x20 + reg + \ + (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); @@ -294,28 +301,31 @@ static void rsnd_dmapp_stop(struct rsnd_dma *dma) static void rsnd_dmapp_start(struct rsnd_dma *dma) { + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); + rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); - rsnd_dmapp_write(dma, dma->chcr, PDMACHCR); + rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); } static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); dev_dbg(dev, "Audio DMAC peri peri init\n"); - dma->dmapp_id = dmac->dmapp_num; - dma->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE; + dmapp->dmapp_id = dmac->dmapp_num; + dmapp->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE; dmac->dmapp_num++; rsnd_dmapp_stop(dma); dev_dbg(dev, "id/src/dst/chcr = %d/%x/%x/%08x\n", - dma->dmapp_id, dma->src_addr, dma->dst_addr, dma->chcr); + dmapp->dmapp_id, dma->src_addr, dma->dst_addr, dmapp->chcr); return 0; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5d65a4b96743..0d36e38ebbcf 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -179,14 +179,26 @@ struct rsnd_dma_ops { void (*quit)(struct rsnd_dma *dma); }; -struct rsnd_dma { +struct rsnd_dmaen { struct dma_chan *chan; - struct rsnd_dma_ops *ops; +}; + +struct rsnd_dmapp { int dmapp_id; u32 chcr; +}; + +struct rsnd_dma { + struct rsnd_dma_ops *ops; dma_addr_t src_addr; dma_addr_t dst_addr; + union { + struct rsnd_dmaen en; + struct rsnd_dmapp pp; + } dma; }; +#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) +#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_stop(struct rsnd_dma *dma); -- GitLab From e879a9ddf41c47ccc83039e99e04b0d5c56cd0c5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:29:41 +0000 Subject: [PATCH 0250/1910] ASoC: rsnd: enable rsnd_ssi_use_busif() for DMA Renesas R-Car sound driver uses SSI, but the DMA interfaces are SSI/SSIU. This interface is based on SSI/SRC/DVC connection. And DMA function needs to know which interface is used somehow. This patch enables rsnd_ssi_use_busif() for DMA. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 2 +- sound/soc/sh/rcar/rsnd.h | 1 + sound/soc/sh/rcar/ssi.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index b449763ebd43..3f34461da1e0 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -427,7 +427,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, dev_err(dev, "DVC is selected without SRC\n"); /* use SSIU or SSI ? */ - if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) + if (is_ssi && rsnd_ssi_use_busif(mod)) is_ssi++; return (is_from) ? diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 0d36e38ebbcf..68bc3f46d70b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -514,6 +514,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); +int rsnd_ssi_use_busif(struct rsnd_mod *mod); /* * R-Car DVC diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index a0d902ad5985..7e48d562dea8 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -84,7 +84,7 @@ struct rsnd_ssi { #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) -static int rsnd_ssi_use_busif(struct rsnd_mod *mod) +int rsnd_ssi_use_busif(struct rsnd_mod *mod) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); -- GitLab From 04e627baa68a8dc42f19b68e1b46d1c6aecebfd9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:30:02 +0000 Subject: [PATCH 0251/1910] ASoC: rsnd: ssi: add rsnd_ssi_of_node() This patch adds rsnd_ssi_of_node() to get SSI subnode from DT. This is prepare for new DT bindings for 1st DMAC Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7e48d562dea8..2133eb34ed06 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -83,6 +83,8 @@ struct rsnd_ssi { #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) +#define rsnd_ssi_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") int rsnd_ssi_use_busif(struct rsnd_mod *mod) { @@ -633,7 +635,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, if (!of_data) return; - node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); + node = rsnd_ssi_of_node(priv); if (!node) return; -- GitLab From 82e76ed38edbdb338d64f5f2486fcd1482c8859a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:30:22 +0000 Subject: [PATCH 0252/1910] ASoC: rsnd: src: add rsnd_src_of_node() This patch adds rsnd_src_of_node() to get SRC subnode from DT. This is prepare for new DT bindings for 1st DMAC Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index e2792056ce24..5a601bed4154 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -28,6 +28,9 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) +#define rsnd_src_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") + #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) @@ -807,7 +810,7 @@ static void rsnd_of_parse_src(struct platform_device *pdev, if (!of_data) return; - src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); + src_node = rsnd_src_of_node(priv); if (!src_node) return; -- GitLab From 93b986e246248d0587acb4f073a621179a16b763 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:30:41 +0000 Subject: [PATCH 0253/1910] ASoC: rsnd: dvc: add rsnd_dvc_of_node() This patch adds rsnd_dvc_of_node() to get DVC subnode from DT. This is prepare for new DT bindings for 1st DMAC Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d7f9ed959c4e..e0990180e1ea 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -24,6 +24,9 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ }; +#define rsnd_dvc_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") + #define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod) -- GitLab From 72adc61f4637aa3596c1db1129f84d768475a885 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:31:23 +0000 Subject: [PATCH 0254/1910] ASoC: rsnd: 1st DMAC dma-names cares subnode Renesas R-Car sound (= rsnd) needs 2 DMAC which are called as Audio DMAC (= 1st DMAC) and Audio DMAC peri peri (2nd DMAC). And rsnd had assumed that 1st / 2nd DMACs are implemented as DMAEngine. But, in result of DMA ML discussion, 2nd DMAC was concluded that it is not a general purpose DMAC (2nd DMAC is for Device to Device inside sound system). Additionally, current DMAEngine can't support Device to Device, and we don't have correct DT bindings for it at this point. So the easiest solution for it is that move it from DMAEngine to rsnd driver. dma-names on DT was implemented as no difference between 1st / 2nd DMAC's, since rsnd had assumed that both DMACs are implemented as DMAEngine. That style was "src_dst". But now, 2nd DMAC was implemented as non DMAEngine, and it doesn't need dma-names anymore. So, this dma-names rule is no longer needed. And additionally, dma-names was assumed that it has all (= SSI/SSIU/SRC/DVC) nodes under sound node. In upstream code, no SoC/platform is supporting DMA for rsnd driver yet. This means there is no compatible issue if this patch changes dma-names's rule of DT. This patch assumes dma-names for 1st DMAC are tx/rx base, and listed in each SSI/SRC/DVC subnode ex) rcar_sound,dvc { dvc0: dvc@0 { dmas = <&audma0 0xbc>; dma-names = "tx"; }; ... rcar_sound,src { src0: src@0 { ... dmas = <&audma0 0x85>, <&audma1 0x9a>; dma-names = "rx", "tx"; }; ... rcar_sound,ssi { ssi0: ssi@0 { ... dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; dma-names = "rx", "tx", "rxu", "txu"; }; ... Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 11 ++--- sound/soc/sh/rcar/dma.c | 88 +++++++++++++++++++++++----------------- sound/soc/sh/rcar/dvc.c | 9 ++++ sound/soc/sh/rcar/rsnd.h | 6 ++- sound/soc/sh/rcar/src.c | 13 ++++++ sound/soc/sh/rcar/ssi.c | 17 ++++++-- 6 files changed, 95 insertions(+), 49 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3b6e21948c71..7b995f025e22 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -137,15 +137,12 @@ char *rsnd_mod_name(struct rsnd_mod *mod) return mod->ops->name; } -char *rsnd_mod_dma_name(struct rsnd_mod *mod) +struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod) { - if (!mod || !mod->ops) - return "unknown"; - - if (!mod->ops->dma_name) - return mod->ops->name; + if (!mod || !mod->ops || !mod->ops->dma_req) + return NULL; - return mod->ops->dma_name(mod); + return mod->ops->dma_req(mod); } void rsnd_mod_init(struct rsnd_mod *mod, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 3f34461da1e0..92fd55044ee6 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include +#include #include "rsnd.h" /* @@ -52,28 +53,6 @@ static void rsnd_dmaen_complete(void *data) rsnd_dai_pointer_update(io, io->byte_per_period); } -#define DMA_NAME_SIZE 16 -static int _rsnd_dmaen_of_name(char *dma_name, struct rsnd_mod *mod) -{ - if (mod) - return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", - rsnd_mod_dma_name(mod), rsnd_mod_id(mod)); - else - return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); - -} - -static void rsnd_dmaen_of_name(struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to, - char *dma_name) -{ - int index = 0; - - index = _rsnd_dmaen_of_name(dma_name + index, mod_from); - *(dma_name + index++) = '_'; - index = _rsnd_dmaen_of_name(dma_name + index, mod_to); -} - static void rsnd_dmaen_stop(struct rsnd_dma *dma) { struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); @@ -115,6 +94,40 @@ static void rsnd_dmaen_start(struct rsnd_dma *dma) dma_async_issue_pending(dmaen->chan); } +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, + struct rsnd_mod *mod, char *name) +{ + struct dma_chan *chan; + struct device_node *np; + int i = 0; + + for_each_child_of_node(of_node, np) { + if (i == rsnd_mod_id(mod)) + break; + i++; + } + + chan = of_dma_request_slave_channel(np, name); + + of_node_put(np); + of_node_put(of_node); + + return chan; +} + +static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + if ((!mod_from && !mod_to) || + (mod_from && mod_to)) + return NULL; + + if (mod_from) + return rsnd_mod_dma_req(mod_from); + else + return rsnd_mod_dma_req(mod_to); +} + static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { @@ -124,8 +137,6 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); int is_play = rsnd_io_is_play(io); - char dma_name[DMA_NAME_SIZE]; - dma_cap_mask_t mask; int ret; if (dmaen->chan) { @@ -135,10 +146,21 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, dev_dbg(dev, "Audio DMAC init\n"); - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + if (dev->of_node) { + dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to); + } else { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); - rsnd_dmaen_of_name(mod_from, mod_to, dma_name); + dmaen->chan = dma_request_channel(mask, shdma_chan_filter, + (void *)id); + } + if (IS_ERR_OR_NULL(dmaen->chan)) { + dev_err(dev, "can't get dma channel\n"); + goto rsnd_dma_channel_err; + } cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; cfg.src_addr = dma->src_addr; @@ -146,16 +168,8 @@ static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "dma : %s %pad -> %pad\n", - dma_name, &cfg.src_addr, &cfg.dst_addr); - - dmaen->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, - (void *)id, dev, - dma_name); - if (!dmaen->chan) { - dev_err(dev, "can't get dma channel\n"); - goto rsnd_dma_channel_err; - } + dev_dbg(dev, "dma : %pad -> %pad\n", + &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index e0990180e1ea..aeeef1352eee 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -272,8 +272,17 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, return 0; } +static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), + mod, "tx"); +} + static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, + .dma_req = rsnd_dvc_dma_req, .probe = rsnd_dvc_probe_gen2, .remove = rsnd_dvc_remove_gen2, .init = rsnd_dvc_init, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 68bc3f46d70b..52c401c9eeef 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -207,6 +207,8 @@ void rsnd_dma_quit(struct rsnd_dma *dma); int rsnd_dma_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv); +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, + struct rsnd_mod *mod, char *name); #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) @@ -222,7 +224,7 @@ enum rsnd_mod_type { struct rsnd_mod_ops { char *name; - char* (*dma_name)(struct rsnd_mod *mod); + struct dma_chan* (*dma_req)(struct rsnd_mod *mod); int (*probe)(struct rsnd_mod *mod, struct rsnd_priv *priv); int (*remove)(struct rsnd_mod *mod, @@ -292,7 +294,7 @@ void rsnd_mod_init(struct rsnd_mod *mod, enum rsnd_mod_type type, int id); char *rsnd_mod_name(struct rsnd_mod *mod); -char *rsnd_mod_dma_name(struct rsnd_mod *mod); +struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod); /* * R-Car sound DAI diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 5a601bed4154..6ce8985757c1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -114,6 +114,17 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ +static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); + + return rsnd_dma_request_channel(rsnd_src_of_node(priv), + mod, + is_play ? "rx" : "tx"); +} + int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif) { @@ -506,6 +517,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_src_gen1_ops = { .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen1, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, @@ -780,6 +792,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_src_gen2_ops = { .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen2, .remove = rsnd_src_remove_gen2, .init = rsnd_src_init_gen2, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2133eb34ed06..fea4aa53918a 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -553,14 +553,25 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, return 0; } -static char *rsnd_ssi_dma_name(struct rsnd_mod *mod) +static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod) { - return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME; + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int is_play = rsnd_io_is_play(io); + char *name; + + if (rsnd_ssi_use_busif(mod)) + name = is_play ? "rxu" : "txu"; + else + name = is_play ? "rx" : "tx"; + + return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), + mod, name); } static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .name = SSI_NAME, - .dma_name = rsnd_ssi_dma_name, + .dma_req = rsnd_ssi_dma_req, .probe = rsnd_ssi_dma_probe, .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, -- GitLab From 5cf4f68672856dcbca883b460aee4ee5bfbeafb0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:31:55 +0000 Subject: [PATCH 0255/1910] ASoC: rsnd: add sample code of rcar_sound,src irq cfcefe01265cbaf5ca7209226d043b07bfa8b587 (ASoC: rsnd: add recovery support for under/over flow error on SRC) added SRC recovery support which needs IRQ. This patch adds SRC irq sample code on DT bingdings text Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 2dd690bc19cc..87e0fc2ce399 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -53,16 +53,36 @@ rcar_sound: rcar_sound@ec500000 { }; rcar_sound,src { - src0: src@0 { }; - src1: src@1 { }; - src2: src@2 { }; - src3: src@3 { }; - src4: src@4 { }; - src5: src@5 { }; - src6: src@6 { }; - src7: src@7 { }; - src8: src@8 { }; - src9: src@9 { }; + src0: src@0 { + interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; + }; + src1: src@1 { + interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; + }; + src2: src@2 { + interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; + }; + src3: src@3 { + interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; + }; + src4: src@4 { + interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; + }; + src5: src@5 { + interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; + }; + src6: src@6 { + interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; + }; + src7: src@7 { + interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; + }; + src8: src@8 { + interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; + }; + src9: src@9 { + interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; + }; }; rcar_sound,ssi { -- GitLab From bb02714fe5f198c0f07a8039ebcc636c1bffbc03 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:32:15 +0000 Subject: [PATCH 0256/1910] ASoC: rsnd: add sample code of missing clocks Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 87e0fc2ce399..503967ba39db 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -47,6 +47,27 @@ rcar_sound: rcar_sound@ec500000 { <0 0xec540000 0 0x1000>, /* SSIU */ <0 0xec541000 0 0x1280>; /* SSI */ + clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>, + <&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>, + <&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>, + <&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>, + <&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>, + <&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>, + <&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>, + <&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>, + <&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>, + <&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>, + <&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>, + <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>; + clock-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5", + "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0", + "src.9", "src.8", "src.7", "src.6", "src.5", + "src.4", "src.3", "src.2", "src.1", "src.0", + "dvc.0", "dvc.1", + "clk_a", "clk_b", "clk_c", "clk_i"; + rcar_sound,dvc { dvc0: dvc@0 { }; dvc1: dvc@1 { }; -- GitLab From e80a2fb18bc7dca116ec623dc909f07c5e505349 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:32:49 +0000 Subject: [PATCH 0257/1910] ASoC: rsnd: add sample code of dma entry rsnd driver supports Audio DMAC (via DMAEngine) / Audio DMAC peri peri (via rsnd driver) now. This patch adds DT binding sample code on DT binging text Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 503967ba39db..6e660d4f3631 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -29,9 +29,17 @@ SSI subnode properties: - shared-pin : if shared clock pin - pio-transfer : use PIO transfer mode - no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case +- dma : Should contain Audio DMAC entry +- dma-names : SSI case "rx" (=playback), "tx" (=capture) + SSIU case "rxu" (=playback), "txu" (=capture) SRC subnode properties: -no properties at this point +- dma : Should contain Audio DMAC entry +- dma-names : "rx" (=playback), "tx" (=capture) + +DVC subnode properties: +- dma : Should contain Audio DMAC entry +- dma-names : "tx" (=playback/capture) DAI subnode properties: - playback : list of playback modules @@ -69,73 +77,119 @@ rcar_sound: rcar_sound@ec500000 { "clk_a", "clk_b", "clk_c", "clk_i"; rcar_sound,dvc { - dvc0: dvc@0 { }; - dvc1: dvc@1 { }; + dvc0: dvc@0 { + dmas = <&audma0 0xbc>; + dma-names = "tx"; + }; + dvc1: dvc@1 { + dmas = <&audma0 0xbe>; + dma-names = "tx"; + }; }; rcar_sound,src { src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x85>, <&audma1 0x9a>; + dma-names = "rx", "tx"; }; src1: src@1 { interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x87>, <&audma1 0x9c>; + dma-names = "rx", "tx"; }; src2: src@2 { interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x89>, <&audma1 0x9e>; + dma-names = "rx", "tx"; }; src3: src@3 { interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8b>, <&audma1 0xa0>; + dma-names = "rx", "tx"; }; src4: src@4 { interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8d>, <&audma1 0xb0>; + dma-names = "rx", "tx"; }; src5: src@5 { interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8f>, <&audma1 0xb2>; + dma-names = "rx", "tx"; }; src6: src@6 { interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x91>, <&audma1 0xb4>; + dma-names = "rx", "tx"; }; src7: src@7 { interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x93>, <&audma1 0xb6>; + dma-names = "rx", "tx"; }; src8: src@8 { interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x95>, <&audma1 0xb8>; + dma-names = "rx", "tx"; }; src9: src@9 { interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x97>, <&audma1 0xba>; + dma-names = "rx", "tx"; }; }; rcar_sound,ssi { ssi0: ssi@0 { interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi1: ssi@1 { interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi2: ssi@2 { interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi3: ssi@3 { interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi4: ssi@4 { interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi5: ssi@5 { interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi6: ssi@6 { interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi7: ssi@7 { interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi8: ssi@8 { interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>; + dma-names = "rx", "tx", "rxu", "txu"; }; ssi9: ssi@9 { interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>; + dma-names = "rx", "tx", "rxu", "txu"; }; }; -- GitLab From d3b1c0badbc86c034af55704ea88c1e656b402fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Feb 2015 10:33:09 +0000 Subject: [PATCH 0258/1910] ASoC: rsnd: add sample code of reg-names Current rsnd driver supports reg-names, and Audio DMAC peri peri. This patch adds sample code for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 6e660d4f3631..f316ce1f214a 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -53,7 +53,9 @@ rcar_sound: rcar_sound@ec500000 { reg = <0 0xec500000 0 0x1000>, /* SCU */ <0 0xec5a0000 0 0x100>, /* ADG */ <0 0xec540000 0 0x1000>, /* SSIU */ - <0 0xec541000 0 0x1280>; /* SSI */ + <0 0xec541000 0 0x1280>, /* SSI */ + <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/ + reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>, -- GitLab From 778952598e53f09251bebe1655177b355cd9e836 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 7 Mar 2015 19:35:08 +0100 Subject: [PATCH 0259/1910] ASoC: Remove unnecessary device_remove_file() Since commit d29697dc3b92 ("ASoC: Add sysfs entries via static attribute groups") the sysfs attributes of the rtd are manged by the device core and there is no need to manually call device_remove_file() anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 30579ca5bacb..acf99f1250e5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1410,7 +1410,6 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) /* unregister the rtd device */ if (rtd->dev_registered) { - device_remove_file(rtd->dev, &dev_attr_codec_reg); device_unregister(rtd->dev); rtd->dev_registered = 0; } -- GitLab From 060e234e959a1c42f40f355963064c3e24981c7f Mon Sep 17 00:00:00 2001 From: Yanjiang Jin Date: Fri, 6 Mar 2015 10:34:41 +0800 Subject: [PATCH 0260/1910] crypto: caam - fix uninitialized edesc->sec4_sg_bytes field sec4_sg_bytes not being properly initialized causes ahash_done to try to free unallocated DMA memory: caam_jr ffe301000.jr: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0xdeadbeefdeadbeef] [size=3735928559 bytes] ------------[ cut here ]------------ WARNING: at lib/dma-debug.c:1093 Modules linked in: CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.0.0-rc1+ #6 task: e9598c00 ti: effca000 task.ti: e95a2000 NIP: c04ef24c LR: c04ef24c CTR: c0549730 REGS: effcbd40 TRAP: 0700 Not tainted (4.0.0-rc1+) MSR: 00029002 CR: 22008084 XER: 20000000 GPR00: c04ef24c effcbdf0 e9598c00 00000096 c08f7424 c00ab2b0 00000000 00000001 GPR08: c0fe7510 effca000 00000000 000001c3 22008082 00000000 c1048e77 c1050000 GPR16: c0c36700 493c0040 0000002c e690e4a0 c1054fb4 c18bac40 00029002 c18b0788 GPR24: 00000014 e690e480 effcbe48 00000000 c0fde128 e6ffac10 deadbeef deadbeef NIP [c04ef24c] check_unmap+0x93c/0xb40 LR [c04ef24c] check_unmap+0x93c/0xb40 Call Trace: [effcbdf0] [c04ef24c] check_unmap+0x93c/0xb40 (unreliable) [effcbe40] [c04ef4f4] debug_dma_unmap_page+0xa4/0xc0 [effcbec0] [c070cda8] ahash_done+0x128/0x1a0 [effcbef0] [c0700070] caam_jr_dequeue+0x1d0/0x290 [effcbf40] [c0045f40] tasklet_action+0x110/0x1f0 [effcbf80] [c0044bc8] __do_softirq+0x188/0x700 [effcbfe0] [c00455d8] irq_exit+0x108/0x120 [effcbff0] [c000f520] call_do_irq+0x24/0x3c [e95a3e20] [c00059b8] do_IRQ+0xc8/0x170 [e95a3e50] [c0011bc8] ret_from_except+0x0/0x18 Signed-off-by: Yanjiang Jin Acked-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index f347ab7eea95..ba0532efd3ae 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1172,6 +1172,7 @@ static int ahash_final_no_ctx(struct ahash_request *req) return -ENOMEM; } + edesc->sec4_sg_bytes = 0; sh_len = desc_len(sh_desc); desc = edesc->hw_desc; init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER | HDR_REVERSE); -- GitLab From 4842234f83bfce83c93f84f5972a956ef2c87805 Mon Sep 17 00:00:00 2001 From: Yanjiang Jin Date: Fri, 6 Mar 2015 10:34:42 +0800 Subject: [PATCH 0261/1910] hwrng: caam - fix rng_unmap_ctx's DMA_UNMAP size problem Fix rng_unmap_ctx's DMA_UNMAP size problem for caam_rng, else system would report the below calltrace during cleanup caam_rng. Since rng_create_sh_desc() creates a fixed descriptor of exactly 4 command-lengths now, also update DESC_RNG_LEN to (4 * CAAM_CMD_SZ). caam_jr ffe301000.jr: DMA-API: device driver frees DMA memory with different size [device address=0x000000007f080010] [map size=16 bytes] [unmap size=40 bytes] ------------[ cut here ]------------ WARNING: at lib/dma-debug.c:887 Modules linked in: task: c0000000f7cdaa80 ti: c0000000e5340000 task.ti: c0000000e5340000 NIP: c0000000004f5bc8 LR: c0000000004f5bc4 CTR: c0000000005f69b0 REGS: c0000000e53433c0 TRAP: 0700 Not tainted MSR: 0000000080029000 CR: 24088482 XER: 00000000 SOFTE: 0 GPR00: c0000000004f5bc4 c0000000e5343640 c0000000012af360 000000000000009f GPR04: 0000000000000000 00000000000000a0 c000000000d02070 c000000015980660 GPR08: c000000000cff360 0000000000000000 0000000000000000 c0000000012da018 GPR12: 00000000000001e3 c000000001fff780 00000000100f0000 0000000000000001 GPR16: 0000000000000002 0000000000000000 0000000000000000 0000000000000000 GPR20: 0000000000000000 0000000000000000 ffffffffffffffff 0000000000000001 GPR24: 0000000000000001 0000000000000001 0000000000000000 0000000000000001 GPR28: c000000001556b90 c000000001565b80 c0000000e5343750 c0000000f9427480 NIP [c0000000004f5bc8] .check_unmap+0x538/0x9c0 LR [c0000000004f5bc4] .check_unmap+0x534/0x9c0 Call Trace: [c0000000e5343640] [c0000000004f5bc4] .check_unmap+0x534/0x9c0 (unreliable) [c0000000e53436e0] [c0000000004f60d4] .debug_dma_unmap_page+0x84/0xb0 [c0000000e5343810] [c00000000082f9d4] .caam_cleanup+0x1d4/0x240 [c0000000e53438a0] [c00000000056cc88] .hwrng_unregister+0xd8/0x1c0 Instruction dump: 7c641b78 41de0410 e8a90050 2fa50000 419e0484 e8de0028 e8ff0030 3c62ff90 e91e0030 38638388 48546ed9 60000000 <0fe00000> 3c62ff8f 38637fc8 48546ec5 ---[ end trace e43fd1734d6600df ]--- Signed-off-by: Yanjiang Jin Acked-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamrng.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index ae31e555793c..26a544b505f1 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -52,7 +52,7 @@ /* length of descriptors */ #define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ * 2) -#define DESC_RNG_LEN (10 * CAAM_CMD_SZ) +#define DESC_RNG_LEN (4 * CAAM_CMD_SZ) /* Buffer, its dma address and lock */ struct buf_data { @@ -90,8 +90,8 @@ static inline void rng_unmap_ctx(struct caam_rng_ctx *ctx) struct device *jrdev = ctx->jrdev; if (ctx->sh_desc_dma) - dma_unmap_single(jrdev, ctx->sh_desc_dma, DESC_RNG_LEN, - DMA_TO_DEVICE); + dma_unmap_single(jrdev, ctx->sh_desc_dma, + desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); rng_unmap_buf(jrdev, &ctx->bufs[0]); rng_unmap_buf(jrdev, &ctx->bufs[1]); } -- GitLab From cde001e4c3c3625c60b68a83eb1f1c2572dee07a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 6 Mar 2015 08:26:31 +0100 Subject: [PATCH 0262/1910] crypto: rng - RNGs must return 0 in success case Change the RNGs to always return 0 in success case. This patch ensures that seqiv.c works with RNGs other than krng. seqiv expects that any return code other than 0 is an error. Without the patch, rfc4106(gcm(aes)) will not work when using a DRBG or an ANSI X9.31 RNG. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/ansi_cprng.c | 6 +++++- crypto/drbg.c | 7 ++++++- include/crypto/rng.h | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 6f5bebc9bf01..765fe7609348 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -210,7 +210,11 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx, byte_count = DEFAULT_BLK_SZ; } - err = byte_count; + /* + * Return 0 in case of success as mandated by the kernel + * crypto API interface definition. + */ + err = 0; dbgprint(KERN_CRIT "getting %d random bytes for context %p\n", byte_count, ctx); diff --git a/crypto/drbg.c b/crypto/drbg.c index 56c1d7ec3d9e..b69409cb7e6a 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1280,7 +1280,7 @@ static void drbg_restore_shadow(struct drbg_state *drbg, * as defined in SP800-90A. The additional input is mixed into * the state in addition to the pulled entropy. * - * return: generated number of bytes + * return: 0 when all bytes are generated; < 0 in case of an error */ static int drbg_generate(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, @@ -1419,6 +1419,11 @@ static int drbg_generate(struct drbg_state *drbg, } #endif + /* + * All operations were successful, return 0 as mandated by + * the kernel crypto API interface. + */ + len = 0; err: shadow->d_ops->crypto_fini(shadow); drbg_restore_shadow(drbg, &shadow); diff --git a/include/crypto/rng.h b/include/crypto/rng.h index a16fb10142bf..6e28ea5be9f1 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -103,8 +103,7 @@ static inline void crypto_free_rng(struct crypto_rng *tfm) * This function fills the caller-allocated buffer with random numbers using the * random number generator referenced by the cipher handle. * - * Return: > 0 function was successful and returns the number of generated - * bytes; < 0 if an error occurred + * Return: 0 function was successful; < 0 if an error occurred */ static inline int crypto_rng_get_bytes(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen) -- GitLab From dbe5fe7e1b3b3632bef2c09964a5f5505de4d744 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 6 Mar 2015 21:34:22 +0100 Subject: [PATCH 0263/1910] crypto: doc - AEAD / RNG AF_ALG interface The patch moves the information provided in Documentation/crypto/crypto-API-userspace.txt into a separate chapter in the kernel crypto API DocBook. Some corrections are applied (such as removing a reference to Netlink when the AF_ALG socket is referred to). In addition, the AEAD and RNG interface description is now added. Also, a brief description of the zero-copy interface with an example code snippet is provided. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 596 ++++++++++++++++++ Documentation/crypto/crypto-API-userspace.txt | 205 ------ 2 files changed, 596 insertions(+), 205 deletions(-) delete mode 100644 Documentation/crypto/crypto-API-userspace.txt diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 33f63cfc00ca..efc8d90a9a3f 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -1072,6 +1072,602 @@ kernel crypto API | Caller + User Space Interface + Introduction + + The concepts of the kernel crypto API visible to kernel space is fully + applicable to the user space interface as well. Therefore, the kernel + crypto API high level discussion for the in-kernel use cases applies + here as well. + + + + The major difference, however, is that user space can only act as a + consumer and never as a provider of a transformation or cipher algorithm. + + + + The following covers the user space interface exported by the kernel + crypto API. A working example of this description is libkcapi that + can be obtained from [1]. That library can be used by user space + applications that require cryptographic services from the kernel. + + + + Some details of the in-kernel kernel crypto API aspects do not + apply to user space, however. This includes the difference between + synchronous and asynchronous invocations. The user space API call + is fully synchronous. + + + + [1] http://www.chronox.de/libkcapi.html + + + + + User Space API General Remarks + + The kernel crypto API is accessible from user space. Currently, + the following ciphers are accessible: + + + + + Message digest including keyed message digest (HMAC, CMAC) + + + + Symmetric ciphers + + + + AEAD ciphers + + + + Random Number Generators + + + + + The interface is provided via socket type using the type AF_ALG. + In addition, the setsockopt option type is SOL_ALG. In case the + user space header files do not export these flags yet, use the + following macros: + + + +#ifndef AF_ALG +#define AF_ALG 38 +#endif +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + + + + A cipher is accessed with the same name as done for the in-kernel + API calls. This includes the generic vs. unique naming schema for + ciphers as well as the enforcement of priorities for generic names. + + + + To interact with the kernel crypto API, a socket must be + created by the user space application. User space invokes the cipher + operation with the send()/write() system call family. The result of the + cipher operation is obtained with the read()/recv() system call family. + + + + The following API calls assume that the socket descriptor + is already opened by the user space application and discusses only + the kernel crypto API specific invocations. + + + + To initialize the socket interface, the following sequence has to + be performed by the consumer: + + + + + + Create a socket of type AF_ALG with the struct sockaddr_alg + parameter specified below for the different cipher types. + + + + + + Invoke bind with the socket descriptor + + + + + + Invoke accept with the socket descriptor. The accept system call + returns a new file descriptor that is to be used to interact with + the particular cipher instance. When invoking send/write or recv/read + system calls to send data to the kernel or obtain data from the + kernel, the file descriptor returned by accept must be used. + + + + + + In-place Cipher operation + + Just like the in-kernel operation of the kernel crypto API, the user + space interface allows the cipher operation in-place. That means that + the input buffer used for the send/write system call and the output + buffer used by the read/recv system call may be one and the same. + This is of particular interest for symmetric cipher operations where a + copying of the output data to its final destination can be avoided. + + + + If a consumer on the other hand wants to maintain the plaintext and + the ciphertext in different memory locations, all a consumer needs + to do is to provide different memory pointers for the encryption and + decryption operation. + + + + Message Digest API + + The message digest type to be used for the cipher operation is + selected when invoking the bind syscall. bind requires the caller + to provide a filled struct sockaddr data structure. This data + structure must be filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "hash", /* this selects the hash logic in the kernel */ + .salg_name = "sha1" /* this is the cipher name */ +}; + + + + The salg_type value "hash" applies to message digests and keyed + message digests. Though, a keyed message digest is referenced by + the appropriate salg_name. Please see below for the setsockopt + interface that explains how the key can be set for a keyed message + digest. + + + + Using the send() system call, the application provides the data that + should be processed with the message digest. The send system call + allows the following flags to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + message digest update function where the final hash is not + yet calculated. If the flag is not set, the send system call + calculates the final message digest immediately. + + + + + + With the recv() system call, the application can read the message + digest from the kernel crypto API. If the buffer is too small for the + message digest, the flag MSG_TRUNC is set by the kernel. + + + + In order to set a message digest key, the calling application must use + the setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC + operation is performed without the initial HMAC state change caused by + the key. + + + + Symmetric Cipher API + + The operation is very similar to the message digest discussion. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "skcipher", /* this selects the symmetric cipher */ + .salg_name = "cbc(aes)" /* this is the cipher name */ +}; + + + + Before data can be sent to the kernel using the write/send system + call family, the consumer must set the key. The key setting is + described with the setsockopt invocation below. + + + + Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is + specified with the data structure provided by the sendmsg() system call. + + + + The sendmsg system call parameter of struct msghdr is embedded into the + struct cmsghdr data structure. See recv(2) and cmsg(3) for more + information on how the cmsghdr data structure is used together with the + send/recv system call family. That cmsghdr data structure holds the + following information specified with a separate header instances: + + + + + + specification of the cipher operation type with one of these flags: + + + + ALG_OP_ENCRYPT - encryption of data + + + ALG_OP_DECRYPT - decryption of data + + + + + + + specification of the IV information marked with the flag ALG_SET_IV + + + + + + The send system call family allows the following flag to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + cipher update function where more input data is expected + with a subsequent invocation of the send system call. + + + + + + Note: The kernel reports -EINVAL for any unexpected data. The caller + must make sure that all data matches the constraints given in + /proc/crypto for the selected cipher. + + + + With the recv() system call, the application can read the result of + the cipher operation from the kernel crypto API. The output buffer + must be at least as large as to hold all blocks of the encrypted or + decrypted data. If the output data size is smaller, only as many + blocks are returned that fit into that output buffer size. + + + + AEAD Cipher API + + The operation is very similar to the symmetric cipher discussion. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "aead", /* this selects the symmetric cipher */ + .salg_name = "gcm(aes)" /* this is the cipher name */ +}; + + + + Before data can be sent to the kernel using the write/send system + call family, the consumer must set the key. The key setting is + described with the setsockopt invocation below. + + + + In addition, before data can be sent to the kernel using the + write/send system call family, the consumer must set the authentication + tag size. To set the authentication tag size, the caller must use the + setsockopt invocation described below. + + + + Using the sendmsg() system call, the application provides the data that should be processed for encryption or decryption. In addition, the IV is + specified with the data structure provided by the sendmsg() system call. + + + + The sendmsg system call parameter of struct msghdr is embedded into the + struct cmsghdr data structure. See recv(2) and cmsg(3) for more + information on how the cmsghdr data structure is used together with the + send/recv system call family. That cmsghdr data structure holds the + following information specified with a separate header instances: + + + + + + specification of the cipher operation type with one of these flags: + + + + ALG_OP_ENCRYPT - encryption of data + + + ALG_OP_DECRYPT - decryption of data + + + + + + + specification of the IV information marked with the flag ALG_SET_IV + + + + + + specification of the associated authentication data (AAD) with the + flag ALG_SET_AEAD_ASSOCLEN. The AAD is sent to the kernel together + with the plaintext / ciphertext. See below for the memory structure. + + + + + + The send system call family allows the following flag to be specified: + + + + + + MSG_MORE: If this flag is set, the send system call acts like a + cipher update function where more input data is expected + with a subsequent invocation of the send system call. + + + + + + Note: The kernel reports -EINVAL for any unexpected data. The caller + must make sure that all data matches the constraints given in + /proc/crypto for the selected cipher. + + + + With the recv() system call, the application can read the result of + the cipher operation from the kernel crypto API. The output buffer + must be at least as large as defined with the memory structure below. + If the output data size is smaller, the cipher operation is not performed. + + + + The authenticated decryption operation may indicate an integrity error. + Such breach in integrity is marked with the -EBADMSG error code. + + + AEAD Memory Structure + + The AEAD cipher operates with the following information that + is communicated between user and kernel space as one data stream: + + + + + plaintext or ciphertext + + + + associated authentication data (AAD) + + + + authentication tag + + + + + The sizes of the AAD and the authentication tag are provided with + the sendmsg and setsockopt calls (see there). As the kernel knows + the size of the entire data stream, the kernel is now able to + calculate the right offsets of the data components in the data + stream. + + + + The user space caller must arrange the aforementioned information + in the following order: + + + + + + AEAD encryption input: AAD || plaintext + + + + + + AEAD decryption input: AAD || ciphertext || authentication tag + + + + + + The output buffer the user space caller provides must be at least as + large to hold the following data: + + + + + + AEAD encryption output: ciphertext || authentication tag + + + + + + AEAD decryption output: plaintext + + + + + + + Random Number Generator API + + Again, the operation is very similar to the other APIs. + During initialization, the struct sockaddr data structure must be + filled as follows: + + + +struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "rng", /* this selects the symmetric cipher */ + .salg_name = "drbg_nopr_sha256" /* this is the cipher name */ +}; + + + + Depending on the RNG type, the RNG must be seeded. The seed is provided + using the setsockopt interface to set the key. For example, the + ansi_cprng requires a seed. The DRBGs do not require a seed, but + may be seeded. + + + + Using the read()/recvmsg() system calls, random numbers can be obtained. + The kernel generates at most 128 bytes in one call. If user space + requires more data, multiple calls to read()/recvmsg() must be made. + + + + WARNING: The user space caller may invoke the initially mentioned + accept system call multiple times. In this case, the returned file + descriptors have the same state. + + + + + Zero-Copy Interface + + In addition to the send/write/read/recv system call familty, the AF_ALG + interface can be accessed with the zero-copy interface of splice/vmsplice. + As the name indicates, the kernel tries to avoid a copy operation into + kernel space. + + + + The zero-copy operation requires data to be aligned at the page boundary. + Non-aligned data can be used as well, but may require more operations of + the kernel which would defeat the speed gains obtained from the zero-copy + interface. + + + + The system-interent limit for the size of one zero-copy operation is + 16 pages. If more data is to be sent to AF_ALG, user space must slice + the input into segments with a maximum size of 16 pages. + + + + Zero-copy can be used with the following code example (a complete working + example is provided with libkcapi): + + + +int pipes[2]; + +pipe(pipes); +/* input data in iov */ +vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); +/* opfd is the file descriptor returned from accept() system call */ +splice(pipes[0], NULL, opfd, NULL, ret, 0); +read(opfd, out, outlen); + + + + + Setsockopt Interface + + In addition to the read/recv and send/write system call handling + to send and retrieve data subject to the cipher operation, a consumer + also needs to set the additional information for the cipher operation. + This additional information is set using the setsockopt system call + that must be invoked with the file descriptor of the open cipher + (i.e. the file descriptor returned by the accept system call). + + + + Each setsockopt invocation must use the level SOL_ALG. + + + + The setsockopt interface allows setting the following data using + the mentioned optname: + + + + + + ALG_SET_KEY -- Setting the key. Key setting is applicable to: + + + + the skcipher cipher type (symmetric ciphers) + + + the hash cipher type (keyed message digests) + + + the AEAD cipher type + + + the RNG cipher type to provide the seed + + + + + + + ALG_SET_AEAD_AUTHSIZE -- Setting the authentication tag size + for AEAD ciphers. For a encryption operation, the authentication + tag of the given size will be generated. For a decryption operation, + the provided ciphertext is assumed to contain an authentication tag + of the given size (see section about AEAD memory layout below). + + + + + + + User space API example + + Please see [1] for libkcapi which provides an easy-to-use wrapper + around the aforementioned Netlink kernel interface. [1] also contains + a test application that invokes all libkcapi API calls. + + + + [1] http://www.chronox.de/libkcapi.html + + + + + + Programming Interface Block Cipher Context Data Structures !Pinclude/linux/crypto.h Block Cipher Context Data Structures diff --git a/Documentation/crypto/crypto-API-userspace.txt b/Documentation/crypto/crypto-API-userspace.txt deleted file mode 100644 index ac619cd90300..000000000000 --- a/Documentation/crypto/crypto-API-userspace.txt +++ /dev/null @@ -1,205 +0,0 @@ -Introduction -============ - -The concepts of the kernel crypto API visible to kernel space is fully -applicable to the user space interface as well. Therefore, the kernel crypto API -high level discussion for the in-kernel use cases applies here as well. - -The major difference, however, is that user space can only act as a consumer -and never as a provider of a transformation or cipher algorithm. - -The following covers the user space interface exported by the kernel crypto -API. A working example of this description is libkcapi that can be obtained from -[1]. That library can be used by user space applications that require -cryptographic services from the kernel. - -Some details of the in-kernel kernel crypto API aspects do not -apply to user space, however. This includes the difference between synchronous -and asynchronous invocations. The user space API call is fully synchronous. -In addition, only a subset of all cipher types are available as documented -below. - - -User space API general remarks -============================== - -The kernel crypto API is accessible from user space. Currently, the following -ciphers are accessible: - - * Message digest including keyed message digest (HMAC, CMAC) - - * Symmetric ciphers - -Note, AEAD ciphers are currently not supported via the symmetric cipher -interface. - -The interface is provided via Netlink using the type AF_ALG. In addition, the -setsockopt option type is SOL_ALG. In case the user space header files do not -export these flags yet, use the following macros: - -#ifndef AF_ALG -#define AF_ALG 38 -#endif -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif - -A cipher is accessed with the same name as done for the in-kernel API calls. -This includes the generic vs. unique naming schema for ciphers as well as the -enforcement of priorities for generic names. - -To interact with the kernel crypto API, a Netlink socket must be created by -the user space application. User space invokes the cipher operation with the -send/write system call family. The result of the cipher operation is obtained -with the read/recv system call family. - -The following API calls assume that the Netlink socket descriptor is already -opened by the user space application and discusses only the kernel crypto API -specific invocations. - -To initialize a Netlink interface, the following sequence has to be performed -by the consumer: - - 1. Create a socket of type AF_ALG with the struct sockaddr_alg parameter - specified below for the different cipher types. - - 2. Invoke bind with the socket descriptor - - 3. Invoke accept with the socket descriptor. The accept system call - returns a new file descriptor that is to be used to interact with - the particular cipher instance. When invoking send/write or recv/read - system calls to send data to the kernel or obtain data from the - kernel, the file descriptor returned by accept must be used. - -In-place cipher operation -========================= - -Just like the in-kernel operation of the kernel crypto API, the user space -interface allows the cipher operation in-place. That means that the input buffer -used for the send/write system call and the output buffer used by the read/recv -system call may be one and the same. This is of particular interest for -symmetric cipher operations where a copying of the output data to its final -destination can be avoided. - -If a consumer on the other hand wants to maintain the plaintext and the -ciphertext in different memory locations, all a consumer needs to do is to -provide different memory pointers for the encryption and decryption operation. - -Message digest API -================== - -The message digest type to be used for the cipher operation is selected when -invoking the bind syscall. bind requires the caller to provide a filled -struct sockaddr data structure. This data structure must be filled as follows: - -struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "hash", /* this selects the hash logic in the kernel */ - .salg_name = "sha1" /* this is the cipher name */ -}; - -The salg_type value "hash" applies to message digests and keyed message digests. -Though, a keyed message digest is referenced by the appropriate salg_name. -Please see below for the setsockopt interface that explains how the key can be -set for a keyed message digest. - -Using the send() system call, the application provides the data that should be -processed with the message digest. The send system call allows the following -flags to be specified: - - * MSG_MORE: If this flag is set, the send system call acts like a - message digest update function where the final hash is not - yet calculated. If the flag is not set, the send system call - calculates the final message digest immediately. - -With the recv() system call, the application can read the message digest from -the kernel crypto API. If the buffer is too small for the message digest, the -flag MSG_TRUNC is set by the kernel. - -In order to set a message digest key, the calling application must use the -setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC operation is -performed without the initial HMAC state change caused by the key. - - -Symmetric cipher API -==================== - -The operation is very similar to the message digest discussion. During -initialization, the struct sockaddr data structure must be filled as follows: - -struct sockaddr_alg sa = { - .salg_family = AF_ALG, - .salg_type = "skcipher", /* this selects the symmetric cipher */ - .salg_name = "cbc(aes)" /* this is the cipher name */ -}; - -Before data can be sent to the kernel using the write/send system call family, -the consumer must set the key. The key setting is described with the setsockopt -invocation below. - -Using the sendmsg() system call, the application provides the data that should -be processed for encryption or decryption. In addition, the IV is specified -with the data structure provided by the sendmsg() system call. - -The sendmsg system call parameter of struct msghdr is embedded into the -struct cmsghdr data structure. See recv(2) and cmsg(3) for more information -on how the cmsghdr data structure is used together with the send/recv system -call family. That cmsghdr data structure holds the following information -specified with a separate header instances: - - * specification of the cipher operation type with one of these flags: - ALG_OP_ENCRYPT - encryption of data - ALG_OP_DECRYPT - decryption of data - - * specification of the IV information marked with the flag ALG_SET_IV - -The send system call family allows the following flag to be specified: - - * MSG_MORE: If this flag is set, the send system call acts like a - cipher update function where more input data is expected - with a subsequent invocation of the send system call. - -Note: The kernel reports -EINVAL for any unexpected data. The caller must -make sure that all data matches the constraints given in /proc/crypto for the -selected cipher. - -With the recv() system call, the application can read the result of the -cipher operation from the kernel crypto API. The output buffer must be at least -as large as to hold all blocks of the encrypted or decrypted data. If the output -data size is smaller, only as many blocks are returned that fit into that -output buffer size. - -Setsockopt interface -==================== - -In addition to the read/recv and send/write system call handling to send and -retrieve data subject to the cipher operation, a consumer also needs to set -the additional information for the cipher operation. This additional information -is set using the setsockopt system call that must be invoked with the file -descriptor of the open cipher (i.e. the file descriptor returned by the -accept system call). - -Each setsockopt invocation must use the level SOL_ALG. - -The setsockopt interface allows setting the following data using the mentioned -optname: - - * ALG_SET_KEY -- Setting the key. Key setting is applicable to: - - - the skcipher cipher type (symmetric ciphers) - - - the hash cipher type (keyed message digests) - -User space API example -====================== - -Please see [1] for libkcapi which provides an easy-to-use wrapper around the -aforementioned Netlink kernel interface. [1] also contains a test application -that invokes all libkcapi API calls. - -[1] http://www.chronox.de/libkcapi.html - -Author -====== - -Stephan Mueller -- GitLab From 2ca87a17045194638c69be87e2430842f743b00b Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 6 Mar 2015 21:36:21 +0100 Subject: [PATCH 0264/1910] MAINTAINERS: add crypto-API.tmpl The file Documentation/DocBook/crypto-API.tmpl documents the kernel crypto API and is maintained. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddc5a8cf9a8a..c10814e53858 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2805,6 +2805,7 @@ L: linux-crypto@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git S: Maintained F: Documentation/crypto/ +F: Documentation/DocBook/crypto-API.tmpl F: arch/*/crypto/ F: crypto/ F: drivers/crypto/ -- GitLab From a508412b169d5398dc5f800147097b255c2941be Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Fri, 6 Mar 2015 14:53:15 -0800 Subject: [PATCH 0265/1910] hwrng: xgene - add ACPI support for APM X-Gene RNG unit This adds ACPI support for APM X-Gene RNG unit. Signed-off-by: Feng Kan Signed-off-by: Herbert Xu --- drivers/char/hw_random/xgene-rng.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index 23caa05380a8..c37cf754a985 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -21,6 +21,7 @@ * */ +#include #include #include #include @@ -310,6 +311,14 @@ static int xgene_rng_init(struct hwrng *rng) return 0; } +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_rng_acpi_match[] = { + { "APMC0D18", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, xgene_rng_acpi_match); +#endif + static struct hwrng xgene_rng_func = { .name = "xgene-rng", .init = xgene_rng_init, @@ -415,6 +424,7 @@ static struct platform_driver xgene_rng_driver = { .driver = { .name = "xgene-rng", .of_match_table = xgene_rng_of_match, + .acpi_match_table = ACPI_PTR(xgene_rng_acpi_match), }, }; -- GitLab From 3265c4babe93832167cb148083a0544548c23e6a Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 6 Mar 2015 18:46:21 -0600 Subject: [PATCH 0266/1910] crypto: powerpc - move files to fix build error The current cryptodev-2.6 tree commits: d9850fc529ef ("crypto: powerpc/sha1 - kernel config") 50ba29aaa7b0 ("crypto: powerpc/sha1 - glue") failed to properly place files under arch/powerpc/crypto, which leads to build errors: make[1]: *** No rule to make target 'arch/powerpc/crypto/sha1-spe-asm.o', needed by 'arch/powerpc/crypto/sha1-ppc-spe.o'. Stop. make[1]: *** No rule to make target 'arch/powerpc/crypto/sha1_spe_glue.o', needed by 'arch/powerpc/crypto/sha1-ppc-spe.o'. Stop. Makefile:947: recipe for target 'arch/powerpc/crypto' failed Move the two sha1 spe files under crypto/, and whilst there, rename other powerpc crypto files with underscores to use dashes for consistency. Cc: Markus Stockhausen Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- arch/powerpc/crypto/Makefile | 8 ++++---- arch/powerpc/crypto/{aes_spe_glue.c => aes-spe-glue.c} | 0 arch/powerpc/crypto/{md5_glue.c => md5-glue.c} | 0 arch/powerpc/{ => crypto}/sha1-spe-asm.S | 0 arch/powerpc/{sha1_spe_glue.c => crypto/sha1-spe-glue.c} | 0 .../crypto/{sha256_spe_glue.c => sha256-spe-glue.c} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename arch/powerpc/crypto/{aes_spe_glue.c => aes-spe-glue.c} (100%) rename arch/powerpc/crypto/{md5_glue.c => md5-glue.c} (100%) rename arch/powerpc/{ => crypto}/sha1-spe-asm.S (100%) rename arch/powerpc/{sha1_spe_glue.c => crypto/sha1-spe-glue.c} (100%) rename arch/powerpc/crypto/{sha256_spe_glue.c => sha256-spe-glue.c} (100%) diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index c6b25cba3a0c..9c221b69c181 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -10,8 +10,8 @@ obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o obj-$(CONFIG_CRYPTO_SHA1_PPC_SPE) += sha1-ppc-spe.o obj-$(CONFIG_CRYPTO_SHA256_PPC_SPE) += sha256-ppc-spe.o -aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes_spe_glue.o -md5-ppc-y := md5-asm.o md5_glue.o +aes-ppc-spe-y := aes-spe-core.o aes-spe-keys.o aes-tab-4k.o aes-spe-modes.o aes-spe-glue.o +md5-ppc-y := md5-asm.o md5-glue.o sha1-powerpc-y := sha1-powerpc-asm.o sha1.o -sha1-ppc-spe-y := sha1-spe-asm.o sha1_spe_glue.o -sha256-ppc-spe-y := sha256-spe-asm.o sha256_spe_glue.o +sha1-ppc-spe-y := sha1-spe-asm.o sha1-spe-glue.o +sha256-ppc-spe-y := sha256-spe-asm.o sha256-spe-glue.o diff --git a/arch/powerpc/crypto/aes_spe_glue.c b/arch/powerpc/crypto/aes-spe-glue.c similarity index 100% rename from arch/powerpc/crypto/aes_spe_glue.c rename to arch/powerpc/crypto/aes-spe-glue.c diff --git a/arch/powerpc/crypto/md5_glue.c b/arch/powerpc/crypto/md5-glue.c similarity index 100% rename from arch/powerpc/crypto/md5_glue.c rename to arch/powerpc/crypto/md5-glue.c diff --git a/arch/powerpc/sha1-spe-asm.S b/arch/powerpc/crypto/sha1-spe-asm.S similarity index 100% rename from arch/powerpc/sha1-spe-asm.S rename to arch/powerpc/crypto/sha1-spe-asm.S diff --git a/arch/powerpc/sha1_spe_glue.c b/arch/powerpc/crypto/sha1-spe-glue.c similarity index 100% rename from arch/powerpc/sha1_spe_glue.c rename to arch/powerpc/crypto/sha1-spe-glue.c diff --git a/arch/powerpc/crypto/sha256_spe_glue.c b/arch/powerpc/crypto/sha256-spe-glue.c similarity index 100% rename from arch/powerpc/crypto/sha256_spe_glue.c rename to arch/powerpc/crypto/sha256-spe-glue.c -- GitLab From 700d98551ff16a59e164bf884aefbdc5d798ff75 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 29 Jan 2015 17:54:46 +1100 Subject: [PATCH 0267/1910] ncr5380: Drop owner assignment from platform_drivers This platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Wolfram Sang Signed-off-by: Finn Thain Signed-off-by: James Bottomley --- drivers/scsi/atari_scsi.c | 1 - drivers/scsi/mac_scsi.c | 1 - drivers/scsi/sun3_scsi.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index d1c37a386947..5ede3daa93dc 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -1014,7 +1014,6 @@ static struct platform_driver atari_scsi_driver = { .remove = __exit_p(atari_scsi_remove), .driver = { .name = DRV_MODULE_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 1e85c07e3b62..d64a769b8155 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -483,7 +483,6 @@ static struct platform_driver mac_scsi_driver = { .remove = __exit_p(mac_scsi_remove), .driver = { .name = DRV_MODULE_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 2a906d1d34ba..22a42836d193 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -676,7 +676,6 @@ static struct platform_driver sun3_scsi_driver = { .remove = __exit_p(sun3_scsi_remove), .driver = { .name = DRV_MODULE_NAME, - .owner = THIS_MODULE, }, }; -- GitLab From b026e8ed55e05a81018ba4ce73ca0cf2c9300950 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 3 Jan 2015 23:00:16 +0100 Subject: [PATCH 0268/1910] g_NCR5380: Kill compiler warning if builtin If CONFIG_SCSI_GENERIC_NCR5380=y: drivers/scsi/g_NCR5380.c:727: warning: 'id_table' defined but not used In the non-modular case, MODULE_DEVICE_TABLE() expands to nothing, and id_table is not referenced. Correct the existing #ifdef to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: James Bottomley --- drivers/scsi/g_NCR5380.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index f35792f7051c..74ec2f5669ab 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -723,7 +723,7 @@ module_param(ncr_53c400a, int, 0); module_param(dtc_3181e, int, 0); MODULE_LICENSE("GPL"); -#ifndef SCSI_G_NCR5380_MEM +#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE) static struct isapnp_device_id id_table[] = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, -- GitLab From 8582e267e9a29ccfd2151c5d74bc2b1440dfb827 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 11 Feb 2015 13:53:14 +0100 Subject: [PATCH 0269/1910] asm/dma-mapping-common: Clarify output of dma_map_sg_attrs Although dma_map_sg_attrs returns 0 on error and it cannot return a value < 0, the function returns a signed integer. Most of the time, this function is used with a scatterlist structure. This structure uses an unsigned integer for the number of memory. A dma developer that has not read in detail DMA-API.txt, can wrongly return a value < 0 on error. The comment will help the driver developer, and the WARN_ON the dma developer. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Marek Szyprowski --- include/asm-generic/dma-mapping-common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 3378dcf4c31e..940d5ec122c9 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -39,6 +39,10 @@ static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, debug_dma_unmap_page(dev, addr, size, dir, true); } +/* + * dma_maps_sg_attrs returns 0 on error and > 0 on success. + * It should never return a value < 0. + */ static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) @@ -51,6 +55,7 @@ static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, kmemcheck_mark_initialized(sg_virt(s), s->length); BUG_ON(!valid_dma_direction(dir)); ents = ops->map_sg(dev, sg, nents, dir, attrs); + BUG_ON(ents < 0); debug_dma_map_sg(dev, sg, nents, ents, dir); return ents; -- GitLab From 04abab698285297115e5096b3100df1064045529 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 11 Feb 2015 13:53:15 +0100 Subject: [PATCH 0270/1910] include/dma-mapping: Clarify output of dma_map_sg Although dma_map_sg returns 0 on error and it cannot return a value < 0, the function returns a signed integer. Most of the time, this function is used with a scatterlist structure. This structure uses an unsigned integer for the number of memory. A dma developer that has not read in detail DMA-API.txt, can wrongly return a value < 0 on error. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Marek Szyprowski --- include/linux/dma-mapping.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index c3007cb4bfa6..ac07ff090919 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -34,6 +34,10 @@ struct dma_map_ops { void (*unmap_page)(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs); + /* + * map_sg returns 0 on error and a value > 0 on success. + * It should never return a value < 0. + */ int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs); -- GitLab From 4e5a800c82ec21335349a97cf58d97fbb0d3c98e Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 4 Feb 2015 13:30:20 -0500 Subject: [PATCH 0271/1910] ncr5380: Harmonize jiffies conversion with msecs_to_jiffies Instances of var * HZ / 1000 are replaced by msecs_to_jiffies(var). In addition some timing constants that assumed HZ 100 were adjusted to HZ independent settings based on review comments from Michael Schmitz and review of the original drivers in 1.0.31 and 2.2.16. Signed-off-by: Nicholas Mc Guire Acked-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: James Bottomley --- drivers/scsi/NCR5380.c | 10 +++++----- drivers/scsi/atari_NCR5380.c | 2 +- drivers/scsi/g_NCR5380.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 8981701802ca..a777e5c412df 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -474,11 +474,11 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) */ #ifndef USLEEP_SLEEP /* 20 ms (reasonable hard disk speed) */ -#define USLEEP_SLEEP (20*HZ/1000) +#define USLEEP_SLEEP msecs_to_jiffies(20) #endif /* 300 RPM (floppy speed) */ #ifndef USLEEP_POLL -#define USLEEP_POLL (200*HZ/1000) +#define USLEEP_POLL msecs_to_jiffies(200) #endif #ifndef USLEEP_WAITLONG /* RvC: (reasonable time to wait on select error) */ @@ -576,7 +576,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0)) trying_irqs |= mask; - timeout = jiffies + (250 * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(250); probe_irq = NO_IRQ; /* @@ -634,7 +634,7 @@ static void prepare_info(struct Scsi_Host *instance) "sg_tablesize %d, this_id %d, " "flags { %s%s%s}, " #if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG) - "USLEEP_POLL %d, USLEEP_WAITLONG %d, " + "USLEEP_POLL %lu, USLEEP_WAITLONG %lu, " #endif "options { %s} ", instance->hostt->name, instance->io_port, instance->n_io_port, @@ -1346,7 +1346,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) * selection. */ - timeout = jiffies + (250 * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(250); /* * XXX very interesting - we're seeing a bounce where the BSY we diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index a70255413e7f..db87ece6edb2 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -1486,7 +1486,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) * selection. */ - timeout = jiffies + (250 * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(250); /* * XXX very interesting - we're seeing a bounce where the BSY we diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 74ec2f5669ab..f8d2478b11cc 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -57,9 +57,9 @@ */ /* settings for DTC3181E card with only Mustek scanner attached */ -#define USLEEP_POLL 1 -#define USLEEP_SLEEP 20 -#define USLEEP_WAITLONG 500 +#define USLEEP_POLL msecs_to_jiffies(10) +#define USLEEP_SLEEP msecs_to_jiffies(200) +#define USLEEP_WAITLONG msecs_to_jiffies(5000) #define AUTOPROBE_IRQ -- GitLab From 967beb2e87771411e08467152e3d9f1c3ae73a67 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Mon, 9 Mar 2015 12:11:08 +0000 Subject: [PATCH 0272/1910] ASoC: jz4740: Add jz4780 support The jz4780 and jz4740 have very similar i2s blocks. The slight difference is in Rx/Tx fifos. And the bitclocks for input/output are different. This patch adds jz4780 support to the driver Signed-off-by: Zubair Lutfullah Kakakhel Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4740-i2s.txt | 2 +- sound/soc/jz4740/jz4740-i2s.c | 84 ++++++++++++++++--- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt index b41433386e2f..b623d50004fb 100644 --- a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt @@ -1,7 +1,7 @@ Ingenic JZ4740 I2S controller Required properties: -- compatible : "ingenic,jz4740-i2s" +- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s" - reg : I2S registers location and length - clocks : AIC and I2S PLL clock specifiers. - clock-names: "aic" and "i2s" diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 07f77815a586..b05fb1c1a848 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -58,6 +58,12 @@ #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 +#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24 +#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16 +#define JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_MASK \ + (0xf << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) +#define JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_MASK \ + (0x1f << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) @@ -79,6 +85,7 @@ #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) +#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13) #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) #define JZ_AIC_I2S_FMT_MSB BIT(0) @@ -87,6 +94,13 @@ #define JZ_AIC_CLK_DIV_MASK 0xf #define I2SDIV_DV_SHIFT 8 #define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) +#define I2SDIV_IDV_SHIFT 8 +#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT) + +enum jz47xx_i2s_version { + JZ_I2S_JZ4740, + JZ_I2S_JZ4780, +}; struct jz4740_i2s { struct resource *mem; @@ -98,6 +112,8 @@ struct jz4740_i2s { struct snd_dmaengine_dai_dma_data playback_dma_data; struct snd_dmaengine_dai_dma_data capture_dma_data; + + enum jz47xx_i2s_version version; }; static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, @@ -267,13 +283,22 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; else ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; + + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; } else { ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; + + if (i2s->version >= JZ_I2S_JZ4780) { + div_reg &= ~I2SDIV_IDV_MASK; + div_reg |= (div - 1) << I2SDIV_IDV_SHIFT; + } else { + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; + } } - div_reg &= ~I2SDIV_DV_MASK; - div_reg |= (div - 1) << I2SDIV_DV_SHIFT; jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg); @@ -369,11 +394,19 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, &i2s->capture_dma_data); - conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | - (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | - JZ_AIC_CONF_OVERFLOW_PLAY_LAST | - JZ_AIC_CONF_I2S | - JZ_AIC_CONF_INTERNAL_CODEC; + if (i2s->version >= JZ_I2S_JZ4780) { + conf = (7 << JZ4780_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | + (8 << JZ4780_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | + JZ_AIC_CONF_OVERFLOW_PLAY_LAST | + JZ_AIC_CONF_I2S | + JZ_AIC_CONF_INTERNAL_CODEC; + } else { + conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | + (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | + JZ_AIC_CONF_OVERFLOW_PLAY_LAST | + JZ_AIC_CONF_I2S | + JZ_AIC_CONF_INTERNAL_CODEC; + } jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); @@ -422,13 +455,34 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = { .resume = jz4740_i2s_resume, }; +static struct snd_soc_dai_driver jz4780_i2s_dai = { + .probe = jz4740_i2s_dai_probe, + .remove = jz4740_i2s_dai_remove, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = JZ4740_I2S_FMTS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = JZ4740_I2S_FMTS, + }, + .ops = &jz4740_i2s_dai_ops, + .suspend = jz4740_i2s_suspend, + .resume = jz4740_i2s_resume, +}; + static const struct snd_soc_component_driver jz4740_i2s_component = { .name = "jz4740-i2s", }; #ifdef CONFIG_OF static const struct of_device_id jz4740_of_matches[] = { - { .compatible = "ingenic,jz4740-i2s" }, + { .compatible = "ingenic,jz4740-i2s", .data = (void *)JZ_I2S_JZ4740 }, + { .compatible = "ingenic,jz4780-i2s", .data = (void *)JZ_I2S_JZ4780 }, { /* sentinel */ } }; #endif @@ -438,11 +492,16 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) struct jz4740_i2s *i2s; struct resource *mem; int ret; + const struct of_device_id *match; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) return -ENOMEM; + match = of_match_device(jz4740_of_matches, &pdev->dev); + if (match) + i2s->version = (enum jz47xx_i2s_version)match->data; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2s->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(i2s->base)) @@ -460,8 +519,13 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2s); - ret = devm_snd_soc_register_component(&pdev->dev, - &jz4740_i2s_component, &jz4740_i2s_dai, 1); + if (i2s->version == JZ_I2S_JZ4780) + ret = devm_snd_soc_register_component(&pdev->dev, + &jz4740_i2s_component, &jz4780_i2s_dai, 1); + else + ret = devm_snd_soc_register_component(&pdev->dev, + &jz4740_i2s_component, &jz4740_i2s_dai, 1); + if (ret) return ret; -- GitLab From bd22f9d405eb14cc074d294919d0b909e0bc6170 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Mar 2015 16:55:22 +0800 Subject: [PATCH 0273/1910] ASoC: rt5670: Revert Keep sysclk on patch The "Keep sysclk on if JD func is used" patch force enable/disable pin in rt5670_set_dai_sysclk. But some machine driver call it in dapm widget event. It will cause kernel crash. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 592f961b5de5..32cd26678bae 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2273,13 +2273,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) return 0; - if (rt5670->pdata.jd_mode) { - if (clk_id == RT5670_SCLK_S_PLL1) - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - else - snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); - snd_soc_dapm_sync(&codec->dapm); - } switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2724,10 +2717,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } if (rt5670->pdata.jd_mode) { - regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, - RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); - rt5670->sysclk = 0; - rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, RT5670_PWR_MB, RT5670_PWR_MB); regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, -- GitLab From 485372dc24ca2eaac18ce41a51b9dd017bc11400 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Mar 2015 16:55:23 +0800 Subject: [PATCH 0274/1910] ASoC: rt5670: Check sysclk source by private data Currently, is_sys_clk_from_pll check sysclk source by reading codec register value. And it will be invoked before updating dapm widget power. In some machine driver, snd_soc_dai_set_sysclk is called in dapm event to switch codec sysclk to RC clock in idle mode. And in some use cases (such as syspend/resume) hw_params will not be called when the dapm widget is powered up. As a result, is_sys_clk_from_pll will return 0 although it is supposed to be 1. To solve this, we let is_sys_clk_from_pll check sysclk sysclk_src which is stored in private data and don't change the value of sysclk_src when codec sysclk is switched to internal clock. The internal clock can only be used in idle mode, so it sould be fine if we don't set sysclk_src to internal clock. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 32cd26678bae..9e3bc43178f1 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -517,11 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - unsigned int val; + struct snd_soc_codec *codec = source->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); - val = snd_soc_read(source->codec, RT5670_GLB_CLK); - val &= RT5670_SCLK_SRC_MASK; - if (val == RT5670_SCLK_SRC_PLL1) + if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1) return 1; else return 0; @@ -2270,9 +2269,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); unsigned int reg_val = 0; - if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) - return 0; - switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2290,7 +2286,8 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, RT5670_GLB_CLK, RT5670_SCLK_SRC_MASK, reg_val); rt5670->sysclk = freq; - rt5670->sysclk_src = clk_id; + if (clk_id != RT5670_SCLK_S_RCCLK) + rt5670->sysclk_src = clk_id; dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); -- GitLab From 62c76fe2e580f6a975679e8711bade09e24c204b Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Mar 2015 06:02:15 -0400 Subject: [PATCH 0275/1910] ASoC: wm8996: match wait_for_completion_timeout return type return type of wait_for_completion_timeout is unsigned long not int. An appropriately named unsigned long is added and the assignment fixed up in case of completion occurring the remaining time is >=1 so ret is set to 1 if no timeout occurred. Signed-off-by: Nicholas Mc Guire Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index dc92d5e4e942..7a2b96959589 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2009,7 +2009,7 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); struct i2c_client *i2c = to_i2c_client(codec->dev); struct _fll_div fll_div; - unsigned long timeout; + unsigned long timeout, time_left; int ret, reg, retry; /* Any change? */ @@ -2113,10 +2113,11 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, timeout /= 2; for (retry = 0; retry < 10; retry++) { - ret = wait_for_completion_timeout(&wm8996->fll_lock, - timeout); - if (ret != 0) { + time_left = wait_for_completion_timeout(&wm8996->fll_lock, + timeout); + if (time_left != 0) { WARN_ON(!i2c->irq); + ret = 1; break; } -- GitLab From 159366ea38706402e8ebd0f55eef52931333deac Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Mar 2015 06:02:38 -0400 Subject: [PATCH 0276/1910] ASoC: wm8996: ensure lower bounds of 1 for timeout wait_for_completion_timeout can be called with timeout == 0 due to msecs_to_jiffies(2) == 1 for HZ < 1000 and usecs_to_jiffies(300) == 1 for all reasonable values of HZ, thus the following timeout /= 2; sets timeout to 0. This patch simply adds a lower-bounds of 1. Signed-off-by: Nicholas Mc Guire Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 7a2b96959589..308748a022c5 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2110,7 +2110,8 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source, if (i2c->irq) timeout *= 10; else - timeout /= 2; + /* ensure timeout of atleast 1 jiffies */ + timeout = timeout/2 ? : 1; for (retry = 0; retry < 10; retry++) { time_left = wait_for_completion_timeout(&wm8996->fll_lock, -- GitLab From 17f4ad601d2753be7f15cd2928e89309759e4936 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Mar 2015 09:16:49 -0400 Subject: [PATCH 0277/1910] ASoC: arizona: match wait_for_completion_timeout return type return type of wait_for_completion_timeout is unsigned long not int. An appropriately named unsigned long is added and the assignment fixed up. Signed-off-by: Nicholas Mc Guire Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 29202610dd0d..9015b44a9e11 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1901,7 +1901,7 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll) static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - int ret; + unsigned long time_left; bool use_sync = false; int already_enabled = arizona_is_enabled_fll(fll); struct arizona_fll_cfg cfg; @@ -1977,9 +1977,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - ret = wait_for_completion_timeout(&fll->ok, + time_left = wait_for_completion_timeout(&fll->ok, msecs_to_jiffies(250)); - if (ret == 0) + if (time_left == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); return 0; -- GitLab From 905a808664402dec0ac11376833e79da4ae7b2fd Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Mar 2015 06:57:07 -0400 Subject: [PATCH 0278/1910] ASoC: wm5100: match wait_for_completion_timeout return type return type of wait_for_completion_timeout is unsigned long not int. An appropriately named unsigned long is added and the assignment fixed up. Signed-off-by: Nicholas Mc Guire Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index ea09db585aa1..96740379b711 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1762,6 +1762,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, struct _fll_div factors; struct wm5100_fll *fll; int ret, base, lock, i, timeout; + unsigned long time_left; switch (fll_id) { case WM5100_FLL1: @@ -1842,9 +1843,9 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source, /* Poll for the lock; will use interrupt when we can test */ for (i = 0; i < timeout; i++) { if (i2c->irq) { - ret = wait_for_completion_timeout(&fll->lock, - msecs_to_jiffies(25)); - if (ret > 0) + time_left = wait_for_completion_timeout(&fll->lock, + msecs_to_jiffies(25)); + if (time_left > 0) break; } else { msleep(1); -- GitLab From 78bb997ace926451ec8d1ed15178b161dc61b805 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Mar 2015 07:06:05 -0400 Subject: [PATCH 0279/1910] ASoC: wm2200: match wait_for_completion_timeout return type return type of wait_for_completion_timeout is unsigned long not int. An appropriately named unsigned long is added and the assignment fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 15599845a660..b48694a8d213 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1942,6 +1942,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); struct _fll_div factors; int ret, i, timeout; + unsigned long time_left; if (!Fout) { dev_dbg(codec->dev, "FLL disabled"); @@ -2021,9 +2022,10 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, /* Poll for the lock; will use the interrupt to exit quickly */ for (i = 0; i < timeout; i++) { if (i2c->irq) { - ret = wait_for_completion_timeout(&wm2200->fll_lock, - msecs_to_jiffies(25)); - if (ret > 0) + time_left = wait_for_completion_timeout( + &wm2200->fll_lock, + msecs_to_jiffies(25)); + if (time_left > 0) break; } else { msleep(1); -- GitLab From 32556394501a27c02e7185c4d11a51b636b02f4b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 11:15:28 -0700 Subject: [PATCH 0280/1910] ASoC: cx20442: remove incorerct __exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Mark Brown --- sound/soc/codecs/cx20442.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 0b10979513c4..0f334bc1b63c 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -420,7 +420,7 @@ static int cx20442_platform_probe(struct platform_device *pdev) &cx20442_codec_dev, &cx20442_dai, 1); } -static int __exit cx20442_platform_remove(struct platform_device *pdev) +static int cx20442_platform_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; @@ -431,7 +431,7 @@ static struct platform_driver cx20442_platform_driver = { .name = "cx20442-codec", }, .probe = cx20442_platform_probe, - .remove = __exit_p(cx20442_platform_remove), + .remove = cx20442_platform_remove, }; module_platform_driver(cx20442_platform_driver); -- GitLab From f580f8afd0d81c3f04d8b393c9d675ef289e4d40 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 11:18:14 -0700 Subject: [PATCH 0281/1910] ASoC: tlv320aic23: remove incorrect __exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23-i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index f13701995482..78a94af65518 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -31,7 +31,7 @@ static int tlv320aic23_i2c_probe(struct i2c_client *i2c, return tlv320aic23_probe(&i2c->dev, regmap); } -static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) +static int tlv320aic23_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); return 0; @@ -56,7 +56,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { .of_match_table = of_match_ptr(tlv320aic23_of_match), }, .probe = tlv320aic23_i2c_probe, - .remove = __exit_p(tlv320aic23_i2c_remove), + .remove = tlv320aic23_i2c_remove, .id_table = tlv320aic23_id, }; -- GitLab From ca1bb4ee4c3a017bb66840d11d5efdf4e8f3f66d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 23 Feb 2015 16:11:41 -0800 Subject: [PATCH 0282/1910] leds: Introduce devres helper for led_classdev_register (cooloney@gmail.com: add _unregister function into the document) Suggested-by: Stephen Boyd Signed-off-by: Bjorn Andersson Signed-off-by: Bryan Wu --- Documentation/driver-model/devres.txt | 4 ++ drivers/leds/led-class.c | 57 +++++++++++++++++++++++++++ include/linux/leds.h | 4 ++ 3 files changed, 65 insertions(+) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 6d1e8eeb5990..e1e2bbd7a404 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -289,6 +289,10 @@ IRQ devm_request_irq() devm_request_threaded_irq() +LED + devm_led_classdev_register() + devm_led_classdev_unregister() + MDIO devm_mdiobus_alloc() devm_mdiobus_alloc_size() diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 795ec994c663..768d33a79881 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -288,6 +288,63 @@ void led_classdev_unregister(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_unregister); +static void devm_led_classdev_release(struct device *dev, void *res) +{ + led_classdev_unregister(*(struct led_classdev **)res); +} + +/** + * devm_led_classdev_register - resource managed led_classdev_register() + * @parent: The device to register. + * @led_cdev: the led_classdev structure for this device. + */ +int devm_led_classdev_register(struct device *parent, + struct led_classdev *led_cdev) +{ + struct led_classdev **dr; + int rc; + + dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = led_classdev_register(parent, led_cdev); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = led_cdev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_led_classdev_register); + +static int devm_led_classdev_match(struct device *dev, void *res, void *data) +{ + struct led_cdev **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +/** + * devm_led_classdev_unregister() - resource managed led_classdev_unregister() + * @parent: The device to unregister. + * @led_cdev: the led_classdev structure for this device. + */ +void devm_led_classdev_unregister(struct device *dev, + struct led_classdev *led_cdev) +{ + WARN_ON(devres_release(dev, + devm_led_classdev_release, + devm_led_classdev_match, led_cdev)); +} +EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); + static int __init leds_init(void) { leds_class = class_create(THIS_MODULE, "leds"); diff --git a/include/linux/leds.h b/include/linux/leds.h index f70f84f35674..ed634279062e 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -105,7 +105,11 @@ struct led_classdev { extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); +extern int devm_led_classdev_register(struct device *parent, + struct led_classdev *led_cdev); extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern void devm_led_classdev_unregister(struct device *parent, + struct led_classdev *led_cdev); extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); -- GitLab From 94fdec768dc72a6993479f59a17daa413f30029e Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Wed, 4 Mar 2015 08:14:22 -0800 Subject: [PATCH 0283/1910] leds: flash: Remove synchronized flash strobe feature Synchronized flash strobe feature has been considered not fitting for LED subsystem sysfs interface and thus is being removed. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Signed-off-by: Bryan Wu --- drivers/leds/led-class-flash.c | 82 --------------------------------- include/linux/led-class-flash.h | 14 ------ include/linux/leds.h | 1 - 3 files changed, 97 deletions(-) diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c index 4a19fd44f93f..3b2573411a37 100644 --- a/drivers/leds/led-class-flash.c +++ b/drivers/leds/led-class-flash.c @@ -216,75 +216,6 @@ static ssize_t flash_fault_show(struct device *dev, } static DEVICE_ATTR_RO(flash_fault); -static ssize_t available_sync_leds_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); - char *pbuf = buf; - int i, buf_len; - - buf_len = sprintf(pbuf, "[0: none] "); - pbuf += buf_len; - - for (i = 0; i < fled_cdev->num_sync_leds; ++i) { - buf_len = sprintf(pbuf, "[%d: %s] ", i + 1, - fled_cdev->sync_leds[i]->led_cdev.name); - pbuf += buf_len; - } - - return sprintf(buf, "%s\n", buf); -} -static DEVICE_ATTR_RO(available_sync_leds); - -static ssize_t flash_sync_strobe_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); - unsigned long led_id; - ssize_t ret; - - mutex_lock(&led_cdev->led_access); - - if (led_sysfs_is_disabled(led_cdev)) { - ret = -EBUSY; - goto unlock; - } - - ret = kstrtoul(buf, 10, &led_id); - if (ret) - goto unlock; - - if (led_id > fled_cdev->num_sync_leds) { - ret = -ERANGE; - goto unlock; - } - - fled_cdev->sync_led_id = led_id; - - ret = size; -unlock: - mutex_unlock(&led_cdev->led_access); - return ret; -} - -static ssize_t flash_sync_strobe_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); - int sled_id = fled_cdev->sync_led_id; - char *sync_led_name = "none"; - - if (fled_cdev->sync_led_id > 0) - sync_led_name = (char *) - fled_cdev->sync_leds[sled_id - 1]->led_cdev.name; - - return sprintf(buf, "[%d: %s]\n", sled_id, sync_led_name); -} -static DEVICE_ATTR_RW(flash_sync_strobe); - static struct attribute *led_flash_strobe_attrs[] = { &dev_attr_flash_strobe.attr, NULL, @@ -307,12 +238,6 @@ static struct attribute *led_flash_fault_attrs[] = { NULL, }; -static struct attribute *led_flash_sync_strobe_attrs[] = { - &dev_attr_available_sync_leds.attr, - &dev_attr_flash_sync_strobe.attr, - NULL, -}; - static const struct attribute_group led_flash_strobe_group = { .attrs = led_flash_strobe_attrs, }; @@ -329,10 +254,6 @@ static const struct attribute_group led_flash_fault_group = { .attrs = led_flash_fault_attrs, }; -static const struct attribute_group led_flash_sync_strobe_group = { - .attrs = led_flash_sync_strobe_attrs, -}; - static void led_flash_resume(struct led_classdev *led_cdev) { struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); @@ -361,9 +282,6 @@ static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev) if (ops->fault_get) flash_groups[num_sysfs_groups++] = &led_flash_fault_group; - if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE) - flash_groups[num_sysfs_groups++] = &led_flash_sync_strobe_group; - led_cdev->groups = flash_groups; } diff --git a/include/linux/led-class-flash.h b/include/linux/led-class-flash.h index 3b5b9643cea1..21ec91e13c47 100644 --- a/include/linux/led-class-flash.h +++ b/include/linux/led-class-flash.h @@ -81,20 +81,6 @@ struct led_classdev_flash { /* LED Flash class sysfs groups */ const struct attribute_group *sysfs_groups[LED_FLASH_MAX_SYSFS_GROUPS]; - - /* LEDs available for flash strobe synchronization */ - struct led_classdev_flash **sync_leds; - - /* Number of LEDs available for flash strobe synchronization */ - int num_sync_leds; - - /* - * The identifier of the sub-led to synchronize the flash strobe with. - * Identifiers start from 1, which reflects the first element from the - * sync_leds array. 0 means that the flash strobe should not be - * synchronized. - */ - u32 sync_led_id; }; static inline struct led_classdev_flash *lcdev_to_flcdev( diff --git a/include/linux/leds.h b/include/linux/leds.h index ed634279062e..9a2b000094cf 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -47,7 +47,6 @@ struct led_classdev { #define SET_BRIGHTNESS_ASYNC (1 << 21) #define SET_BRIGHTNESS_SYNC (1 << 22) #define LED_DEV_CAP_FLASH (1 << 23) -#define LED_DEV_CAP_SYNC_STROBE (1 << 24) /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -- GitLab From 9c4a8e138cfe2cc7262d5d2224162add5632b546 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Wed, 4 Mar 2015 08:14:23 -0800 Subject: [PATCH 0284/1910] leds: flash: document sysfs interface Add a documentation of LED Flash class specific sysfs attributes. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Signed-off-by: Bryan Wu --- .../ABI/testing/sysfs-class-led-flash | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-led-flash diff --git a/Documentation/ABI/testing/sysfs-class-led-flash b/Documentation/ABI/testing/sysfs-class-led-flash new file mode 100644 index 000000000000..220a0270b47b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-led-flash @@ -0,0 +1,80 @@ +What: /sys/class/leds//flash_brightness +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Set the brightness of this LED in the flash strobe mode, in + microamperes. The file is created only for the flash LED devices + that support setting flash brightness. + + The value is between 0 and + /sys/class/leds//max_flash_brightness. + +What: /sys/class/leds//max_flash_brightness +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Maximum brightness level for this LED in the flash strobe mode, + in microamperes. + +What: /sys/class/leds//flash_timeout +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Hardware timeout for flash, in microseconds. The flash strobe + is stopped after this period of time has passed from the start + of the strobe. The file is created only for the flash LED + devices that support setting flash timeout. + +What: /sys/class/leds//max_flash_timeout +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Maximum flash timeout for this LED, in microseconds. + +What: /sys/class/leds//flash_strobe +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read/write + Flash strobe state. When written with 1 it triggers flash strobe + and when written with 0 it turns the flash off. + + On read 1 means that flash is currently strobing and 0 means + that flash is off. + +What: /sys/class/leds//flash_fault +Date: March 2015 +KernelVersion: 4.0 +Contact: Jacek Anaszewski +Description: read only + Space separated list of flash faults that may have occurred. + Flash faults are re-read after strobing the flash. Possible + flash faults: + + * led-over-voltage - flash controller voltage to the flash LED + has exceeded the limit specific to the flash controller + * flash-timeout-exceeded - the flash strobe was still on when + the timeout set by the user has expired; not all flash + controllers may set this in all such conditions + * controller-over-temperature - the flash controller has + overheated + * controller-short-circuit - the short circuit protection + of the flash controller has been triggered + * led-power-supply-over-current - current in the LED power + supply has exceeded the limit specific to the flash + controller + * indicator-led-fault - the flash controller has detected + a short or open circuit condition on the indicator LED + * led-under-voltage - flash controller voltage to the flash + LED has been below the minimum limit specific to + the flash + * controller-under-voltage - the input voltage of the flash + controller is below the limit under which strobing the + flash at full current will not be possible; + the condition persists until this flag is no longer set + * led-over-temperature - the temperature of the LED has exceeded + its allowed upper limit -- GitLab From f6ad395bad57dcd15c6423715d15d91363a62ae8 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Wed, 4 Mar 2015 08:14:24 -0800 Subject: [PATCH 0285/1910] Documentation: leds: Add description of LED Flash class extension The documentation being added contains overall description of the LED Flash Class and the related sysfs attributes. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Richard Purdie Signed-off-by: Bryan Wu --- Documentation/leds/leds-class-flash.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/leds/leds-class-flash.txt diff --git a/Documentation/leds/leds-class-flash.txt b/Documentation/leds/leds-class-flash.txt new file mode 100644 index 000000000000..19bb67355424 --- /dev/null +++ b/Documentation/leds/leds-class-flash.txt @@ -0,0 +1,22 @@ + +Flash LED handling under Linux +============================== + +Some LED devices provide two modes - torch and flash. In the LED subsystem +those modes are supported by LED class (see Documentation/leds/leds-class.txt) +and LED Flash class respectively. The torch mode related features are enabled +by default and the flash ones only if a driver declares it by setting +LED_DEV_CAP_FLASH flag. + +In order to enable the support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol +must be defined in the kernel config. A LED Flash class driver must be +registered in the LED subsystem with led_classdev_flash_register function. + +Following sysfs attributes are exposed for controlling flash LED devices: +(see Documentation/ABI/testing/sysfs-class-led-flash) + - flash_brightness + - max_flash_brightness + - flash_timeout + - max_flash_timeout + - flash_strobe + - flash_fault -- GitLab From 9b2de7ff424220c731276aaef9025cdd1d4052a8 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:41 +0200 Subject: [PATCH 0286/1910] crypto: octeon - don't disable bottom half in octeon-md5 Don't disable bottom half while the crypto engine is in use, as it should be unnecessary: All kernel crypto engine usage is wrapped with crypto engine state save/restore, so if we get interrupted by softirq that uses crypto they should save and restore our context. This actually fixes an issue when running OCTEON MD5 with interrupts disabled (tcrypt mode=302). There's a WARNING because the module is trying to enable the bottom half with irqs disabled: [ 52.656610] ------------[ cut here ]------------ [ 52.661439] WARNING: CPU: 1 PID: 428 at /home/aaro/git/linux/kernel/softirq.c:150 __local_bh_enable_ip+0x9c/0xd8() [ 52.671780] Modules linked in: tcrypt(+) [...] [ 52.763539] [] warn_slowpath_common+0x94/0xd8 [ 52.769465] [] __local_bh_enable_ip+0x9c/0xd8 [ 52.775390] [] octeon_md5_final+0x12c/0x1e8 [ 52.781144] [] shash_compat_digest+0xd0/0x1b0 Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/octeon-md5.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/mips/cavium-octeon/crypto/octeon-md5.c b/arch/mips/cavium-octeon/crypto/octeon-md5.c index b909881ba6c1..3dd88450d440 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-md5.c +++ b/arch/mips/cavium-octeon/crypto/octeon-md5.c @@ -97,7 +97,6 @@ static int octeon_md5_update(struct shash_desc *desc, const u8 *data, memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, avail); - local_bh_disable(); preempt_disable(); flags = octeon_crypto_enable(&state); octeon_md5_store_hash(mctx); @@ -115,7 +114,6 @@ static int octeon_md5_update(struct shash_desc *desc, const u8 *data, octeon_md5_read_hash(mctx); octeon_crypto_disable(&state, flags); preempt_enable(); - local_bh_enable(); memcpy(mctx->block, data, len); @@ -133,7 +131,6 @@ static int octeon_md5_final(struct shash_desc *desc, u8 *out) *p++ = 0x80; - local_bh_disable(); preempt_disable(); flags = octeon_crypto_enable(&state); octeon_md5_store_hash(mctx); @@ -153,7 +150,6 @@ static int octeon_md5_final(struct shash_desc *desc, u8 *out) octeon_md5_read_hash(mctx); octeon_crypto_disable(&state, flags); preempt_enable(); - local_bh_enable(); memcpy(out, mctx->hash, sizeof(mctx->hash)); memset(mctx, 0, sizeof(*mctx)); -- GitLab From c3bc38d9fb30cca2567a4f6f0d52a12d4565c7e5 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:42 +0200 Subject: [PATCH 0287/1910] crypto: octeon - always disable preemption when using crypto engine Always disable preemption on behalf of the drivers when crypto engine is taken into use. This will simplify the usage. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/octeon-crypto.c | 4 +++- arch/mips/cavium-octeon/crypto/octeon-md5.c | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.c b/arch/mips/cavium-octeon/crypto/octeon-crypto.c index 7c82ff463b65..f66bd1adc7ff 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-crypto.c +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.c @@ -17,7 +17,7 @@ * crypto operations in calls to octeon_crypto_enable/disable in order to make * sure the state of COP2 isn't corrupted if userspace is also performing * hardware crypto operations. Allocate the state parameter on the stack. - * Preemption must be disabled to prevent context switches. + * Returns with preemption disabled. * * @state: Pointer to state structure to store current COP2 state in. * @@ -28,6 +28,7 @@ unsigned long octeon_crypto_enable(struct octeon_cop2_state *state) int status; unsigned long flags; + preempt_disable(); local_irq_save(flags); status = read_c0_status(); write_c0_status(status | ST0_CU2); @@ -62,5 +63,6 @@ void octeon_crypto_disable(struct octeon_cop2_state *state, else write_c0_status(read_c0_status() & ~ST0_CU2); local_irq_restore(flags); + preempt_enable(); } EXPORT_SYMBOL_GPL(octeon_crypto_disable); diff --git a/arch/mips/cavium-octeon/crypto/octeon-md5.c b/arch/mips/cavium-octeon/crypto/octeon-md5.c index 3dd88450d440..12dccdb38286 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-md5.c +++ b/arch/mips/cavium-octeon/crypto/octeon-md5.c @@ -97,7 +97,6 @@ static int octeon_md5_update(struct shash_desc *desc, const u8 *data, memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, avail); - preempt_disable(); flags = octeon_crypto_enable(&state); octeon_md5_store_hash(mctx); @@ -113,7 +112,6 @@ static int octeon_md5_update(struct shash_desc *desc, const u8 *data, octeon_md5_read_hash(mctx); octeon_crypto_disable(&state, flags); - preempt_enable(); memcpy(mctx->block, data, len); @@ -131,7 +129,6 @@ static int octeon_md5_final(struct shash_desc *desc, u8 *out) *p++ = 0x80; - preempt_disable(); flags = octeon_crypto_enable(&state); octeon_md5_store_hash(mctx); @@ -149,7 +146,6 @@ static int octeon_md5_final(struct shash_desc *desc, u8 *out) octeon_md5_read_hash(mctx); octeon_crypto_disable(&state, flags); - preempt_enable(); memcpy(out, mctx->hash, sizeof(mctx->hash)); memset(mctx, 0, sizeof(*mctx)); -- GitLab From da3cd5d7a7031a4a9e0b3f84732620c9db8bc65a Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:43 +0200 Subject: [PATCH 0288/1910] crypto: octeon - add instruction definitions for SHA1/256/512 Add instruction definitions for SHA1/256/512. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- .../mips/cavium-octeon/crypto/octeon-crypto.h | 83 ++++++++++++++++++- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.h b/arch/mips/cavium-octeon/crypto/octeon-crypto.h index e2a4aece9c24..355072535110 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-crypto.h +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.h @@ -5,7 +5,8 @@ * * Copyright (C) 2012-2013 Cavium Inc., All Rights Reserved. * - * MD5 instruction definitions added by Aaro Koskinen . + * MD5/SHA1/SHA256/SHA512 instruction definitions added by + * Aaro Koskinen . * */ #ifndef __LINUX_OCTEON_CRYPTO_H @@ -21,11 +22,11 @@ extern void octeon_crypto_disable(struct octeon_cop2_state *state, unsigned long flags); /* - * Macros needed to implement MD5: + * Macros needed to implement MD5/SHA1/SHA256: */ /* - * The index can be 0-1. + * The index can be 0-1 (MD5) or 0-2 (SHA1), 0-3 (SHA256). */ #define write_octeon_64bit_hash_dword(value, index) \ do { \ @@ -36,7 +37,7 @@ do { \ } while (0) /* - * The index can be 0-1. + * The index can be 0-1 (MD5) or 0-2 (SHA1), 0-3 (SHA256). */ #define read_octeon_64bit_hash_dword(index) \ ({ \ @@ -72,4 +73,78 @@ do { \ : [rt] "d" (value)); \ } while (0) +/* + * The value is the final block dword (64-bit). + */ +#define octeon_sha1_start(value) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x4057" \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * The value is the final block dword (64-bit). + */ +#define octeon_sha256_start(value) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x404f" \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * Macros needed to implement SHA512: + */ + +/* + * The index can be 0-7. + */ +#define write_octeon_64bit_hash_sha512(value, index) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x0250+" STR(index) \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * The index can be 0-7. + */ +#define read_octeon_64bit_hash_sha512(index) \ +({ \ + u64 __value; \ + \ + __asm__ __volatile__ ( \ + "dmfc2 %[rt],0x0250+" STR(index) \ + : [rt] "=d" (__value) \ + : ); \ + \ + __value; \ +}) + +/* + * The index can be 0-14. + */ +#define write_octeon_64bit_block_sha512(value, index) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x0240+" STR(index) \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * The value is the final block word (64-bit). + */ +#define octeon_sha512_start(value) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x424f" \ + : \ + : [rt] "d" (value)); \ +} while (0) + #endif /* __LINUX_OCTEON_CRYPTO_H */ -- GitLab From 82be2dcfa6a1eebe0fc608296547ec80b55d512d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:44 +0200 Subject: [PATCH 0289/1910] crypto: octeon - add SHA1 module Add OCTEON SHA1 module. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/Makefile | 3 +- arch/mips/cavium-octeon/crypto/octeon-sha1.c | 241 +++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 arch/mips/cavium-octeon/crypto/octeon-sha1.c diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile index a74f76d85a2f..3f671d60a3d9 100644 --- a/arch/mips/cavium-octeon/crypto/Makefile +++ b/arch/mips/cavium-octeon/crypto/Makefile @@ -4,4 +4,5 @@ obj-y += octeon-crypto.o -obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o +obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o +obj-$(CONFIG_CRYPTO_SHA1_OCTEON) += octeon-sha1.o diff --git a/arch/mips/cavium-octeon/crypto/octeon-sha1.c b/arch/mips/cavium-octeon/crypto/octeon-sha1.c new file mode 100644 index 000000000000..2b74b5b67cae --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-sha1.c @@ -0,0 +1,241 @@ +/* + * Cryptographic API. + * + * SHA1 Secure Hash Algorithm. + * + * Adapted for OCTEON by Aaro Koskinen . + * + * Based on crypto/sha1_generic.c, which is: + * + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald + * Copyright (c) Jean-Francois Dive + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "octeon-crypto.h" + +/* + * We pass everything as 64-bit. OCTEON can handle misaligned data. + */ + +static void octeon_sha1_store_hash(struct sha1_state *sctx) +{ + u64 *hash = (u64 *)sctx->state; + union { + u32 word[2]; + u64 dword; + } hash_tail = { { sctx->state[4], } }; + + write_octeon_64bit_hash_dword(hash[0], 0); + write_octeon_64bit_hash_dword(hash[1], 1); + write_octeon_64bit_hash_dword(hash_tail.dword, 2); + memzero_explicit(&hash_tail.word[0], sizeof(hash_tail.word[0])); +} + +static void octeon_sha1_read_hash(struct sha1_state *sctx) +{ + u64 *hash = (u64 *)sctx->state; + union { + u32 word[2]; + u64 dword; + } hash_tail; + + hash[0] = read_octeon_64bit_hash_dword(0); + hash[1] = read_octeon_64bit_hash_dword(1); + hash_tail.dword = read_octeon_64bit_hash_dword(2); + sctx->state[4] = hash_tail.word[0]; + memzero_explicit(&hash_tail.dword, sizeof(hash_tail.dword)); +} + +static void octeon_sha1_transform(const void *_block) +{ + const u64 *block = _block; + + write_octeon_64bit_block_dword(block[0], 0); + write_octeon_64bit_block_dword(block[1], 1); + write_octeon_64bit_block_dword(block[2], 2); + write_octeon_64bit_block_dword(block[3], 3); + write_octeon_64bit_block_dword(block[4], 4); + write_octeon_64bit_block_dword(block[5], 5); + write_octeon_64bit_block_dword(block[6], 6); + octeon_sha1_start(block[7]); +} + +static int octeon_sha1_init(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA1_H0; + sctx->state[1] = SHA1_H1; + sctx->state[2] = SHA1_H2; + sctx->state[3] = SHA1_H3; + sctx->state[4] = SHA1_H4; + sctx->count = 0; + + return 0; +} + +static void __octeon_sha1_update(struct sha1_state *sctx, const u8 *data, + unsigned int len) +{ + unsigned int partial; + unsigned int done; + const u8 *src; + + partial = sctx->count % SHA1_BLOCK_SIZE; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) >= SHA1_BLOCK_SIZE) { + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, + done + SHA1_BLOCK_SIZE); + src = sctx->buffer; + } + + do { + octeon_sha1_transform(src); + done += SHA1_BLOCK_SIZE; + src = data + done; + } while (done + SHA1_BLOCK_SIZE <= len); + + partial = 0; + } + memcpy(sctx->buffer + partial, src, len - done); +} + +static int octeon_sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + struct octeon_cop2_state state; + unsigned long flags; + + /* + * Small updates never reach the crypto engine, so the generic sha1 is + * faster because of the heavyweight octeon_crypto_enable() / + * octeon_crypto_disable(). + */ + if ((sctx->count % SHA1_BLOCK_SIZE) + len < SHA1_BLOCK_SIZE) + return crypto_sha1_update(desc, data, len); + + flags = octeon_crypto_enable(&state); + octeon_sha1_store_hash(sctx); + + __octeon_sha1_update(sctx, data, len); + + octeon_sha1_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + return 0; +} + +static int octeon_sha1_final(struct shash_desc *desc, u8 *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + static const u8 padding[64] = { 0x80, }; + struct octeon_cop2_state state; + __be32 *dst = (__be32 *)out; + unsigned int pad_len; + unsigned long flags; + unsigned int index; + __be64 bits; + int i; + + /* Save number of bits. */ + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64. */ + index = sctx->count & 0x3f; + pad_len = (index < 56) ? (56 - index) : ((64+56) - index); + + flags = octeon_crypto_enable(&state); + octeon_sha1_store_hash(sctx); + + __octeon_sha1_update(sctx, padding, pad_len); + + /* Append length (before padding). */ + __octeon_sha1_update(sctx, (const u8 *)&bits, sizeof(bits)); + + octeon_sha1_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); + + return 0; +} + +static int octeon_sha1_export(struct shash_desc *desc, void *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int octeon_sha1_import(struct shash_desc *desc, const void *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg octeon_sha1_alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = octeon_sha1_init, + .update = octeon_sha1_update, + .final = octeon_sha1_final, + .export = octeon_sha1_export, + .import = octeon_sha1_import, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name= "octeon-sha1", + .cra_priority = OCTEON_CR_OPCODE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init octeon_sha1_mod_init(void) +{ + if (!octeon_has_crypto()) + return -ENOTSUPP; + return crypto_register_shash(&octeon_sha1_alg); +} + +static void __exit octeon_sha1_mod_fini(void) +{ + crypto_unregister_shash(&octeon_sha1_alg); +} + +module_init(octeon_sha1_mod_init); +module_exit(octeon_sha1_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (OCTEON)"); +MODULE_AUTHOR("Aaro Koskinen "); -- GitLab From c3d0def6200158cfdd280146da0109c264aede49 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:45 +0200 Subject: [PATCH 0290/1910] crypto: octeon - add SHA256 module Add OCTEON SHA256 module. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/Makefile | 1 + .../mips/cavium-octeon/crypto/octeon-sha256.c | 280 ++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 arch/mips/cavium-octeon/crypto/octeon-sha256.c diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile index 3f671d60a3d9..47806a5c5d71 100644 --- a/arch/mips/cavium-octeon/crypto/Makefile +++ b/arch/mips/cavium-octeon/crypto/Makefile @@ -6,3 +6,4 @@ obj-y += octeon-crypto.o obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o obj-$(CONFIG_CRYPTO_SHA1_OCTEON) += octeon-sha1.o +obj-$(CONFIG_CRYPTO_SHA256_OCTEON) += octeon-sha256.o diff --git a/arch/mips/cavium-octeon/crypto/octeon-sha256.c b/arch/mips/cavium-octeon/crypto/octeon-sha256.c new file mode 100644 index 000000000000..97e96fead08a --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-sha256.c @@ -0,0 +1,280 @@ +/* + * Cryptographic API. + * + * SHA-224 and SHA-256 Secure Hash Algorithm. + * + * Adapted for OCTEON by Aaro Koskinen . + * + * Based on crypto/sha256_generic.c, which is: + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * SHA224 Support Copyright 2007 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "octeon-crypto.h" + +/* + * We pass everything as 64-bit. OCTEON can handle misaligned data. + */ + +static void octeon_sha256_store_hash(struct sha256_state *sctx) +{ + u64 *hash = (u64 *)sctx->state; + + write_octeon_64bit_hash_dword(hash[0], 0); + write_octeon_64bit_hash_dword(hash[1], 1); + write_octeon_64bit_hash_dword(hash[2], 2); + write_octeon_64bit_hash_dword(hash[3], 3); +} + +static void octeon_sha256_read_hash(struct sha256_state *sctx) +{ + u64 *hash = (u64 *)sctx->state; + + hash[0] = read_octeon_64bit_hash_dword(0); + hash[1] = read_octeon_64bit_hash_dword(1); + hash[2] = read_octeon_64bit_hash_dword(2); + hash[3] = read_octeon_64bit_hash_dword(3); +} + +static void octeon_sha256_transform(const void *_block) +{ + const u64 *block = _block; + + write_octeon_64bit_block_dword(block[0], 0); + write_octeon_64bit_block_dword(block[1], 1); + write_octeon_64bit_block_dword(block[2], 2); + write_octeon_64bit_block_dword(block[3], 3); + write_octeon_64bit_block_dword(block[4], 4); + write_octeon_64bit_block_dword(block[5], 5); + write_octeon_64bit_block_dword(block[6], 6); + octeon_sha256_start(block[7]); +} + +static int octeon_sha224_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA224_H0; + sctx->state[1] = SHA224_H1; + sctx->state[2] = SHA224_H2; + sctx->state[3] = SHA224_H3; + sctx->state[4] = SHA224_H4; + sctx->state[5] = SHA224_H5; + sctx->state[6] = SHA224_H6; + sctx->state[7] = SHA224_H7; + sctx->count = 0; + + return 0; +} + +static int octeon_sha256_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; + sctx->count = 0; + + return 0; +} + +static void __octeon_sha256_update(struct sha256_state *sctx, const u8 *data, + unsigned int len) +{ + unsigned int partial; + unsigned int done; + const u8 *src; + + partial = sctx->count % SHA256_BLOCK_SIZE; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) >= SHA256_BLOCK_SIZE) { + if (partial) { + done = -partial; + memcpy(sctx->buf + partial, data, + done + SHA256_BLOCK_SIZE); + src = sctx->buf; + } + + do { + octeon_sha256_transform(src); + done += SHA256_BLOCK_SIZE; + src = data + done; + } while (done + SHA256_BLOCK_SIZE <= len); + + partial = 0; + } + memcpy(sctx->buf + partial, src, len - done); +} + +static int octeon_sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + struct octeon_cop2_state state; + unsigned long flags; + + /* + * Small updates never reach the crypto engine, so the generic sha256 is + * faster because of the heavyweight octeon_crypto_enable() / + * octeon_crypto_disable(). + */ + if ((sctx->count % SHA256_BLOCK_SIZE) + len < SHA256_BLOCK_SIZE) + return crypto_sha256_update(desc, data, len); + + flags = octeon_crypto_enable(&state); + octeon_sha256_store_hash(sctx); + + __octeon_sha256_update(sctx, data, len); + + octeon_sha256_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + return 0; +} + +static int octeon_sha256_final(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + static const u8 padding[64] = { 0x80, }; + struct octeon_cop2_state state; + __be32 *dst = (__be32 *)out; + unsigned int pad_len; + unsigned long flags; + unsigned int index; + __be64 bits; + int i; + + /* Save number of bits. */ + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64. */ + index = sctx->count & 0x3f; + pad_len = (index < 56) ? (56 - index) : ((64+56) - index); + + flags = octeon_crypto_enable(&state); + octeon_sha256_store_hash(sctx); + + __octeon_sha256_update(sctx, padding, pad_len); + + /* Append length (before padding). */ + __octeon_sha256_update(sctx, (const u8 *)&bits, sizeof(bits)); + + octeon_sha256_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + /* Store state in digest */ + for (i = 0; i < 8; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); + + return 0; +} + +static int octeon_sha224_final(struct shash_desc *desc, u8 *hash) +{ + u8 D[SHA256_DIGEST_SIZE]; + + octeon_sha256_final(desc, D); + + memcpy(hash, D, SHA224_DIGEST_SIZE); + memzero_explicit(D, SHA256_DIGEST_SIZE); + + return 0; +} + +static int octeon_sha256_export(struct shash_desc *desc, void *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int octeon_sha256_import(struct shash_desc *desc, const void *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg octeon_sha256_algs[2] = { { + .digestsize = SHA256_DIGEST_SIZE, + .init = octeon_sha256_init, + .update = octeon_sha256_update, + .final = octeon_sha256_final, + .export = octeon_sha256_export, + .import = octeon_sha256_import, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256", + .cra_driver_name= "octeon-sha256", + .cra_priority = OCTEON_CR_OPCODE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}, { + .digestsize = SHA224_DIGEST_SIZE, + .init = octeon_sha224_init, + .update = octeon_sha256_update, + .final = octeon_sha224_final, + .descsize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha224", + .cra_driver_name= "octeon-sha224", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} }; + +static int __init octeon_sha256_mod_init(void) +{ + if (!octeon_has_crypto()) + return -ENOTSUPP; + return crypto_register_shashes(octeon_sha256_algs, + ARRAY_SIZE(octeon_sha256_algs)); +} + +static void __exit octeon_sha256_mod_fini(void) +{ + crypto_unregister_shashes(octeon_sha256_algs, + ARRAY_SIZE(octeon_sha256_algs)); +} + +module_init(octeon_sha256_mod_init); +module_exit(octeon_sha256_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm (OCTEON)"); +MODULE_AUTHOR("Aaro Koskinen "); -- GitLab From fbaa4dfd51a0bfec1e03d4f887c250993f9dc18d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:46 +0200 Subject: [PATCH 0291/1910] crypto: octeon - add SHA512 module Add OCTEON SHA512 module. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/Makefile | 1 + .../mips/cavium-octeon/crypto/octeon-sha512.c | 277 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 arch/mips/cavium-octeon/crypto/octeon-sha512.c diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile index 47806a5c5d71..f7aa9d5d3b87 100644 --- a/arch/mips/cavium-octeon/crypto/Makefile +++ b/arch/mips/cavium-octeon/crypto/Makefile @@ -7,3 +7,4 @@ obj-y += octeon-crypto.o obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o obj-$(CONFIG_CRYPTO_SHA1_OCTEON) += octeon-sha1.o obj-$(CONFIG_CRYPTO_SHA256_OCTEON) += octeon-sha256.o +obj-$(CONFIG_CRYPTO_SHA512_OCTEON) += octeon-sha512.o diff --git a/arch/mips/cavium-octeon/crypto/octeon-sha512.c b/arch/mips/cavium-octeon/crypto/octeon-sha512.c new file mode 100644 index 000000000000..d5fb3c6f22ae --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-sha512.c @@ -0,0 +1,277 @@ +/* + * Cryptographic API. + * + * SHA-512 and SHA-384 Secure Hash Algorithm. + * + * Adapted for OCTEON by Aaro Koskinen . + * + * Based on crypto/sha512_generic.c, which is: + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2003 Kyle McMartin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "octeon-crypto.h" + +/* + * We pass everything as 64-bit. OCTEON can handle misaligned data. + */ + +static void octeon_sha512_store_hash(struct sha512_state *sctx) +{ + write_octeon_64bit_hash_sha512(sctx->state[0], 0); + write_octeon_64bit_hash_sha512(sctx->state[1], 1); + write_octeon_64bit_hash_sha512(sctx->state[2], 2); + write_octeon_64bit_hash_sha512(sctx->state[3], 3); + write_octeon_64bit_hash_sha512(sctx->state[4], 4); + write_octeon_64bit_hash_sha512(sctx->state[5], 5); + write_octeon_64bit_hash_sha512(sctx->state[6], 6); + write_octeon_64bit_hash_sha512(sctx->state[7], 7); +} + +static void octeon_sha512_read_hash(struct sha512_state *sctx) +{ + sctx->state[0] = read_octeon_64bit_hash_sha512(0); + sctx->state[1] = read_octeon_64bit_hash_sha512(1); + sctx->state[2] = read_octeon_64bit_hash_sha512(2); + sctx->state[3] = read_octeon_64bit_hash_sha512(3); + sctx->state[4] = read_octeon_64bit_hash_sha512(4); + sctx->state[5] = read_octeon_64bit_hash_sha512(5); + sctx->state[6] = read_octeon_64bit_hash_sha512(6); + sctx->state[7] = read_octeon_64bit_hash_sha512(7); +} + +static void octeon_sha512_transform(const void *_block) +{ + const u64 *block = _block; + + write_octeon_64bit_block_sha512(block[0], 0); + write_octeon_64bit_block_sha512(block[1], 1); + write_octeon_64bit_block_sha512(block[2], 2); + write_octeon_64bit_block_sha512(block[3], 3); + write_octeon_64bit_block_sha512(block[4], 4); + write_octeon_64bit_block_sha512(block[5], 5); + write_octeon_64bit_block_sha512(block[6], 6); + write_octeon_64bit_block_sha512(block[7], 7); + write_octeon_64bit_block_sha512(block[8], 8); + write_octeon_64bit_block_sha512(block[9], 9); + write_octeon_64bit_block_sha512(block[10], 10); + write_octeon_64bit_block_sha512(block[11], 11); + write_octeon_64bit_block_sha512(block[12], 12); + write_octeon_64bit_block_sha512(block[13], 13); + write_octeon_64bit_block_sha512(block[14], 14); + octeon_sha512_start(block[15]); +} + +static int octeon_sha512_init(struct shash_desc *desc) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA512_H0; + sctx->state[1] = SHA512_H1; + sctx->state[2] = SHA512_H2; + sctx->state[3] = SHA512_H3; + sctx->state[4] = SHA512_H4; + sctx->state[5] = SHA512_H5; + sctx->state[6] = SHA512_H6; + sctx->state[7] = SHA512_H7; + sctx->count[0] = sctx->count[1] = 0; + + return 0; +} + +static int octeon_sha384_init(struct shash_desc *desc) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + + sctx->state[0] = SHA384_H0; + sctx->state[1] = SHA384_H1; + sctx->state[2] = SHA384_H2; + sctx->state[3] = SHA384_H3; + sctx->state[4] = SHA384_H4; + sctx->state[5] = SHA384_H5; + sctx->state[6] = SHA384_H6; + sctx->state[7] = SHA384_H7; + sctx->count[0] = sctx->count[1] = 0; + + return 0; +} + +static void __octeon_sha512_update(struct sha512_state *sctx, const u8 *data, + unsigned int len) +{ + unsigned int part_len; + unsigned int index; + unsigned int i; + + /* Compute number of bytes mod 128. */ + index = sctx->count[0] % SHA512_BLOCK_SIZE; + + /* Update number of bytes. */ + if ((sctx->count[0] += len) < len) + sctx->count[1]++; + + part_len = SHA512_BLOCK_SIZE - index; + + /* Transform as many times as possible. */ + if (len >= part_len) { + memcpy(&sctx->buf[index], data, part_len); + octeon_sha512_transform(sctx->buf); + + for (i = part_len; i + SHA512_BLOCK_SIZE <= len; + i += SHA512_BLOCK_SIZE) + octeon_sha512_transform(&data[i]); + + index = 0; + } else { + i = 0; + } + + /* Buffer remaining input. */ + memcpy(&sctx->buf[index], &data[i], len - i); +} + +static int octeon_sha512_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + struct octeon_cop2_state state; + unsigned long flags; + + /* + * Small updates never reach the crypto engine, so the generic sha512 is + * faster because of the heavyweight octeon_crypto_enable() / + * octeon_crypto_disable(). + */ + if ((sctx->count[0] % SHA512_BLOCK_SIZE) + len < SHA512_BLOCK_SIZE) + return crypto_sha512_update(desc, data, len); + + flags = octeon_crypto_enable(&state); + octeon_sha512_store_hash(sctx); + + __octeon_sha512_update(sctx, data, len); + + octeon_sha512_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + return 0; +} + +static int octeon_sha512_final(struct shash_desc *desc, u8 *hash) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); + static u8 padding[128] = { 0x80, }; + struct octeon_cop2_state state; + __be64 *dst = (__be64 *)hash; + unsigned int pad_len; + unsigned long flags; + unsigned int index; + __be64 bits[2]; + int i; + + /* Save number of bits. */ + bits[1] = cpu_to_be64(sctx->count[0] << 3); + bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); + + /* Pad out to 112 mod 128. */ + index = sctx->count[0] & 0x7f; + pad_len = (index < 112) ? (112 - index) : ((128+112) - index); + + flags = octeon_crypto_enable(&state); + octeon_sha512_store_hash(sctx); + + __octeon_sha512_update(sctx, padding, pad_len); + + /* Append length (before padding). */ + __octeon_sha512_update(sctx, (const u8 *)bits, sizeof(bits)); + + octeon_sha512_read_hash(sctx); + octeon_crypto_disable(&state, flags); + + /* Store state in digest. */ + for (i = 0; i < 8; i++) + dst[i] = cpu_to_be64(sctx->state[i]); + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(struct sha512_state)); + + return 0; +} + +static int octeon_sha384_final(struct shash_desc *desc, u8 *hash) +{ + u8 D[64]; + + octeon_sha512_final(desc, D); + + memcpy(hash, D, 48); + memzero_explicit(D, 64); + + return 0; +} + +static struct shash_alg octeon_sha512_algs[2] = { { + .digestsize = SHA512_DIGEST_SIZE, + .init = octeon_sha512_init, + .update = octeon_sha512_update, + .final = octeon_sha512_final, + .descsize = sizeof(struct sha512_state), + .base = { + .cra_name = "sha512", + .cra_driver_name= "octeon-sha512", + .cra_priority = OCTEON_CR_OPCODE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}, { + .digestsize = SHA384_DIGEST_SIZE, + .init = octeon_sha384_init, + .update = octeon_sha512_update, + .final = octeon_sha384_final, + .descsize = sizeof(struct sha512_state), + .base = { + .cra_name = "sha384", + .cra_driver_name= "octeon-sha384", + .cra_priority = OCTEON_CR_OPCODE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA384_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} }; + +static int __init octeon_sha512_mod_init(void) +{ + if (!octeon_has_crypto()) + return -ENOTSUPP; + return crypto_register_shashes(octeon_sha512_algs, + ARRAY_SIZE(octeon_sha512_algs)); +} + +static void __exit octeon_sha512_mod_fini(void) +{ + crypto_unregister_shashes(octeon_sha512_algs, + ARRAY_SIZE(octeon_sha512_algs)); +} + +module_init(octeon_sha512_mod_init); +module_exit(octeon_sha512_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms (OCTEON)"); +MODULE_AUTHOR("Aaro Koskinen "); -- GitLab From efdb6f6edb526f160b8db1670b93a07180ac8306 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 8 Mar 2015 22:07:47 +0200 Subject: [PATCH 0292/1910] crypto: octeon - enable OCTEON SHA1/256/512 module selection Enable user to select OCTEON SHA1/256/512 modules. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- crypto/Kconfig | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crypto/Kconfig b/crypto/Kconfig index 6918aff74f4d..1afb0f66ad43 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -554,6 +554,15 @@ config CRYPTO_SHA512_SSSE3 Extensions version 1 (AVX1), or Advanced Vector Extensions version 2 (AVX2) instructions, when available. +config CRYPTO_SHA1_OCTEON + tristate "SHA1 digest algorithm (OCTEON)" + depends on CPU_CAVIUM_OCTEON + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using OCTEON crypto instructions, when available. + config CRYPTO_SHA1_SPARC64 tristate "SHA1 digest algorithm (SPARC64)" depends on SPARC64 @@ -634,6 +643,15 @@ config CRYPTO_SHA256_PPC_SPE SHA224 and SHA256 secure hash standard (DFIPS 180-2) implemented using powerpc SPE SIMD instruction set. +config CRYPTO_SHA256_OCTEON + tristate "SHA224 and SHA256 digest algorithm (OCTEON)" + depends on CPU_CAVIUM_OCTEON + select CRYPTO_SHA256 + select CRYPTO_HASH + help + SHA-256 secure hash standard (DFIPS 180-2) implemented + using OCTEON crypto instructions, when available. + config CRYPTO_SHA256_SPARC64 tristate "SHA224 and SHA256 digest algorithm (SPARC64)" depends on SPARC64 @@ -655,6 +673,15 @@ config CRYPTO_SHA512 This code also includes SHA-384, a 384 bit hash with 192 bits of security against collision attacks. +config CRYPTO_SHA512_OCTEON + tristate "SHA384 and SHA512 digest algorithms (OCTEON)" + depends on CPU_CAVIUM_OCTEON + select CRYPTO_SHA512 + select CRYPTO_HASH + help + SHA-512 secure hash standard (DFIPS 180-2) implemented + using OCTEON crypto instructions, when available. + config CRYPTO_SHA512_SPARC64 tristate "SHA384 and SHA512 digest algorithm (SPARC64)" depends on SPARC64 -- GitLab From ce991981311e0ae258982b600564226ad6cb24ea Mon Sep 17 00:00:00 2001 From: Yannick Guerrini Date: Mon, 9 Mar 2015 22:13:03 +0100 Subject: [PATCH 0293/1910] ALSA: firewire: Fix trivial typos in comments Change 'propper' to 'proper' Change 'paramters' to 'parameters' Change 'SYT_INTEVAL' to 'SYT_INTERVAL' Change 'aligh'/'alighed' to 'align'/'aligned' Signed-off-by: Yannick Guerrini Signed-off-by: Takashi Iwai --- sound/firewire/amdtp.c | 8 ++++---- sound/firewire/fireworks/fireworks_transaction.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 5cc356db5351..e061355f535f 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -166,10 +166,10 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, * One AMDTP packet can include some frames. In blocking mode, the * number equals to SYT_INTERVAL. So the number is 8, 16 or 32, * depending on its sampling rate. For accurate period interrupt, it's - * preferrable to aligh period/buffer sizes to current SYT_INTERVAL. + * preferrable to align period/buffer sizes to current SYT_INTERVAL. * - * TODO: These constraints can be improved with propper rules. - * Currently apply LCM of SYT_INTEVALs. + * TODO: These constraints can be improved with proper rules. + * Currently apply LCM of SYT_INTERVALs. */ err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); @@ -270,7 +270,7 @@ static void amdtp_read_s32(struct amdtp_stream *s, * @s: the AMDTP stream to configure * @format: the format of the ALSA PCM device * - * The sample format must be set after the other paramters (rate/PCM channels/ + * The sample format must be set after the other parameters (rate/PCM channels/ * MIDI) and before the stream is started, and must not be changed while the * stream is running. */ diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c index 2a85e4209f0b..f550808d1784 100644 --- a/sound/firewire/fireworks/fireworks_transaction.c +++ b/sound/firewire/fireworks/fireworks_transaction.c @@ -13,7 +13,7 @@ * * Transaction substance: * At first, 6 data exist. Following to the data, parameters for each command - * exist. All of the parameters are 32 bit alighed to big endian. + * exist. All of the parameters are 32 bit aligned to big endian. * data[0]: Length of transaction substance * data[1]: Transaction version * data[2]: Sequence number. This is incremented by the device -- GitLab From 4ed56666b7fc98c750a23b5263350b75e742b534 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 10 Mar 2015 22:13:30 +0900 Subject: [PATCH 0294/1910] ALSA: core: use precomputed table to check userspace control params The parameters can be decided in compile time. This commit adds precomputed table to reduce calculating time. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 60 +++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 35324a8e83c8..0b85cbc27e4d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1161,6 +1161,23 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) static int snd_ctl_elem_add(struct snd_ctl_file *file, struct snd_ctl_elem_info *info, int replace) { + /* The capacity of struct snd_ctl_elem_value.value.*/ + static const unsigned int value_sizes[] = { + [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = sizeof(long), + [SNDRV_CTL_ELEM_TYPE_INTEGER] = sizeof(long), + [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int), + [SNDRV_CTL_ELEM_TYPE_BYTES] = sizeof(unsigned char), + [SNDRV_CTL_ELEM_TYPE_IEC958] = sizeof(struct snd_aes_iec958), + [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long), + }; + static const unsigned int max_value_counts[] = { + [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = 128, + [SNDRV_CTL_ELEM_TYPE_INTEGER] = 128, + [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128, + [SNDRV_CTL_ELEM_TYPE_BYTES] = 512, + [SNDRV_CTL_ELEM_TYPE_IEC958] = 1, + [SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64, + }; struct snd_card *card = file->card; struct snd_kcontrol kctl, *_kctl; unsigned int access; @@ -1168,8 +1185,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, struct user_element *ue; int idx, err; - if (info->count < 1) - return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| SNDRV_CTL_ELEM_ACCESS_INACTIVE| @@ -1201,37 +1216,18 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl.tlv.c = snd_ctl_elem_user_tlv; access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; } - switch (info->type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - private_size = sizeof(long); - if (info->count > 128) - return -EINVAL; - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - private_size = sizeof(long long); - if (info->count > 64) - return -EINVAL; - break; - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - private_size = sizeof(unsigned int); - if (info->count > 128 || info->value.enumerated.items == 0) - return -EINVAL; - break; - case SNDRV_CTL_ELEM_TYPE_BYTES: - private_size = sizeof(unsigned char); - if (info->count > 512) - return -EINVAL; - break; - case SNDRV_CTL_ELEM_TYPE_IEC958: - private_size = sizeof(struct snd_aes_iec958); - if (info->count != 1) - return -EINVAL; - break; - default: + + if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN || + info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) return -EINVAL; - } - private_size *= info->count; + if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && + info->value.enumerated.items == 0) + return -EINVAL; + if (info->count < 1 || + info->count > max_value_counts[info->type]) + return -EINVAL; + + private_size = value_sizes[info->type] * info->count; ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); if (ue == NULL) return -ENOMEM; -- GitLab From 2225e79b9b0370bc179f44756bee809b5e7b4d06 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 10 Mar 2015 22:13:31 +0900 Subject: [PATCH 0295/1910] ALSA: core: reduce stack usage related to snd_ctl_new() The callers of snd_ctl_new() need to have 'struct snd_kcontrol' data, and pass the data as template. Then, the function allocates the structure data again and copy from the template. This is a waste of resources. Especially, the callers use large stack for the template. This commit removes a need of template for the function, thus, changes the prototype of snd_ctl_new(). Furthermore, this commit changes the code of callers, snd_ctl_new1() and snd_ctl_elem_add() for better shape. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 213 ++++++++++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 83 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 0b85cbc27e4d..e1d8e0c816f0 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -192,36 +192,43 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, EXPORT_SYMBOL(snd_ctl_notify); /** - * snd_ctl_new - create a control instance from the template - * @control: the control template - * @access: the default control access + * snd_ctl_new - create a new control instance with some elements + * @kctl: the pointer to store new control instance + * @count: the number of elements in this control + * @access: the default access flags for elements in this control + * @file: given when locking these elements * - * Allocates a new struct snd_kcontrol instance and copies the given template - * to the new instance. It does not copy volatile data (access). + * Allocates a memory object for a new control instance. The instance has + * elements as many as the given number (@count). Each element has given + * access permissions (@access). Each element is locked when @file is given. * - * Return: The pointer of the new instance, or %NULL on failure. + * Return: 0 on success, error code on failure */ -static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, - unsigned int access) +static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count, + unsigned int access, struct snd_ctl_file *file) { - struct snd_kcontrol *kctl; + unsigned int size; unsigned int idx; - if (snd_BUG_ON(!control || !control->count)) - return NULL; + if (count == 0 || count > MAX_CONTROL_COUNT) + return -EINVAL; - if (control->count > MAX_CONTROL_COUNT) - return NULL; + size = sizeof(struct snd_kcontrol); + size += sizeof(struct snd_kcontrol_volatile) * count; - kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL); - if (kctl == NULL) { + *kctl = kzalloc(size, GFP_KERNEL); + if (*kctl == NULL) { pr_err("ALSA: Cannot allocate control instance\n"); - return NULL; + return -ENOMEM; } - *kctl = *control; - for (idx = 0; idx < kctl->count; idx++) - kctl->vd[idx].access = access; - return kctl; + + for (idx = 0; idx < count; idx++) { + (*kctl)->vd[idx].access = access; + (*kctl)->vd[idx].owner = file; + } + (*kctl)->count = count; + + return 0; } /** @@ -238,37 +245,53 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, void *private_data) { - struct snd_kcontrol kctl; + struct snd_kcontrol *kctl; + unsigned int count; unsigned int access; + int err; if (snd_BUG_ON(!ncontrol || !ncontrol->info)) return NULL; - memset(&kctl, 0, sizeof(kctl)); - kctl.id.iface = ncontrol->iface; - kctl.id.device = ncontrol->device; - kctl.id.subdevice = ncontrol->subdevice; + + count = ncontrol->count; + if (count == 0) + count = 1; + + access = ncontrol->access; + if (access == 0) + access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); + + err = snd_ctl_new(&kctl, count, access, NULL); + if (err < 0) + return NULL; + + /* The 'numid' member is decided when calling snd_ctl_add(). */ + kctl->id.iface = ncontrol->iface; + kctl->id.device = ncontrol->device; + kctl->id.subdevice = ncontrol->subdevice; if (ncontrol->name) { - strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)); - if (strcmp(ncontrol->name, kctl.id.name) != 0) + strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name)); + if (strcmp(ncontrol->name, kctl->id.name) != 0) pr_warn("ALSA: Control name '%s' truncated to '%s'\n", - ncontrol->name, kctl.id.name); + ncontrol->name, kctl->id.name); } - kctl.id.index = ncontrol->index; - kctl.count = ncontrol->count ? ncontrol->count : 1; - access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : - (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| - SNDRV_CTL_ELEM_ACCESS_VOLATILE| - SNDRV_CTL_ELEM_ACCESS_INACTIVE| - SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| - SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); - kctl.info = ncontrol->info; - kctl.get = ncontrol->get; - kctl.put = ncontrol->put; - kctl.tlv.p = ncontrol->tlv.p; - kctl.private_value = ncontrol->private_value; - kctl.private_data = private_data; - return snd_ctl_new(&kctl, access); + kctl->id.index = ncontrol->index; + + kctl->info = ncontrol->info; + kctl->get = ncontrol->get; + kctl->put = ncontrol->put; + kctl->tlv.p = ncontrol->tlv.p; + + kctl->private_value = ncontrol->private_value; + kctl->private_data = private_data; + + return kctl; } EXPORT_SYMBOL(snd_ctl_new1); @@ -1179,44 +1202,48 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, [SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64, }; struct snd_card *card = file->card; - struct snd_kcontrol kctl, *_kctl; + struct snd_kcontrol *kctl; + unsigned int count; unsigned int access; long private_size; struct user_element *ue; - int idx, err; - - access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : - (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| - SNDRV_CTL_ELEM_ACCESS_INACTIVE| - SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); - info->id.numid = 0; - memset(&kctl, 0, sizeof(kctl)); + int err; + /* Delete a control to replace them if needed. */ if (replace) { + info->id.numid = 0; err = snd_ctl_remove_user_ctl(file, &info->id); if (err) return err; } - if (card->user_ctl_count >= MAX_USER_CONTROLS) + /* + * The number of userspace controls are counted control by control, + * not element by element. + */ + if (card->user_ctl_count + 1 > MAX_USER_CONTROLS) return -ENOMEM; - memcpy(&kctl.id, &info->id, sizeof(info->id)); - kctl.count = info->owner ? info->owner : 1; - access |= SNDRV_CTL_ELEM_ACCESS_USER; - if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) - kctl.info = snd_ctl_elem_user_enum_info; - else - kctl.info = snd_ctl_elem_user_info; - if (access & SNDRV_CTL_ELEM_ACCESS_READ) - kctl.get = snd_ctl_elem_user_get; - if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) - kctl.put = snd_ctl_elem_user_put; - if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { - kctl.tlv.c = snd_ctl_elem_user_tlv; + /* Check the number of elements for this userspace control. */ + count = info->owner; + if (count == 0) + count = 1; + + /* Arrange access permissions if needed. */ + access = info->access; + if (access == 0) + access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE); + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; - } + access |= SNDRV_CTL_ELEM_ACCESS_USER; + /* + * Check information and calculate the size of data specific to + * this userspace control. + */ if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN || info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) return -EINVAL; @@ -1226,11 +1253,27 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1 || info->count > max_value_counts[info->type]) return -EINVAL; - private_size = value_sizes[info->type] * info->count; - ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); - if (ue == NULL) + + /* + * Keep memory object for this userspace control. After passing this + * code block, the instance should be freed by snd_ctl_free_one(). + * + * Note that these elements in this control are locked. + */ + err = snd_ctl_new(&kctl, count, access, file); + if (err < 0) + return err; + kctl->private_data = kzalloc(sizeof(struct user_element) + private_size, + GFP_KERNEL); + if (kctl->private_data == NULL) { + kfree(kctl); return -ENOMEM; + } + kctl->private_free = snd_ctl_elem_user_free; + + /* Set private data for this userspace control. */ + ue = (struct user_element *)kctl->private_data; ue->card = card; ue->info = *info; ue->info.access = 0; @@ -1239,21 +1282,25 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { err = snd_ctl_elem_init_enum_names(ue); if (err < 0) { - kfree(ue); + snd_ctl_free_one(kctl); return err; } } - kctl.private_free = snd_ctl_elem_user_free; - _kctl = snd_ctl_new(&kctl, access); - if (_kctl == NULL) { - kfree(ue->priv_data); - kfree(ue); - return -ENOMEM; - } - _kctl->private_data = ue; - for (idx = 0; idx < _kctl->count; idx++) - _kctl->vd[idx].owner = file; - err = snd_ctl_add(card, _kctl); + + /* Set callback functions. */ + if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) + kctl->info = snd_ctl_elem_user_enum_info; + else + kctl->info = snd_ctl_elem_user_info; + if (access & SNDRV_CTL_ELEM_ACCESS_READ) + kctl->get = snd_ctl_elem_user_get; + if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) + kctl->put = snd_ctl_elem_user_put; + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) + kctl->tlv.c = snd_ctl_elem_user_tlv; + + /* This function manage to free the instance on failure. */ + err = snd_ctl_add(card, kctl); if (err < 0) return err; -- GitLab From 8d98a0673f761f9b7be51a293ca9142ec0c037ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Mar 2015 15:39:55 +0100 Subject: [PATCH 0296/1910] ALSA: seq_oss: Drop superfluous error/debug messages after malloc failures The kernel memory allocators already report the errors when the requested allocation fails, thus we don't need to warn it again in each caller side. Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_init.c | 4 +--- sound/core/seq/oss/seq_oss_midi.c | 5 ++--- sound/core/seq/oss/seq_oss_readq.c | 9 ++++----- sound/core/seq/oss/seq_oss_synth.c | 6 ++---- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index b0e32e161dd1..2de3feff70d0 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -188,10 +188,8 @@ snd_seq_oss_open(struct file *file, int level) struct seq_oss_devinfo *dp; dp = kzalloc(sizeof(*dp), GFP_KERNEL); - if (!dp) { - pr_err("ALSA: seq_oss: can't malloc device info\n"); + if (!dp) return -ENOMEM; - } dp->cseq = system_client; dp->port = -1; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index e79cc44b1394..96e8395ae586 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -173,10 +173,9 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) /* * allocate midi info record */ - if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { - pr_err("ALSA: seq_oss: can't malloc midi info\n"); + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) return -ENOMEM; - } /* copy the port information */ mdev->client = pinfo->addr.client; diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c index 654d17a5023c..c080c73cea04 100644 --- a/sound/core/seq/oss/seq_oss_readq.c +++ b/sound/core/seq/oss/seq_oss_readq.c @@ -47,13 +47,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen) { struct seq_oss_readq *q; - if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) { - pr_err("ALSA: seq_oss: can't malloc read queue\n"); + q = kzalloc(sizeof(*q), GFP_KERNEL); + if (!q) return NULL; - } - if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) { - pr_err("ALSA: seq_oss: can't malloc read queue buffer\n"); + q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL); + if (!q->q) { kfree(q); return NULL; } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 835edc80f918..48e4fe1b68ab 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -106,10 +106,9 @@ snd_seq_oss_synth_probe(struct device *_dev) struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); unsigned long flags; - if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) { - pr_err("ALSA: seq_oss: can't malloc synth info\n"); + rec = kzalloc(sizeof(*rec), GFP_KERNEL); + if (!rec) return -ENOMEM; - } rec->seq_device = -1; rec->synth_type = reg->type; rec->synth_subtype = reg->subtype; @@ -249,7 +248,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) if (info->nr_voices > 0) { info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL); if (!info->ch) { - pr_err("ALSA: seq_oss: Cannot malloc voices\n"); rec->oper.close(&info->arg); module_put(rec->oper.owner); snd_use_lock_free(&rec->use_lock); -- GitLab From 24db8bbaa3fcfaf0c2faccbff5864b58088ac1f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Mar 2015 15:41:18 +0100 Subject: [PATCH 0297/1910] ALSA: seq: Drop superfluous error/debug messages after malloc failures The kernel memory allocators already report the errors when the requested allocation fails, thus we don't need to warn it again in each caller side. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_fifo.c | 4 +--- sound/core/seq/seq_memory.c | 8 ++------ sound/core/seq/seq_ports.c | 4 +--- sound/core/seq/seq_prioq.c | 4 +--- sound/core/seq/seq_queue.c | 4 +--- sound/core/seq/seq_timer.c | 4 +--- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 53a403e17c5b..1d5acbe0c08b 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -33,10 +33,8 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) struct snd_seq_fifo *f; f = kzalloc(sizeof(*f), GFP_KERNEL); - if (f == NULL) { - pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n"); + if (!f) return NULL; - } f->pool = snd_seq_pool_new(poolsize); if (f->pool == NULL) { diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index ba8e4a64e13e..801076687bb1 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -387,10 +387,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) return 0; pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); - if (pool->ptr == NULL) { - pr_debug("ALSA: seq: malloc for sequencer events failed\n"); + if (!pool->ptr) return -ENOMEM; - } /* add new cells to the free cell list */ spin_lock_irqsave(&pool->lock, flags); @@ -463,10 +461,8 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize) /* create pool block */ pool = kzalloc(sizeof(*pool), GFP_KERNEL); - if (pool == NULL) { - pr_debug("ALSA: seq: malloc failed for pool\n"); + if (!pool) return NULL; - } spin_lock_init(&pool->lock); pool->ptr = NULL; pool->free = NULL; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 46ff593f618d..55170a20ae72 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -141,10 +141,8 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, /* create a new port */ new_port = kzalloc(sizeof(*new_port), GFP_KERNEL); - if (! new_port) { - pr_debug("ALSA: seq: malloc failed for registering client port\n"); + if (!new_port) return NULL; /* failure, out of memory */ - } /* init port data */ new_port->addr.client = client->number; new_port->addr.port = -1; diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index 021b02bc9330..bc1c8488fc2a 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -59,10 +59,8 @@ struct snd_seq_prioq *snd_seq_prioq_new(void) struct snd_seq_prioq *f; f = kzalloc(sizeof(*f), GFP_KERNEL); - if (f == NULL) { - pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n"); + if (!f) return NULL; - } spin_lock_init(&f->lock); f->head = NULL; diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index aad4878cee55..a0cda38205b9 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -111,10 +111,8 @@ static struct snd_seq_queue *queue_new(int owner, int locked) struct snd_seq_queue *q; q = kzalloc(sizeof(*q), GFP_KERNEL); - if (q == NULL) { - pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n"); + if (!q) return NULL; - } spin_lock_init(&q->owner_lock); spin_lock_init(&q->check_lock); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index e73605393eee..186f1611103c 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -56,10 +56,8 @@ struct snd_seq_timer *snd_seq_timer_new(void) struct snd_seq_timer *tmr; tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); - if (tmr == NULL) { - pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n"); + if (!tmr) return NULL; - } spin_lock_init(&tmr->lock); /* reset setup to defaults */ -- GitLab From ec0e9937aaa8b0a4b0633711c4d70d622acd9a7f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Mar 2015 15:42:14 +0100 Subject: [PATCH 0298/1910] ALSA: core: Drop superfluous error/debug messages after malloc failures The kernel memory allocators already report the errors when the requested allocation fails, thus we don't need to warn it again in each caller side. Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +--- sound/core/device.c | 4 +--- sound/core/hwdep.c | 4 +--- sound/core/oss/mixer_oss.c | 4 +--- sound/core/oss/pcm_oss.c | 1 - sound/core/pcm.c | 13 +++---------- sound/core/rawmidi.c | 8 ++------ sound/core/timer.c | 4 +--- 8 files changed, 10 insertions(+), 32 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index e1d8e0c816f0..833b223a363a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -217,10 +217,8 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count, size += sizeof(struct snd_kcontrol_volatile) * count; *kctl = kzalloc(size, GFP_KERNEL); - if (*kctl == NULL) { - pr_err("ALSA: Cannot allocate control instance\n"); + if (!*kctl) return -ENOMEM; - } for (idx = 0; idx < count; idx++) { (*kctl)->vd[idx].access = access; diff --git a/sound/core/device.c b/sound/core/device.c index 41bec3075ae5..c1a845b42a8b 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -50,10 +50,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, if (snd_BUG_ON(!card || !device_data || !ops)) return -ENXIO; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(card->dev, "Cannot allocate device, type=%d\n", type); + if (!dev) return -ENOMEM; - } INIT_LIST_HEAD(&dev->list); dev->card = card; dev->type = type; diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 84244a5143cf..51692c8a39ea 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -378,10 +378,8 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, if (rhwdep) *rhwdep = NULL; hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); - if (hwdep == NULL) { - dev_err(card->dev, "hwdep: cannot allocate\n"); + if (!hwdep) return -ENOMEM; - } init_waitqueue_head(&hwdep->open_wait); mutex_init(&hwdep->open_mutex); diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 5e6349f00ecd..056f8e274851 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1212,10 +1212,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, /* not changed */ goto __unlock; tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); - if (! tbl) { - pr_err("ALSA: mixer_oss: no memory\n"); + if (!tbl) goto __unlock; - } tbl->oss_id = ch; tbl->name = kstrdup(str, GFP_KERNEL); if (! tbl->name) { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 80423a4ccab6..58550cc93f28 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -854,7 +854,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); if (!sw_params || !params || !sparams) { - pcm_dbg(substream->pcm, "No memory\n"); err = -ENOMEM; goto failure; } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index e9b87465c73d..b25bcf5b8644 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -343,11 +343,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, return; info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) { - pcm_dbg(substream->pcm, - "snd_pcm_proc_info_read: cannot malloc\n"); + if (!info) return; - } err = snd_pcm_info(substream, info); if (err < 0) { @@ -717,10 +714,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) prev = NULL; for (idx = 0, prev = NULL; idx < substream_count; idx++) { substream = kzalloc(sizeof(*substream), GFP_KERNEL); - if (substream == NULL) { - pcm_err(pcm, "Cannot allocate PCM substream\n"); + if (!substream) return -ENOMEM; - } substream->pcm = pcm; substream->pstr = pstr; substream->number = idx; @@ -774,10 +769,8 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, if (rpcm) *rpcm = NULL; pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); - if (pcm == NULL) { - dev_err(card->dev, "Cannot allocate PCM\n"); + if (!pcm) return -ENOMEM; - } pcm->card = card; pcm->device = device; pcm->internal = internal; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index b5a748596fc4..a7759846fbaa 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1429,10 +1429,8 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, for (idx = 0; idx < count; idx++) { substream = kzalloc(sizeof(*substream), GFP_KERNEL); - if (substream == NULL) { - rmidi_err(rmidi, "rawmidi: cannot allocate substream\n"); + if (!substream) return -ENOMEM; - } substream->stream = direction; substream->number = idx; substream->rmidi = rmidi; @@ -1479,10 +1477,8 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, if (rrawmidi) *rrawmidi = NULL; rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); - if (rmidi == NULL) { - dev_err(card->dev, "rawmidi: cannot allocate\n"); + if (!rmidi) return -ENOMEM; - } rmidi->card = card; rmidi->device = device; mutex_init(&rmidi->open_mutex); diff --git a/sound/core/timer.c b/sound/core/timer.c index 490b489d713d..a9a1a047c521 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -774,10 +774,8 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, if (rtimer) *rtimer = NULL; timer = kzalloc(sizeof(*timer), GFP_KERNEL); - if (timer == NULL) { - pr_err("ALSA: timer: cannot allocate\n"); + if (!timer) return -ENOMEM; - } timer->tmr_class = tid->dev_class; timer->card = card; timer->tmr_device = tid->device; -- GitLab From 8d0c38a3f2a6bb70e952f127ed817fc7a08db52c Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 10 Mar 2015 09:05:38 +0800 Subject: [PATCH 0299/1910] ASoC: Intel: move sysclk source setting to platform_clock_control for balance. A playback noise happens after suspend/resume on Braswell. The issue is due to the codec PLL and codec ASRC are not enabled correctly due to the incorrect sysclk setting after resume. This patch resets the sysclk source setting in platform clock control widget handler. Signed-off-by: Bard Liao Signed-off-by: Jin Yao Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 40 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index bc8dcacd5e6a..279df4c43de1 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -50,6 +50,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct snd_soc_dai *codec_dai; + int ret; codec_dai = cht_get_codec_dai(card); if (!codec_dai) { @@ -57,17 +58,31 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return -EIO; } - if (!SND_SOC_DAPM_EVENT_OFF(event)) - return 0; - - /* Set codec sysclk source to its internal clock because codec PLL will - * be off when idle and MCLK will also be off by ACPI when codec is - * runtime suspended. Codec needs clock for jack detection and button - * press. - */ - snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, - 0, SND_SOC_CLOCK_IN); - + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + /* set codec sysclk source to PLL */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + } else { + /* Set codec sysclk source to its internal clock because codec + * PLL will be off when idle and MCLK will also be off by ACPI + * when codec is runtime suspended. Codec needs clock for jack + * detection and button press. + */ + snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + } return 0; } @@ -77,7 +92,8 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD), + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route cht_audio_map[] = { -- GitLab From 4945f1fdc14ef090abe50d1b5682bfc1e4763c06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2015 12:50:15 +0100 Subject: [PATCH 0300/1910] ALSA: seq: Fix init order of snd_seq_device stuff When the sequencer driver is built in kernel, it may panic at boot because of the uninitialized snd_seq_bus_type. Initialize it properly via subsys_initcall() instead of module_init() to assure that the bus is registered beforehand. Reported-by: Fengguang Wu Fixes: 7c37ae5c625a ('ALSA: seq: Rewrite sequencer device binding with standard bus') Signed-off-by: Takashi Iwai --- sound/core/seq/seq_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 355b34269bd1..d99f99d61983 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -311,5 +311,5 @@ static void __exit alsa_seq_device_exit(void) bus_unregister(&snd_seq_bus_type); } -module_init(alsa_seq_device_init) +subsys_initcall(alsa_seq_device_init) module_exit(alsa_seq_device_exit) -- GitLab From 6ec6fb6f231547834925ff802deb4415f49f708e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Mar 2015 11:48:05 +0100 Subject: [PATCH 0301/1910] ASoC: rsnd: Use %pad to print dma_addr_t in rsnd_dmapp_init() sound/soc/sh/rcar/dma.c: In function 'rsnd_dmapp_init': sound/soc/sh/rcar/dma.c:341:2: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'dma_addr_t' [-Wformat=] dev_dbg(dev, "id/src/dst/chcr = %d/%x/%x/%08x\n", ^ sound/soc/sh/rcar/dma.c:341:2: warning: format '%x' expects argument of type 'unsigned int', but argument 6 has type 'dma_addr_t' [-Wformat=] Fixes: 288f392e729dd4d3 ("ASoC: rsnd: add Audio DMAC peri peri support rework") Signed-off-by: Geert Uytterhoeven Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 92fd55044ee6..2b73df84a769 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -338,8 +338,8 @@ static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id, rsnd_dmapp_stop(dma); - dev_dbg(dev, "id/src/dst/chcr = %d/%x/%x/%08x\n", - dmapp->dmapp_id, dma->src_addr, dma->dst_addr, dmapp->chcr); + dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", + dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); return 0; } -- GitLab From 8537483a17038f08c68c1f0a561f0fe686e5706f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Mar 2015 01:25:01 +0000 Subject: [PATCH 0302/1910] ASoC: rsnd: recover PIO mode for new dma interface Renesas sound driver needs 1st/2nd DMA interface, and 1st DMA is using DMAEngine, and 2nd is using local method now. 2nd DMA had been DMAEngine, but it was moved to local method by previous patchset. But then, it lost PIO mode fallback when probe. this patch recovers it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 2b73df84a769..cd7b79a01ce2 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -539,6 +539,13 @@ void rsnd_dma_start(struct rsnd_dma *dma) void rsnd_dma_quit(struct rsnd_dma *dma) { + struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + + if (!dmac) + return; + dma->ops->quit(dma); } @@ -548,8 +555,18 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id) struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); int is_play = rsnd_io_is_play(io); + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + if (!dmac) + return -EAGAIN; + rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1); @@ -589,7 +606,7 @@ int rsnd_dma_probe(struct platform_device *pdev, dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); if (!dmac || !res) { dev_err(dev, "dma allocate failed\n"); - return -ENOMEM; + return 0; /* it will be PIO mode */ } dmac->dmapp_num = 0; -- GitLab From 530b7b4a52365ce2a250669b87e964a843bdbedb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Mar 2015 01:25:36 +0000 Subject: [PATCH 0303/1910] ASoC: rsnd: add regmap_config::name for debugfs Renesas sound driver needs SSI/SRC/DVC regmaps, but it didn't have regmap_config::name for devm_regmap_init_mmio(). Thus, debugfs initialization code tried to use same driver name many times, and failed. This patch adds eacy own name for regmap_config::name Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0273724a2668..a17a504d93b5 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -150,6 +150,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, regc.reg_bits = 32; regc.val_bits = 32; regc.reg_stride = 4; + regc.name = name; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); if (!res) -- GitLab From d3ef70543429b754dacc87fc68c30c2c34502337 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 11 Mar 2015 11:42:44 +0800 Subject: [PATCH 0304/1910] ASoC: rt5670: Add IRQ function This patch adds the IRQ function support of rt5670. We use a flag named dev_gpio in platform data to inform codec driver if the IRQ function is used or not. Also, we export rt5670_set_jack_detect for machine driver to pass the jack point. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5670.h | 1 + sound/soc/codecs/rt5670.c | 176 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt5670.h | 4 + 3 files changed, 179 insertions(+), 2 deletions(-) diff --git a/include/sound/rt5670.h b/include/sound/rt5670.h index bd311197a3b5..b7d60510819b 100644 --- a/include/sound/rt5670.h +++ b/include/sound/rt5670.h @@ -14,6 +14,7 @@ struct rt5670_platform_data { int jd_mode; bool in2_diff; + bool dev_gpio; bool dmic_en; unsigned int dmic1_data_pin; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 1a6a9c4dc879..a900db5fb1d9 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -403,6 +403,171 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg) } } +/** + * rt5670_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + int val; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD, + RT5670_CBJ_MN_JD); + snd_soc_write(codec, RT5670_GPIO_CTRL2, 0x0004); + snd_soc_update_bits(codec, RT5670_GPIO_CTRL1, + RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); + snd_soc_update_bits(codec, RT5670_CJ_CTRL1, + RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN); + snd_soc_write(codec, RT5670_JD_CTRL3, 0x00f0); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_MN_JD, 0); + msleep(300); + val = snd_soc_read(codec, RT5670_CJ_CTRL3) & 0x7; + if (val == 0x1 || val == 0x2) { + rt5670->jack_type = SND_JACK_HEADSET; + /* for push button */ + snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x8); + snd_soc_update_bits(codec, RT5670_IL_CMD, 0x40, 0x40); + snd_soc_read(codec, RT5670_IL_CMD); + } else { + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); + rt5670->jack_type = SND_JACK_HEADPHONE; + snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + } + } else { + snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0); + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); + rt5670->jack_type = 0; + snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + } + + return rt5670->jack_type; +} + +static int rt5670_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5670_IL_CMD); + btn_type = val & 0xff80; + snd_soc_write(codec, RT5670_IL_CMD, val); + if (btn_type != 0) { + msleep(20); + val = snd_soc_read(codec, RT5670_IL_CMD); + snd_soc_write(codec, RT5670_IL_CMD, val); + } + + return btn_type; +} + +static int rt5670_irq_detection(void *data) +{ + struct rt5670_priv *rt5670 = (struct rt5670_priv *)data; + struct snd_soc_jack_gpio *gpio = &rt5670->hp_gpio; + struct snd_soc_jack *jack = rt5670->jack; + int val, btn_type, report = jack->status; + + if (rt5670->pdata.jd_mode == 1) /* 2 port */ + val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0070; + else + val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0020; + + switch (val) { + /* jack in */ + case 0x30: /* 2 port */ + case 0x0: /* 1 port or 2 port */ + if (rt5670->jack_type == 0) { + report = rt5670_headset_detect(rt5670->codec, 1); + /* for push button and jack out */ + gpio->debounce_time = 25; + break; + } + btn_type = 0; + if (snd_soc_read(rt5670->codec, RT5670_INT_IRQ_ST) & 0x4) { + /* button pressed */ + report = SND_JACK_HEADSET; + btn_type = rt5670_button_detect(rt5670->codec); + switch (btn_type) { + case 0x2000: /* up */ + report |= SND_JACK_BTN_1; + break; + case 0x0400: /* center */ + report |= SND_JACK_BTN_0; + break; + case 0x0080: /* down */ + report |= SND_JACK_BTN_2; + break; + default: + dev_err(rt5670->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + } + if (btn_type == 0)/* button release */ + report = rt5670->jack_type; + + break; + /* jack out */ + case 0x70: /* 2 port */ + case 0x10: /* 2 port */ + case 0x20: /* 1 port */ + report = 0; + snd_soc_update_bits(rt5670->codec, RT5670_INT_IRQ_ST, 0x1, 0x0); + rt5670_headset_detect(rt5670->codec, 0); + gpio->debounce_time = 150; /* for jack in */ + break; + default: + break; + } + + return report; +} + +int rt5670_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + int ret; + + rt5670->jack = jack; + rt5670->hp_gpio.gpiod_dev = codec->dev; + rt5670->hp_gpio.name = "headphone detect"; + rt5670->hp_gpio.report = SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2; + rt5670->hp_gpio.debounce_time = 150; + rt5670->hp_gpio.wake = true; + rt5670->hp_gpio.data = (struct rt5670_priv *)rt5670; + rt5670->hp_gpio.jack_status_check = rt5670_irq_detection; + + ret = snd_soc_jack_add_gpios(rt5670->jack, 1, + &rt5670->hp_gpio); + if (ret) { + dev_err(codec->dev, "Adding jack GPIO failed\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_set_jack_detect); + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); @@ -2506,6 +2671,7 @@ static int rt5670_remove(struct snd_soc_codec *codec) struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5670->regmap, RT5670_RESET, 0); + snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio); return 0; } @@ -2665,6 +2831,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (dmi_check_system(dmi_platform_intel_braswell)) { rt5670->pdata.dmic_en = true; rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.dev_gpio = true; rt5670->pdata.jd_mode = 1; } @@ -2706,12 +2873,17 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5670->regmap, RT5670_IN2, RT5670_IN_DF2, RT5670_IN_DF2); - if (i2c->irq) { + if (rt5670->pdata.dev_gpio) { + /* for push button */ + regmap_write(rt5670->regmap, RT5670_IL_CMD, 0x0000); + regmap_write(rt5670->regmap, RT5670_IL_CMD2, 0x0010); + regmap_write(rt5670->regmap, RT5670_IL_CMD3, 0x0014); + /* for irq */ regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); - + regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8); } if (rt5670->pdata.jd_mode) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 0a67adbcfbc3..0f3255aeeb9b 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1988,6 +1988,8 @@ struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; struct regmap *regmap; + struct snd_soc_jack *jack; + struct snd_soc_jack_gpio hp_gpio; int sysclk; int sysclk_src; @@ -2004,4 +2006,6 @@ struct rt5670_priv { int jack_type; }; +int rt5670_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack); #endif /* __RT5670_H__ */ -- GitLab From cc3c340d28b9f730fdc6bc5caa77e3bbd1e2377c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 11 Mar 2015 11:42:45 +0800 Subject: [PATCH 0305/1910] ASoC: rt5670: export jack suspend/resume APIs We force enable "Mic Det Power" when a jack is inserted. Also, we set codec idle_bias_off = true. As a result, codec driver will not suspend as we expect. On Braswell, we don't need the jack detection when suspend but need it after resume, so export the jack suspend/resume APIs which are provided for machine driver to control during suspend/resume. Signed-off-by: Jie Yang Signed-off-by: Jin Yao Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 18 ++++++++++++++++++ sound/soc/codecs/rt5670.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a900db5fb1d9..91d2069a9313 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -461,6 +461,24 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) return rt5670->jack_type; } +void rt5670_jack_suspend(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + rt5670->jack_type_saved = rt5670->jack_type; + rt5670_headset_detect(codec, 0); +} +EXPORT_SYMBOL_GPL(rt5670_jack_suspend); + +void rt5670_jack_resume(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + if (rt5670->jack_type_saved) + rt5670_headset_detect(codec, 1); +} +EXPORT_SYMBOL_GPL(rt5670_jack_resume); + static int rt5670_button_detect(struct snd_soc_codec *codec) { int btn_type, val; diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 0f3255aeeb9b..dc2b46236c5c 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -2004,8 +2004,11 @@ struct rt5670_priv { int dsp_sw; /* expected parameter setting */ int dsp_rate; int jack_type; + int jack_type_saved; }; +void rt5670_jack_suspend(struct snd_soc_codec *codec); +void rt5670_jack_resume(struct snd_soc_codec *codec); int rt5670_set_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); #endif /* __RT5670_H__ */ -- GitLab From 9449d39b990d6d3d6386fbb92f3b86c808157b47 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:20 +0800 Subject: [PATCH 0306/1910] ASoC: Intel: add function to load firmware image Add a general method to load firmware image, and apply to base firmware image loading. With the method, the driver will support loading multiple different modules in order to support different features. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-dsp-priv.h | 13 +++++ sound/soc/intel/sst-firmware.c | 1 + sound/soc/intel/sst-haswell-dsp.c | 1 + sound/soc/intel/sst-haswell-ipc.c | 83 ++++++++++++++++++++++++++++--- sound/soc/intel/sst-haswell-ipc.h | 6 +++ 5 files changed, 98 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index b9da030e312d..396d54510350 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h @@ -172,6 +172,16 @@ struct sst_module_runtime_context { u32 *buffer; }; +/* + * Audio DSP Module State + */ +enum sst_module_state { + SST_MODULE_STATE_UNLOADED = 0, /* default state */ + SST_MODULE_STATE_LOADED, + SST_MODULE_STATE_INITIALIZED, /* and inactive */ + SST_MODULE_STATE_ACTIVE, +}; + /* * Audio DSP Generic Module. * @@ -203,6 +213,9 @@ struct sst_module { struct list_head list; /* DSP list of modules */ struct list_head list_fw; /* FW list of modules */ struct list_head runtime_list; /* list of runtime module objects*/ + + /* state */ + enum sst_module_state state; }; /* diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 5f71ef607a57..5e5800897da2 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -498,6 +498,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, sst_module->scratch_size = template->scratch_size; sst_module->persistent_size = template->persistent_size; sst_module->entry = template->entry; + sst_module->state = SST_MODULE_STATE_UNLOADED; INIT_LIST_HEAD(&sst_module->block_list); INIT_LIST_HEAD(&sst_module->runtime_list); diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 402b728c0a06..8ad733befbbd 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -169,6 +169,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, block = (void *)block + sizeof(*block) + block->size; } + mod->state = SST_MODULE_STATE_LOADED; return 0; } diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 863a9ca34b8e..ec688f598320 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1844,6 +1844,8 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) if (ret < 0) dev_err(dev, "error: audio DSP boot failure\n"); + sst_hsw_init_module_state(hsw); + ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, msecs_to_jiffies(IPC_BOOT_MSECS)); if (ret == 0) { @@ -1886,6 +1888,74 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) return hsw->dsp; } +void sst_hsw_init_module_state(struct sst_hsw *hsw) +{ + struct sst_module *module; + enum sst_hsw_module_id id; + + /* the base fw contains several modules */ + for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { + module = sst_module_get_from_id(hsw->dsp, id); + if (module) + module->state = SST_MODULE_STATE_ACTIVE; + } +} + +int sst_hsw_module_load(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, char *name) +{ + int ret = 0; + const struct firmware *fw = NULL; + struct sst_fw *hsw_sst_fw; + struct sst_module *module; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name); + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + /* loading for the first time */ + if (module_id == SST_HSW_MODULE_BASE_FW) { + /* for base module: use fw requested in acpi probe */ + fw = dsp->pdata->fw; + if (!fw) { + dev_err(dev, "request Base fw failed\n"); + return -ENODEV; + } + } else { + /* try and load any other optional modules if they are + * available. Use dev_info instead of dev_err in case + * request firmware failed */ + ret = request_firmware(&fw, name, dev); + if (ret) { + dev_info(dev, "fw image %s not available(%d)\n", + name, ret); + return ret; + } + } + hsw_sst_fw = sst_fw_new(dsp, fw, hsw); + if (hsw_sst_fw == NULL) { + dev_err(dev, "error: failed to load firmware\n"); + ret = -ENOMEM; + goto out; + } + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "error: no module %d in firmware %s\n", + module_id, name); + } + } else + dev_info(dev, "module %d (%s) already loaded\n", + module_id, name); +out: + /* release fw, but base fw should be released by acpi driver */ + if (fw && module_id != SST_HSW_MODULE_BASE_FW) + release_firmware(fw); + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, @@ -1947,12 +2017,10 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) /* keep the DSP in reset state for base FW loading */ sst_dsp_reset(hsw->dsp); - hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); - if (hsw->sst_fw == NULL) { - ret = -ENODEV; - dev_err(dev, "error: failed to load firmware\n"); + /* load base module and other modules in base firmware image */ + ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base"); + if (ret < 0) goto fw_err; - } /* allocate scratch mem regions */ ret = sst_block_alloc_scratch(hsw->dsp); @@ -1971,6 +2039,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) goto boot_err; } + /* init module state after boot */ + sst_hsw_init_module_state(hsw); + /* get the FW version */ sst_hsw_fw_get_version(hsw, &version); @@ -1986,7 +2057,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) boot_err: sst_dsp_reset(hsw->dsp); - sst_fw_free(hsw->sst_fw); + sst_fw_free_all(hsw->dsp); fw_err: dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, hsw->dx_context, hsw->dx_context_paddr); diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 858096041cb1..e071b3a54eae 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -467,6 +467,12 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); +/* fw module function */ +void sst_hsw_init_module_state(struct sst_hsw *hsw); + +int sst_hsw_module_load(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, char *name); + /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, int mod_id, int offset); -- GitLab From 8c43fc2fdda0858879ee4dd7d7ed8e67890f699f Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:21 +0800 Subject: [PATCH 0307/1910] ASoC: Intel: add function to load sound effect module waves Try to load module waves and allocate runtime blocks for it if the firmware image of module waves exists. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-dsp.c | 2 ++ sound/soc/intel/sst-haswell-ipc.c | 23 +++++++++++++++++++++-- sound/soc/intel/sst-haswell-ipc.h | 1 + sound/soc/intel/sst-haswell-pcm.c | 21 +++++++++++++++++++-- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 8ad733befbbd..b3e957d46933 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, && module->type != SST_HSW_MODULE_PCM && module->type != SST_HSW_MODULE_PCM_REFERENCE && module->type != SST_HSW_MODULE_PCM_CAPTURE + && module->type != SST_HSW_MODULE_WAVES && module->type != SST_HSW_MODULE_LPAL) return 0; @@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, mod->type = SST_MEM_IRAM; break; case SST_HSW_DRAM: + case SST_HSW_REGS: ram = dsp->addr.lpe; mod->offset = block->ram_offset; mod->type = SST_MEM_DRAM; diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index ec688f598320..63740e36dd26 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1896,11 +1896,27 @@ void sst_hsw_init_module_state(struct sst_hsw *hsw) /* the base fw contains several modules */ for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { module = sst_module_get_from_id(hsw->dsp, id); - if (module) - module->state = SST_MODULE_STATE_ACTIVE; + if (module) { + /* module waves is active only after being enabled */ + if (id == SST_HSW_MODULE_WAVES) + module->state = SST_MODULE_STATE_INITIALIZED; + else + module->state = SST_MODULE_STATE_ACTIVE; + } } } +bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) +{ + struct sst_module *module; + + module = sst_module_get_from_id(hsw->dsp, module_id); + if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED) + return false; + else + return true; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -2022,6 +2038,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (ret < 0) goto fw_err; + /* try to load module waves */ + sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin"); + /* allocate scratch mem regions */ ret = sst_block_alloc_scratch(hsw->dsp); if (ret < 0) diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index e071b3a54eae..208724b74cf7 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -469,6 +469,7 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); /* fw module function */ void sst_hsw_init_module_state(struct sst_hsw *hsw); +bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 7e21e8f85885..a604cc442111 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -807,6 +807,17 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) pcm_data->runtime->persistent_offset; } + /* create runtime blocks for module waves */ + if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; + pcm_data->runtime = sst_hsw_runtime_module_create(hsw, + SST_HSW_MODULE_WAVES, pcm_data->persistent_offset); + if (pcm_data->runtime == NULL) + goto err; + pcm_data->persistent_offset = + pcm_data->runtime->persistent_offset; + } + return 0; err: @@ -820,12 +831,16 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) { + struct sst_hsw *hsw = pdata->hsw; struct hsw_pcm_data *pcm_data; int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - + sst_hsw_runtime_module_free(pcm_data->runtime); + } + if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; sst_hsw_runtime_module_free(pcm_data->runtime); } } @@ -984,7 +999,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) } /* allocate runtime modules */ - hsw_pcm_create_modules(priv_data); + ret = hsw_pcm_create_modules(priv_data); + if (ret < 0) + goto err; /* enable runtime PM with auto suspend */ pm_runtime_set_autosuspend_delay(platform->dev, -- GitLab From e8e79ede44ec99e09f8604c23ee99dc25065a343 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:22 +0800 Subject: [PATCH 0308/1910] ASoC: Intel: add function to enable/disable sound effect module waves Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 175 ++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 11 ++ 2 files changed, 186 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 63740e36dd26..265d754a4090 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -79,6 +79,15 @@ #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) +/* Module Message */ +#define IPC_MODULE_OPERATION_SHIFT 20 +#define IPC_MODULE_OPERATION_MASK (0xf << IPC_MODULE_OPERATION_SHIFT) +#define IPC_MODULE_OPERATION(x) (x << IPC_MODULE_OPERATION_SHIFT) + +#define IPC_MODULE_ID_SHIFT 16 +#define IPC_MODULE_ID_MASK (0xf << IPC_MODULE_ID_SHIFT) +#define IPC_MODULE_ID(x) (x << IPC_MODULE_ID_SHIFT) + /* IPC message timeout (msecs) */ #define IPC_TIMEOUT_MSECS 300 #define IPC_BOOT_MSECS 200 @@ -115,6 +124,7 @@ enum ipc_glb_type { IPC_GLB_ENTER_DX_STATE = 12, IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ + IPC_GLB_MODULE_OPERATION = 15, /* Message to loadable fw module */ IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ }; @@ -133,6 +143,16 @@ enum ipc_glb_reply { IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ }; +enum ipc_module_operation { + IPC_MODULE_NOTIFICATION = 0, + IPC_MODULE_ENABLE = 1, + IPC_MODULE_DISABLE = 2, + IPC_MODULE_GET_PARAMETER = 3, + IPC_MODULE_SET_PARAMETER = 4, + IPC_MODULE_GET_INFO = 5, + IPC_MODULE_MAX_MESSAGE +}; + /* Stream Message - Types */ enum ipc_str_operation { IPC_STR_RESET = 0, @@ -352,6 +372,16 @@ static inline u32 msg_get_notify_reason(u32 msg) return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; } +static inline u32 msg_get_module_operation(u32 msg) +{ + return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT; +} + +static inline u32 msg_get_module_id(u32 msg) +{ + return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT; +} + u32 create_channel_map(enum sst_hsw_channel_config config) { switch (config) { @@ -795,6 +825,31 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) return 1; } +static int hsw_module_message(struct sst_hsw *hsw, u32 header) +{ + u32 operation, module_id; + int handled = 0; + + operation = msg_get_module_operation(header); + module_id = msg_get_module_id(header); + dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n", + header); + dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n", + operation, module_id); + + switch (operation) { + case IPC_MODULE_NOTIFICATION: + dev_dbg(hsw->dev, "module notification received"); + handled = 1; + break; + default: + handled = hsw_process_reply(hsw, header); + break; + } + + return handled; +} + static int hsw_stream_message(struct sst_hsw *hsw, u32 header) { u32 stream_msg, stream_id, stage_type; @@ -890,6 +945,9 @@ static int hsw_process_notification(struct sst_hsw *hsw) case IPC_GLB_DEBUG_LOG_MESSAGE: handled = hsw_log_message(hsw, header); break; + case IPC_GLB_MODULE_OPERATION: + handled = hsw_module_message(hsw, header); + break; default: dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", type, header); @@ -1917,6 +1975,17 @@ bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) return true; } +bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) +{ + struct sst_module *module; + + module = sst_module_get_from_id(hsw->dsp, module_id); + if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE) + return true; + else + return false; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -1972,6 +2041,112 @@ int sst_hsw_module_load(struct sst_hsw *hsw, return ret; } +int sst_hsw_module_enable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id) +{ + int ret; + u32 header = 0; + struct sst_hsw_ipc_module_config config; + struct sst_module *module; + struct sst_module_runtime *runtime; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + if (!sst_hsw_is_module_loaded(hsw, module_id)) { + dev_dbg(dev, "module %d not loaded\n", module_id); + return 0; + } + + if (sst_hsw_is_module_active(hsw, module_id)) { + dev_info(dev, "module %d already enabled\n", module_id); + return 0; + } + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "module %d not valid\n", module_id); + return -ENXIO; + } + + runtime = sst_module_runtime_get_from_id(module, module_id); + if (runtime == NULL) { + dev_err(dev, "runtime %d not valid", module_id); + return -ENXIO; + } + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | + IPC_MODULE_ID(module_id); + dev_dbg(dev, "module enable header: %x\n", header); + + config.map.module_entries_count = 1; + config.map.module_entries[0].module_id = module->id; + config.map.module_entries[0].entry_point = module->entry; + + config.persistent_mem.offset = + sst_dsp_get_offset(dsp, + runtime->persistent_offset, SST_MEM_DRAM); + config.persistent_mem.size = module->persistent_size; + + config.scratch_mem.offset = + sst_dsp_get_offset(dsp, + dsp->scratch_offset, SST_MEM_DRAM); + config.scratch_mem.size = module->scratch_size; + dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x", + config.map.module_entries[0].module_id, + config.persistent_mem.size, + config.persistent_mem.offset, + config.scratch_mem.size, config.scratch_mem.offset, + config.map.module_entries[0].entry_point); + + ret = ipc_tx_message_wait(hsw, header, + &config, sizeof(config), NULL, 0); + if (ret < 0) + dev_err(dev, "ipc: module enable failed - %d\n", ret); + else + module->state = SST_MODULE_STATE_ACTIVE; + + return ret; +} + +int sst_hsw_module_disable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id) +{ + int ret; + u32 header; + struct sst_module *module; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + if (!sst_hsw_is_module_loaded(hsw, module_id)) { + dev_dbg(dev, "module %d not loaded\n", module_id); + return 0; + } + + if (!sst_hsw_is_module_active(hsw, module_id)) { + dev_info(dev, "module %d already disabled\n", module_id); + return 0; + } + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "module %d not valid\n", module_id); + return -ENXIO; + } + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | + IPC_MODULE_ID(module_id); + + ret = ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); + if (ret < 0) + dev_err(dev, "module disable failed - %d\n", ret); + else + module->state = SST_MODULE_STATE_INITIALIZED; + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 208724b74cf7..30c65b28fa60 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -215,6 +215,12 @@ struct sst_hsw_fx_enable { struct sst_hsw_memory_info persistent_mem; } __attribute__((packed)); +struct sst_hsw_ipc_module_config { + struct sst_hsw_module_map map; + struct sst_hsw_memory_info persistent_mem; + struct sst_hsw_memory_info scratch_mem; +} __attribute__((packed)); + struct sst_hsw_get_fx_param { u32 parameter_id; u32 param_size; @@ -470,9 +476,14 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); /* fw module function */ void sst_hsw_init_module_state(struct sst_hsw *hsw); bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); +bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); +int sst_hsw_module_enable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id); +int sst_hsw_module_disable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id); /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, -- GitLab From 007ee8dec6843b3b491a4bb42320c0eb8e884f72 Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Mon, 9 Mar 2015 16:14:58 +0200 Subject: [PATCH 0309/1910] crypto: tcrypt - fix uninit sg entries in test_acipher_speed Commit 5be4d4c94b1f ("crypto: replace scatterwalk_sg_next with sg_next") did not consider the fact that scatterwalk_sg_next() was looking at sg entry length, while sg_next() looks at the "chained" sg bit. This should have no effect in theory. However in practice, there are cases where the sg table is initialized to a number of entries and some of them are not properly configured. While scatterwalk_sg_next() would have returned NULL (since sg length = 0 and sg page_link = 0), sg_next() happily returns the next unconfigured sg entry. insmod tcrypt.ko mode=500 sec=1 testing speed of async cbc(aes) (cbc-aes-talitos) encryption test 0 (128 bit key, 16 byte blocks): Unable to handle kernel paging request for data at address 0x00000000 Faulting instruction address: 0xc00d79e4 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=8 P1022 DS Modules linked in: tcrypt(+) talitos CPU: 0 PID: 2670 Comm: insmod Not tainted 4.0.0-rc1-QorIQ-SDK-V1.6+g904f1ca82209 #1 task: e8de3200 ti: e70bc000 task.ti: e70bc000 NIP: c00d79e4 LR: f92d223c CTR: c00d79c8 REGS: e70bda00 TRAP: 0300 Not tainted (4.0.0-rc1-QorIQ-SDK-V1.6+g904f1ca82209) MSR: 00029000 CR: 84428f22 XER: 00000000 DEAR: 00000000 ESR: 00000000 GPR00: f92d223c e70bdab0 e8de3200 00000000 e70bdbb8 00000001 00000000 00000000 GPR08: 00000000 00000000 c08b0380 27282010 c00d79c8 1003a634 00000000 e70bdf1c GPR16: e70bdef0 00000020 00000000 c08c0000 00000010 00000000 e70bdbb8 00000010 GPR24: e976d3a8 00000010 00000000 e70bdbd8 e8961010 00000001 c086e560 00000000 NIP [c00d79e4] page_address+0x1c/0x110 LR [f92d223c] talitos_map_sg+0x130/0x184 [talitos] Call Trace: [e70bdab0] [00000010] 0x10 (unreliable) [e70bdad0] [f92d223c] talitos_map_sg+0x130/0x184 [talitos] [e70bdb00] [f92d30d8] common_nonsnoop.constprop.13+0xc0/0x304 [talitos] [e70bdb30] [f933fd90] test_acipher_speed+0x434/0x7dc [tcrypt] [e70bdcc0] [f934318c] do_test+0x2478/0x306c [tcrypt] [e70bdd80] [f11fe058] tcrypt_mod_init+0x58/0x100 [tcrypt] [e70bdda0] [c0002354] do_one_initcall+0x90/0x1f4 [e70bde10] [c061fe00] do_init_module+0x60/0x1ac [e70bde30] [c00a79f0] load_module+0x185c/0x1f88 [e70bdee0] [c00a82b0] SyS_finit_module+0x7c/0x98 [e70bdf40] [c000e8b0] ret_from_syscall+0x0/0x3c Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 4b9e23fa4204..1a2800107fc8 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1155,9 +1155,9 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int secs, goto out_free_req; } - sg_init_table(sg, TVMEMSIZE); - k = *keysize + *b_size; + sg_init_table(sg, DIV_ROUND_UP(k, PAGE_SIZE)); + if (k > PAGE_SIZE) { sg_set_buf(sg, tvmem[0] + *keysize, PAGE_SIZE - *keysize); -- GitLab From 1ee9b5e4712948973f0065d944b1afeb50b4dccd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 10:36:35 -0700 Subject: [PATCH 0310/1910] hwrng: omap - remove incorrect __exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index d14dcf788f17..7f3597d2a8ac 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -408,7 +408,7 @@ static int omap_rng_probe(struct platform_device *pdev) return ret; } -static int __exit omap_rng_remove(struct platform_device *pdev) +static int omap_rng_remove(struct platform_device *pdev) { struct omap_rng_dev *priv = platform_get_drvdata(pdev); @@ -460,7 +460,7 @@ static struct platform_driver omap_rng_driver = { .of_match_table = of_match_ptr(omap_rng_of_match), }, .probe = omap_rng_probe, - .remove = __exit_p(omap_rng_remove), + .remove = omap_rng_remove, }; module_platform_driver(omap_rng_driver); -- GitLab From 87094a044ee894870d8784f51618a9b0d1fadc44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 10:36:37 -0700 Subject: [PATCH 0311/1910] hwrng: octeon - remove incorrect __exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/octeon-rng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c index be1c3f607398..6234a4a19b56 100644 --- a/drivers/char/hw_random/octeon-rng.c +++ b/drivers/char/hw_random/octeon-rng.c @@ -105,7 +105,7 @@ static int octeon_rng_probe(struct platform_device *pdev) return 0; } -static int __exit octeon_rng_remove(struct platform_device *pdev) +static int octeon_rng_remove(struct platform_device *pdev) { struct hwrng *rng = platform_get_drvdata(pdev); @@ -119,7 +119,7 @@ static struct platform_driver octeon_rng_driver = { .name = "octeon_rng", }, .probe = octeon_rng_probe, - .remove = __exit_p(octeon_rng_remove), + .remove = octeon_rng_remove, }; module_platform_driver(octeon_rng_driver); -- GitLab From 257bedd4f39d53ca41c5c8e3f8e0d805607ae661 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 10:36:38 -0700 Subject: [PATCH 0312/1910] hwrng: pseries - remove incorrect __init/__exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Similarly probe() methods should not be marked __init unless platform_driver_probe() is used. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/pseries-rng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index bcf86f91800a..63ce51d09af1 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -61,13 +61,13 @@ static struct hwrng pseries_rng = { .read = pseries_rng_read, }; -static int __init pseries_rng_probe(struct vio_dev *dev, +static int pseries_rng_probe(struct vio_dev *dev, const struct vio_device_id *id) { return hwrng_register(&pseries_rng); } -static int __exit pseries_rng_remove(struct vio_dev *dev) +static int pseries_rng_remove(struct vio_dev *dev) { hwrng_unregister(&pseries_rng); return 0; -- GitLab From 83ce01d24a1998cf1be6a7ea37f54edf264abe93 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 13:25:49 -0700 Subject: [PATCH 0313/1910] crypto: qat - remove incorrect __exit markup PCI bus is hot-pluggable, and even if it wasn't one can still unbind the device from driver via sysfs, so we should not make driver's remove method as __exit. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 8ffdb95c9804..e7af9d5980af 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -379,7 +379,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; } -static void __exit adf_remove(struct pci_dev *pdev) +static void adf_remove(struct pci_dev *pdev) { struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); -- GitLab From 1eb8a1b340e2f0a562b4987683bbaee4d620bf0a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 13:35:39 -0700 Subject: [PATCH 0314/1910] crypto: amcc - remove incorrect __init/__exit markups Even if bus is not hot-pluggable, the devices can be bound and unbound from the driver via sysfs, so we should not be using __init/__exit annotations on probe() and remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index d02b77150070..3b28e8c3de28 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1155,7 +1155,7 @@ struct crypto4xx_alg_common crypto4xx_alg[] = { /** * Module Initialization Routine */ -static int __init crypto4xx_probe(struct platform_device *ofdev) +static int crypto4xx_probe(struct platform_device *ofdev) { int rc; struct resource res; @@ -1263,7 +1263,7 @@ static int __init crypto4xx_probe(struct platform_device *ofdev) return rc; } -static int __exit crypto4xx_remove(struct platform_device *ofdev) +static int crypto4xx_remove(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev); @@ -1291,7 +1291,7 @@ static struct platform_driver crypto4xx_driver = { .of_match_table = crypto4xx_match, }, .probe = crypto4xx_probe, - .remove = __exit_p(crypto4xx_remove), + .remove = crypto4xx_remove, }; module_platform_driver(crypto4xx_driver); -- GitLab From b3f5dbec2f077be7ee392da3365d11e393a50038 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Mar 2015 17:56:33 +0100 Subject: [PATCH 0315/1910] ASoC: ab8500-codec: don't export static symbol The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ type T; identifier f; @@ static T f (...) { ... } @@ identifier r.f; declarer name EXPORT_SYMBOL_GPL; @@ -EXPORT_SYMBOL_GPL(f); // Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 7895689588da..88ca9cb0ce79 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2003,7 +2003,6 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, return 0; } -EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics); static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec, enum ear_cm_voltage ear_cmv) @@ -2036,7 +2035,6 @@ static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec, return 0; } -EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv); static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay) -- GitLab From 1ff2765182d1969947dfb50f4e42ebd7e83699fd Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Mon, 9 Mar 2015 15:50:34 -0700 Subject: [PATCH 0316/1910] ASoC: Add max98925 codec driver Signed-off-by: Anish Kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98925.txt | 22 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98925.c | 655 ++++++++++++++ sound/soc/codecs/max98925.h | 832 ++++++++++++++++++ 5 files changed, 1515 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98925.txt create mode 100644 sound/soc/codecs/max98925.c create mode 100644 sound/soc/codecs/max98925.h diff --git a/Documentation/devicetree/bindings/sound/max98925.txt b/Documentation/devicetree/bindings/sound/max98925.txt new file mode 100644 index 000000000000..27be63e2aa0d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98925.txt @@ -0,0 +1,22 @@ +max98925 audio CODEC + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98925" + + - vmon-slot-no : slot number used to send voltage information + + - imon-slot-no : slot number used to send current information + + - reg : the I2C address of the device for I2C + +Example: + +codec: max98925@1a { + compatible = "maxim,max98925"; + vmon-slot-no = <0>; + imon-slot-no = <2>; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ea9f0e31f9d4..0ccce5a1f4fa 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -70,6 +70,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB + select SND_SOC_MAX98925 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -460,6 +461,9 @@ config SND_SOC_MAX98095 config SND_SOC_MAX98357A tristate +config SND_SOC_MAX98925 + tristate + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69b8666d187a..333ee3a4efa1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -65,6 +65,7 @@ snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max98357a-objs := max98357a.o +snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -247,6 +248,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c new file mode 100644 index 000000000000..74f4f0b60108 --- /dev/null +++ b/sound/soc/codecs/max98925.c @@ -0,0 +1,655 @@ +/* + * max98925.c -- ALSA SoC Stereo MAX98925 driver + * Copyright 2013-15 Maxim Integrated Products + * This program is free software; you can 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "max98925.h" + +static const char *const dai_text[] = { + "Left", "Right", "LeftRight", "LeftRightDiv2", +}; + +static const char * const max98925_boost_voltage_text[] = { + "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V", + "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" +}; + +static SOC_ENUM_SINGLE_DECL(max98925_boost_voltage, + MAX98925_CONFIGURATION, M98925_BST_VOUT_SHIFT, + max98925_boost_voltage_text); + +static const char *const hpf_text[] = { + "Disable", "DC Block", "100Hz", "200Hz", "400Hz", "800Hz", +}; + +static struct reg_default max98925_reg[] = { + { 0x0B, 0x00 }, /* IRQ Enable0 */ + { 0x0C, 0x00 }, /* IRQ Enable1 */ + { 0x0D, 0x00 }, /* IRQ Enable2 */ + { 0x0E, 0x00 }, /* IRQ Clear0 */ + { 0x0F, 0x00 }, /* IRQ Clear1 */ + { 0x10, 0x00 }, /* IRQ Clear2 */ + { 0x11, 0xC0 }, /* Map0 */ + { 0x12, 0x00 }, /* Map1 */ + { 0x13, 0x00 }, /* Map2 */ + { 0x14, 0xF0 }, /* Map3 */ + { 0x15, 0x00 }, /* Map4 */ + { 0x16, 0xAB }, /* Map5 */ + { 0x17, 0x89 }, /* Map6 */ + { 0x18, 0x00 }, /* Map7 */ + { 0x19, 0x00 }, /* Map8 */ + { 0x1A, 0x06 }, /* DAI Clock Mode 1 */ + { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */ + { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ + { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ + { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ + { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ + { 0x20, 0x50 }, /* Format */ + { 0x21, 0x00 }, /* TDM Slot Select */ + { 0x22, 0x00 }, /* DOUT Configuration VMON */ + { 0x23, 0x00 }, /* DOUT Configuration IMON */ + { 0x24, 0x00 }, /* DOUT Configuration VBAT */ + { 0x25, 0x00 }, /* DOUT Configuration VBST */ + { 0x26, 0x00 }, /* DOUT Configuration FLAG */ + { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ + { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ + { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ + { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ + { 0x2B, 0x02 }, /* DOUT Drive Strength */ + { 0x2C, 0x90 }, /* Filters */ + { 0x2D, 0x00 }, /* Gain */ + { 0x2E, 0x02 }, /* Gain Ramping */ + { 0x2F, 0x00 }, /* Speaker Amplifier */ + { 0x30, 0x0A }, /* Threshold */ + { 0x31, 0x00 }, /* ALC Attack */ + { 0x32, 0x80 }, /* ALC Atten and Release */ + { 0x33, 0x00 }, /* ALC Infinite Hold Release */ + { 0x34, 0x92 }, /* ALC Configuration */ + { 0x35, 0x01 }, /* Boost Converter */ + { 0x36, 0x00 }, /* Block Enable */ + { 0x37, 0x00 }, /* Configuration */ + { 0x38, 0x00 }, /* Global Enable */ + { 0x3A, 0x00 }, /* Boost Limiter */ +}; + +static const struct soc_enum max98925_dai_enum = + SOC_ENUM_SINGLE(MAX98925_GAIN, 5, ARRAY_SIZE(dai_text), dai_text); + +static const struct soc_enum max98925_hpf_enum = + SOC_ENUM_SINGLE(MAX98925_FILTERS, 0, ARRAY_SIZE(hpf_text), hpf_text); + +static const struct snd_kcontrol_new max98925_hpf_sel_mux = + SOC_DAPM_ENUM("Rc Filter MUX Mux", max98925_hpf_enum); + +static const struct snd_kcontrol_new max98925_dai_sel_mux = + SOC_DAPM_ENUM("DAI IN MUX Mux", max98925_dai_enum); + +static int max98925_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(max98925->regmap, + MAX98925_BLOCK_ENABLE, + M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, + M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(max98925->regmap, + MAX98925_BLOCK_ENABLE, M98925_BST_EN_MASK | + M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, 0); + break; + default: + return 0; + } + return 0; +} + +static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("DAI IN MUX", SND_SOC_NOPM, 0, 0, + &max98925_dai_sel_mux), + SND_SOC_DAPM_MUX("Rc Filter MUX", SND_SOC_NOPM, 0, 0, + &max98925_hpf_sel_mux), + SND_SOC_DAPM_DAC_E("Amp Enable", NULL, MAX98925_BLOCK_ENABLE, + M98925_SPK_EN_SHIFT, 0, max98925_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("Global Enable", MAX98925_GLOBAL_ENABLE, + M98925_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("BE_OUT"), +}; + +static const struct snd_soc_dapm_route max98925_audio_map[] = { + {"DAI IN MUX", "Left", "DAI_OUT"}, + {"DAI IN MUX", "Right", "DAI_OUT"}, + {"DAI IN MUX", "LeftRight", "DAI_OUT"}, + {"DAI IN MUX", "LeftRightDiv2", "DAI_OUT"}, + {"Rc Filter MUX", "Disable", "DAI IN MUX"}, + {"Rc Filter MUX", "DC Block", "DAI IN MUX"}, + {"Rc Filter MUX", "100Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "200Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "400Hz", "DAI IN MUX"}, + {"Rc Filter MUX", "800Hz", "DAI IN MUX"}, + {"Amp Enable", NULL, "Rc Filter MUX"}, + {"BE_OUT", NULL, "Amp Enable"}, + {"BE_OUT", NULL, "Global Enable"}, +}; + +static bool max98925_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98925_VBAT_DATA: + case MAX98925_VBST_DATA: + case MAX98925_LIVE_STATUS0: + case MAX98925_LIVE_STATUS1: + case MAX98925_LIVE_STATUS2: + case MAX98925_STATE0: + case MAX98925_STATE1: + case MAX98925_STATE2: + case MAX98925_FLAG0: + case MAX98925_FLAG1: + case MAX98925_FLAG2: + case MAX98925_REV_VERSION: + return true; + default: + return false; + } +} + +static bool max98925_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98925_IRQ_CLEAR0: + case MAX98925_IRQ_CLEAR1: + case MAX98925_IRQ_CLEAR2: + case MAX98925_ALC_HOLD_RLS: + return false; + default: + return true; + } +} + +DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0); + +static const struct snd_kcontrol_new max98925_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", MAX98925_GAIN, + M98925_SPK_GAIN_SHIFT, (1<= rate) { + *value = rate_table[i].sr; + *n = rate_table[i].divisors[clock][0]; + *m = rate_table[i].divisors[clock][1]; + ret = 0; + break; + } + } + dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n", + __func__, rate_table[i].rate, *value); + return ret; +} + +static void max98925_set_sense_data(struct max98925_priv *max98925) +{ + /* set VMON slots */ + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_VMON, + M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK); + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_VMON, + M98925_DAI_VMON_SLOT_MASK, + max98925->v_slot << M98925_DAI_VMON_SLOT_SHIFT); + /* set IMON slots */ + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_IMON, + M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK); + regmap_update_bits(max98925->regmap, + MAX98925_DOUT_CFG_IMON, + M98925_DAI_IMON_SLOT_MASK, + max98925->i_slot << M98925_DAI_IMON_SLOT_SHIFT); +} + +static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + unsigned int invert = 0; + + dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* set DAI to slave mode */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_MAS_MASK, 0); + max98925_set_sense_data(max98925); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* + * set left channel DAI to master mode, + * right channel always slave + */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "DAI clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + invert = M98925_DAI_WCI_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + invert = M98925_DAI_BCI_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK; + break; + default: + dev_err(codec->dev, "DAI invert mode unsupported"); + return -EINVAL; + } + + regmap_update_bits(max98925->regmap, MAX98925_FORMAT, + M98925_DAI_BCI_MASK | M98925_DAI_BCI_MASK, invert); + return 0; +} + +static int max98925_set_clock(struct max98925_priv *max98925, + struct snd_pcm_hw_params *params) +{ + unsigned int dai_sr = 0, clock, mdll, n, m; + struct snd_soc_codec *codec = max98925->codec; + int rate = params_rate(params); + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = params_channels(params) * max98925->ch_size; + + switch (blr_clk_ratio) { + case 32: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32); + break; + case 48: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48); + break; + case 64: + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64); + break; + default: + return -EINVAL; + } + + switch (max98925->sysclk) { + case 6000000: + clock = 0; + mdll = M98925_MDLL_MULT_MCLKx16; + break; + case 11289600: + clock = 1; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + case 12000000: + clock = 0; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + case 12288000: + clock = 2; + mdll = M98925_MDLL_MULT_MCLKx8; + break; + default: + dev_info(max98925->codec->dev, "unsupported sysclk %d\n", + max98925->sysclk); + return -EINVAL; + } + + if (max98925_rate_value(codec, rate, clock, &dai_sr, &n, &m)) + return -EINVAL; + + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE2, + M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT); + /* set DAI m divider */ + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_M_MSBS, m >> 8); + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_M_LSBS, m & 0xFF); + /* set DAI n divider */ + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_N_MSBS, n >> 8); + regmap_write(max98925->regmap, + MAX98925_DAI_CLK_DIV_N_LSBS, n & 0xFF); + /* set MDLL */ + regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE1, + M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT); + return 0; +} + +static int max98925_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (snd_pcm_format_width(params_format(params))) { + case 16: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16); + max98925->ch_size = 16; + break; + case 24: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32); + max98925->ch_size = 32; + break; + case 32: + regmap_update_bits(max98925->regmap, + MAX98925_FORMAT, + M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32); + max98925->ch_size = 32; + break; + default: + pr_err("%s: format unsupported %d", + __func__, params_format(params)); + return -EINVAL; + } + dev_dbg(codec->dev, "%s: format supported %d", + __func__, params_format(params)); + return max98925_set_clock(max98925, params); +} + +static int max98925_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case 0: + /* use MCLK for Left channel, right channel always BCLK */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE1, + M98925_DAI_CLK_SOURCE_MASK, 0); + break; + case 1: + /* configure dai clock source to BCLK instead of MCLK */ + regmap_update_bits(max98925->regmap, + MAX98925_DAI_CLK_MODE1, + M98925_DAI_CLK_SOURCE_MASK, + M98925_DAI_CLK_SOURCE_MASK); + break; + default: + return -EINVAL; + } + max98925->sysclk = freq; + return 0; +} + +#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops max98925_dai_ops = { + .set_sysclk = max98925_dai_set_sysclk, + .set_fmt = max98925_dai_set_fmt, + .hw_params = max98925_dai_hw_params, +}; + +static struct snd_soc_dai_driver max98925_dai[] = { + { + .name = "max98925-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98925_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98925_FORMATS, + }, + .ops = &max98925_dai_ops, + } +}; + +static int max98925_probe(struct snd_soc_codec *codec) +{ + struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); + + max98925->codec = codec; + codec->control_data = max98925->regmap; + regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00); + /* It's not the default but we need to set DAI_DLY */ + regmap_write(max98925->regmap, + MAX98925_FORMAT, M98925_DAI_DLY_MASK); + regmap_write(max98925->regmap, MAX98925_TDM_SLOT_SELECT, 0xC8); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG1, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG2, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG3, 0xFF); + regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG4, 0xF0); + regmap_write(max98925->regmap, MAX98925_FILTERS, 0xD8); + regmap_write(max98925->regmap, MAX98925_ALC_CONFIGURATION, 0xF8); + regmap_write(max98925->regmap, MAX98925_CONFIGURATION, 0xF0); + /* Disable ALC muting */ + regmap_write(max98925->regmap, MAX98925_BOOST_LIMITER, 0xF8); + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98925 = { + .probe = max98925_probe, + .controls = max98925_snd_controls, + .num_controls = ARRAY_SIZE(max98925_snd_controls), + .dapm_routes = max98925_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98925_audio_map), + .dapm_widgets = max98925_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets), +}; + +static struct regmap_config max98925_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX98925_REV_VERSION, + .reg_defaults = max98925_reg, + .num_reg_defaults = ARRAY_SIZE(max98925_reg), + .volatile_reg = max98925_volatile_register, + .readable_reg = max98925_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int max98925_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret, reg; + u32 value; + struct max98925_priv *max98925; + + max98925 = devm_kzalloc(&i2c->dev, + sizeof(*max98925), GFP_KERNEL); + if (!max98925) + return -ENOMEM; + + i2c_set_clientdata(i2c, max98925); + max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap); + if (IS_ERR(max98925->regmap)) { + ret = PTR_ERR(max98925->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + goto err_out; + } + + if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { + if (value > M98925_DAI_VMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "vmon slot number is wrong:\n"); + return -EINVAL; + } + max98925->v_slot = value; + } + if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) { + if (value > M98925_DAI_IMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "imon slot number is wrong:\n"); + return -EINVAL; + } + max98925->i_slot = value; + } + ret = regmap_read(max98925->regmap, + MAX98925_REV_VERSION, ®); + if ((ret < 0) || + ((reg != MAX98925_VERSION) && + (reg != MAX98925_VERSION1))) { + dev_err(&i2c->dev, + "device initialization error (%d 0x%02X)\n", + ret, reg); + goto err_out; + } + dev_info(&i2c->dev, "device version 0x%02X\n", reg); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925, + max98925_dai, ARRAY_SIZE(max98925_dai)); + if (ret < 0) + dev_err(&i2c->dev, + "Failed to register codec: %d\n", ret); +err_out: + return ret; +} + +static int max98925_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98925_i2c_id[] = { + { "max98925", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98925_i2c_id); + +static const struct of_device_id max98925_of_match[] = { + { .compatible = "maxim,max98925", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98925_of_match); + +static struct i2c_driver max98925_i2c_driver = { + .driver = { + .name = "max98925", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max98925_of_match), + .pm = NULL, + }, + .probe = max98925_i2c_probe, + .remove = max98925_i2c_remove, + .id_table = max98925_i2c_id, +}; + +module_i2c_driver(max98925_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98925 driver"); +MODULE_AUTHOR("Ralph Birt , Anish kumar "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h new file mode 100644 index 000000000000..3783248f2780 --- /dev/null +++ b/sound/soc/codecs/max98925.h @@ -0,0 +1,832 @@ +/* + * max98925.h -- MAX98925 ALSA SoC Audio driver + * + * Copyright 2013-2015 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MAX98925_H +#define _MAX98925_H + +#define MAX98925_VERSION 0x51 +#define MAX98925_VERSION1 0x80 +#define MAX98925_VBAT_DATA 0x00 +#define MAX98925_VBST_DATA 0x01 +#define MAX98925_LIVE_STATUS0 0x02 +#define MAX98925_LIVE_STATUS1 0x03 +#define MAX98925_LIVE_STATUS2 0x04 +#define MAX98925_STATE0 0x05 +#define MAX98925_STATE1 0x06 +#define MAX98925_STATE2 0x07 +#define MAX98925_FLAG0 0x08 +#define MAX98925_FLAG1 0x09 +#define MAX98925_FLAG2 0x0A +#define MAX98925_IRQ_ENABLE0 0x0B +#define MAX98925_IRQ_ENABLE1 0x0C +#define MAX98925_IRQ_ENABLE2 0x0D +#define MAX98925_IRQ_CLEAR0 0x0E +#define MAX98925_IRQ_CLEAR1 0x0F +#define MAX98925_IRQ_CLEAR2 0x10 +#define MAX98925_MAP0 0x11 +#define MAX98925_MAP1 0x12 +#define MAX98925_MAP2 0x13 +#define MAX98925_MAP3 0x14 +#define MAX98925_MAP4 0x15 +#define MAX98925_MAP5 0x16 +#define MAX98925_MAP6 0x17 +#define MAX98925_MAP7 0x18 +#define MAX98925_MAP8 0x19 +#define MAX98925_DAI_CLK_MODE1 0x1A +#define MAX98925_DAI_CLK_MODE2 0x1B +#define MAX98925_DAI_CLK_DIV_M_MSBS 0x1C +#define MAX98925_DAI_CLK_DIV_M_LSBS 0x1D +#define MAX98925_DAI_CLK_DIV_N_MSBS 0x1E +#define MAX98925_DAI_CLK_DIV_N_LSBS 0x1F +#define MAX98925_FORMAT 0x20 +#define MAX98925_TDM_SLOT_SELECT 0x21 +#define MAX98925_DOUT_CFG_VMON 0x22 +#define MAX98925_DOUT_CFG_IMON 0x23 +#define MAX98925_DOUT_CFG_VBAT 0x24 +#define MAX98925_DOUT_CFG_VBST 0x25 +#define MAX98925_DOUT_CFG_FLAG 0x26 +#define MAX98925_DOUT_HIZ_CFG1 0x27 +#define MAX98925_DOUT_HIZ_CFG2 0x28 +#define MAX98925_DOUT_HIZ_CFG3 0x29 +#define MAX98925_DOUT_HIZ_CFG4 0x2A +#define MAX98925_DOUT_DRV_STRENGTH 0x2B +#define MAX98925_FILTERS 0x2C +#define MAX98925_GAIN 0x2D +#define MAX98925_GAIN_RAMPING 0x2E +#define MAX98925_SPK_AMP 0x2F +#define MAX98925_THRESHOLD 0x30 +#define MAX98925_ALC_ATTACK 0x31 +#define MAX98925_ALC_ATTEN_RLS 0x32 +#define MAX98925_ALC_HOLD_RLS 0x33 +#define MAX98925_ALC_CONFIGURATION 0x34 +#define MAX98925_BOOST_CONVERTER 0x35 +#define MAX98925_BLOCK_ENABLE 0x36 +#define MAX98925_CONFIGURATION 0x37 +#define MAX98925_GLOBAL_ENABLE 0x38 +#define MAX98925_BOOST_LIMITER 0x3A +#define MAX98925_REV_VERSION 0xFF + +#define MAX98925_REG_CNT (MAX98925_R03A_BOOST_LIMITER+1) + +/* MAX98925 Register Bit Fields */ + +/* MAX98925_R002_LIVE_STATUS0 */ +#define M98925_THERMWARN_STATUS_MASK (1<<3) +#define M98925_THERMWARN_STATUS_SHIFT 3 +#define M98925_THERMWARN_STATUS_WIDTH 1 +#define M98925_THERMSHDN_STATUS_MASK (1<<1) +#define M98925_THERMSHDN_STATUS_SHIFT 1 +#define M98925_THERMSHDN_STATUS_WIDTH 1 + +/* MAX98925_R003_LIVE_STATUS1 */ +#define M98925_SPKCURNT_STATUS_MASK (1<<5) +#define M98925_SPKCURNT_STATUS_SHIFT 5 +#define M98925_SPKCURNT_STATUS_WIDTH 1 +#define M98925_WATCHFAIL_STATUS_MASK (1<<4) +#define M98925_WATCHFAIL_STATUS_SHIFT 4 +#define M98925_WATCHFAIL_STATUS_WIDTH 1 +#define M98925_ALCINFH_STATUS_MASK (1<<3) +#define M98925_ALCINFH_STATUS_SHIFT 3 +#define M98925_ALCINFH_STATUS_WIDTH 1 +#define M98925_ALCACT_STATUS_MASK (1<<2) +#define M98925_ALCACT_STATUS_SHIFT 2 +#define M98925_ALCACT_STATUS_WIDTH 1 +#define M98925_ALCMUT_STATUS_MASK (1<<1) +#define M98925_ALCMUT_STATUS_SHIFT 1 +#define M98925_ALCMUT_STATUS_WIDTH 1 +#define M98925_ACLP_STATUS_MASK (1<<0) +#define M98925_ACLP_STATUS_SHIFT 0 +#define M98925_ACLP_STATUS_WIDTH 1 + +/* MAX98925_R004_LIVE_STATUS2 */ +#define M98925_SLOTOVRN_STATUS_MASK (1<<6) +#define M98925_SLOTOVRN_STATUS_SHIFT 6 +#define M98925_SLOTOVRN_STATUS_WIDTH 1 +#define M98925_INVALSLOT_STATUS_MASK (1<<5) +#define M98925_INVALSLOT_STATUS_SHIFT 5 +#define M98925_INVALSLOT_STATUS_WIDTH 1 +#define M98925_SLOTCNFLT_STATUS_MASK (1<<4) +#define M98925_SLOTCNFLT_STATUS_SHIFT 4 +#define M98925_SLOTCNFLT_STATUS_WIDTH 1 +#define M98925_VBSTOVFL_STATUS_MASK (1<<3) +#define M98925_VBSTOVFL_STATUS_SHIFT 3 +#define M98925_VBSTOVFL_STATUS_WIDTH 1 +#define M98925_VBATOVFL_STATUS_MASK (1<<2) +#define M98925_VBATOVFL_STATUS_SHIFT 2 +#define M98925_VBATOVFL_STATUS_WIDTH 1 +#define M98925_IMONOVFL_STATUS_MASK (1<<1) +#define M98925_IMONOVFL_STATUS_SHIFT 1 +#define M98925_IMONOVFL_STATUS_WIDTH 1 +#define M98925_VMONOVFL_STATUS_MASK (1<<0) +#define M98925_VMONOVFL_STATUS_SHIFT 0 +#define M98925_VMONOVFL_STATUS_WIDTH 1 + +/* MAX98925_R005_STATE0 */ +#define M98925_THERMWARN_END_STATE_MASK (1<<3) +#define M98925_THERMWARN_END_STATE_SHIFT 3 +#define M98925_THERMWARN_END_STATE_WIDTH 1 +#define M98925_THERMWARN_BGN_STATE_MASK (1<<2) +#define M98925_THERMWARN_BGN_STATE_SHIFT 1 +#define M98925_THERMWARN_BGN_STATE_WIDTH 1 +#define M98925_THERMSHDN_END_STATE_MASK (1<<1) +#define M98925_THERMSHDN_END_STATE_SHIFT 1 +#define M98925_THERMSHDN_END_STATE_WIDTH 1 +#define M98925_THERMSHDN_BGN_STATE_MASK (1<<0) +#define M98925_THERMSHDN_BGN_STATE_SHIFT 0 +#define M98925_THERMSHDN_BGN_STATE_WIDTH 1 + +/* MAX98925_R006_STATE1 */ +#define M98925_SPRCURNT_STATE_MASK (1<<5) +#define M98925_SPRCURNT_STATE_SHIFT 5 +#define M98925_SPRCURNT_STATE_WIDTH 1 +#define M98925_WATCHFAIL_STATE_MASK (1<<4) +#define M98925_WATCHFAIL_STATE_SHIFT 4 +#define M98925_WATCHFAIL_STATE_WIDTH 1 +#define M98925_ALCINFH_STATE_MASK (1<<3) +#define M98925_ALCINFH_STATE_SHIFT 3 +#define M98925_ALCINFH_STATE_WIDTH 1 +#define M98925_ALCACT_STATE_MASK (1<<2) +#define M98925_ALCACT_STATE_SHIFT 2 +#define M98925_ALCACT_STATE_WIDTH 1 +#define M98925_ALCMUT_STATE_MASK (1<<1) +#define M98925_ALCMUT_STATE_SHIFT 1 +#define M98925_ALCMUT_STATE_WIDTH 1 +#define M98925_ALCP_STATE_MASK (1<<0) +#define M98925_ALCP_STATE_SHIFT 0 +#define M98925_ALCP_STATE_WIDTH 1 + +/* MAX98925_R007_STATE2 */ +#define M98925_SLOTOVRN_STATE_MASK (1<<6) +#define M98925_SLOTOVRN_STATE_SHIFT 6 +#define M98925_SLOTOVRN_STATE_WIDTH 1 +#define M98925_INVALSLOT_STATE_MASK (1<<5) +#define M98925_INVALSLOT_STATE_SHIFT 5 +#define M98925_INVALSLOT_STATE_WIDTH 1 +#define M98925_SLOTCNFLT_STATE_MASK (1<<4) +#define M98925_SLOTCNFLT_STATE_SHIFT 4 +#define M98925_SLOTCNFLT_STATE_WIDTH 1 +#define M98925_VBSTOVFL_STATE_MASK (1<<3) +#define M98925_VBSTOVFL_STATE_SHIFT 3 +#define M98925_VBSTOVFL_STATE_WIDTH 1 +#define M98925_VBATOVFL_STATE_MASK (1<<2) +#define M98925_VBATOVFL_STATE_SHIFT 2 +#define M98925_VBATOVFL_STATE_WIDTH 1 +#define M98925_IMONOVFL_STATE_MASK (1<<1) +#define M98925_IMONOVFL_STATE_SHIFT 1 +#define M98925_IMONOVFL_STATE_WIDTH 1 +#define M98925_VMONOVFL_STATE_MASK (1<<0) +#define M98925_VMONOVFL_STATE_SHIFT 0 +#define M98925_VMONOVFL_STATE_WIDTH 1 + +/* MAX98925_R008_FLAG0 */ +#define M98925_THERMWARN_END_FLAG_MASK (1<<3) +#define M98925_THERMWARN_END_FLAG_SHIFT 3 +#define M98925_THERMWARN_END_FLAG_WIDTH 1 +#define M98925_THERMWARN_BGN_FLAG_MASK (1<<2) +#define M98925_THERMWARN_BGN_FLAG_SHIFT 2 +#define M98925_THERMWARN_BGN_FLAG_WIDTH 1 +#define M98925_THERMSHDN_END_FLAG_MASK (1<<1) +#define M98925_THERMSHDN_END_FLAG_SHIFT 1 +#define M98925_THERMSHDN_END_FLAG_WIDTH 1 +#define M98925_THERMSHDN_BGN_FLAG_MASK (1<<0) +#define M98925_THERMSHDN_BGN_FLAG_SHIFT 0 +#define M98925_THERMSHDN_BGN_FLAG_WIDTH 1 + +/* MAX98925_R009_FLAG1 */ +#define M98925_SPKCURNT_FLAG_MASK (1<<5) +#define M98925_SPKCURNT_FLAG_SHIFT 5 +#define M98925_SPKCURNT_FLAG_WIDTH 1 +#define M98925_WATCHFAIL_FLAG_MASK (1<<4) +#define M98925_WATCHFAIL_FLAG_SHIFT 4 +#define M98925_WATCHFAIL_FLAG_WIDTH 1 +#define M98925_ALCINFH_FLAG_MASK (1<<3) +#define M98925_ALCINFH_FLAG_SHIFT 3 +#define M98925_ALCINFH_FLAG_WIDTH 1 +#define M98925_ALCACT_FLAG_MASK (1<<2) +#define M98925_ALCACT_FLAG_SHIFT 2 +#define M98925_ALCACT_FLAG_WIDTH 1 +#define M98925_ALCMUT_FLAG_MASK (1<<1) +#define M98925_ALCMUT_FLAG_SHIFT 1 +#define M98925_ALCMUT_FLAG_WIDTH 1 +#define M98925_ALCP_FLAG_MASK (1<<0) +#define M98925_ALCP_FLAG_SHIFT 0 +#define M98925_ALCP_FLAG_WIDTH 1 + +/* MAX98925_R00A_FLAG2 */ +#define M98925_SLOTOVRN_FLAG_MASK (1<<6) +#define M98925_SLOTOVRN_FLAG_SHIFT 6 +#define M98925_SLOTOVRN_FLAG_WIDTH 1 +#define M98925_INVALSLOT_FLAG_MASK (1<<5) +#define M98925_INVALSLOT_FLAG_SHIFT 5 +#define M98925_INVALSLOT_FLAG_WIDTH 1 +#define M98925_SLOTCNFLT_FLAG_MASK (1<<4) +#define M98925_SLOTCNFLT_FLAG_SHIFT 4 +#define M98925_SLOTCNFLT_FLAG_WIDTH 1 +#define M98925_VBSTOVFL_FLAG_MASK (1<<3) +#define M98925_VBSTOVFL_FLAG_SHIFT 3 +#define M98925_VBSTOVFL_FLAG_WIDTH 1 +#define M98925_VBATOVFL_FLAG_MASK (1<<2) +#define M98925_VBATOVFL_FLAG_SHIFT 2 +#define M98925_VBATOVFL_FLAG_WIDTH 1 +#define M98925_IMONOVFL_FLAG_MASK (1<<1) +#define M98925_IMONOVFL_FLAG_SHIFT 1 +#define M98925_IMONOVFL_FLAG_WIDTH 1 +#define M98925_VMONOVFL_FLAG_MASK (1<<0) +#define M98925_VMONOVFL_FLAG_SHIFT 0 +#define M98925_VMONOVFL_FLAG_WIDTH 1 + +/* MAX98925_R00B_IRQ_ENABLE0 */ +#define M98925_THERMWARN_END_EN_MASK (1<<3) +#define M98925_THERMWARN_END_EN_SHIFT 3 +#define M98925_THERMWARN_END_EN_WIDTH 1 +#define M98925_THERMWARN_BGN_EN_MASK (1<<2) +#define M98925_THERMWARN_BGN_EN_SHIFT 2 +#define M98925_THERMWARN_BGN_EN_WIDTH 1 +#define M98925_THERMSHDN_END_EN_MASK (1<<1) +#define M98925_THERMSHDN_END_EN_SHIFT 1 +#define M98925_THERMSHDN_END_EN_WIDTH 1 +#define M98925_THERMSHDN_BGN_EN_MASK (1<<0) +#define M98925_THERMSHDN_BGN_EN_SHIFT 0 +#define M98925_THERMSHDN_BGN_EN_WIDTH 1 + +/* MAX98925_R00C_IRQ_ENABLE1 */ +#define M98925_SPKCURNT_EN_MASK (1<<5) +#define M98925_SPKCURNT_EN_SHIFT 5 +#define M98925_SPKCURNT_EN_WIDTH 1 +#define M98925_WATCHFAIL_EN_MASK (1<<4) +#define M98925_WATCHFAIL_EN_SHIFT 4 +#define M98925_WATCHFAIL_EN_WIDTH 1 +#define M98925_ALCINFH_EN_MASK (1<<3) +#define M98925_ALCINFH_EN_SHIFT 3 +#define M98925_ALCINFH_EN_WIDTH 1 +#define M98925_ALCACT_EN_MASK (1<<2) +#define M98925_ALCACT_EN_SHIFT 2 +#define M98925_ALCACT_EN_WIDTH 1 +#define M98925_ALCMUT_EN_MASK (1<<1) +#define M98925_ALCMUT_EN_SHIFT 1 +#define M98925_ALCMUT_EN_WIDTH 1 +#define M98925_ALCP_EN_MASK (1<<0) +#define M98925_ALCP_EN_SHIFT 0 +#define M98925_ALCP_EN_WIDTH 1 + +/* MAX98925_R00D_IRQ_ENABLE2 */ +#define M98925_SLOTOVRN_EN_MASK (1<<6) +#define M98925_SLOTOVRN_EN_SHIFT 6 +#define M98925_SLOTOVRN_EN_WIDTH 1 +#define M98925_INVALSLOT_EN_MASK (1<<5) +#define M98925_INVALSLOT_EN_SHIFT 5 +#define M98925_INVALSLOT_EN_WIDTH 1 +#define M98925_SLOTCNFLT_EN_MASK (1<<4) +#define M98925_SLOTCNFLT_EN_SHIFT 4 +#define M98925_SLOTCNFLT_EN_WIDTH 1 +#define M98925_VBSTOVFL_EN_MASK (1<<3) +#define M98925_VBSTOVFL_EN_SHIFT 3 +#define M98925_VBSTOVFL_EN_WIDTH 1 +#define M98925_VBATOVFL_EN_MASK (1<<2) +#define M98925_VBATOVFL_EN_SHIFT 2 +#define M98925_VBATOVFL_EN_WIDTH 1 +#define M98925_IMONOVFL_EN_MASK (1<<1) +#define M98925_IMONOVFL_EN_SHIFT 1 +#define M98925_IMONOVFL_EN_WIDTH 1 +#define M98925_VMONOVFL_EN_MASK (1<<0) +#define M98925_VMONOVFL_EN_SHIFT 0 +#define M98925_VMONOVFL_EN_WIDTH 1 + +/* MAX98925_R00E_IRQ_CLEAR0 */ +#define M98925_THERMWARN_END_CLR_MASK (1<<3) +#define M98925_THERMWARN_END_CLR_SHIFT 3 +#define M98925_THERMWARN_END_CLR_WIDTH 1 +#define M98925_THERMWARN_BGN_CLR_MASK (1<<2) +#define M98925_THERMWARN_BGN_CLR_SHIFT 2 +#define M98925_THERMWARN_BGN_CLR_WIDTH 1 +#define M98925_THERMSHDN_END_CLR_MASK (1<<1) +#define M98925_THERMSHDN_END_CLR_SHIFT 1 +#define M98925_THERMSHDN_END_CLR_WIDTH 1 +#define M98925_THERMSHDN_BGN_CLR_MASK (1<<0) +#define M98925_THERMSHDN_BGN_CLR_SHIFT 0 +#define M98925_THERMSHDN_BGN_CLR_WIDTH 1 + +/* MAX98925_R00F_IRQ_CLEAR1 */ +#define M98925_SPKCURNT_CLR_MASK (1<<5) +#define M98925_SPKCURNT_CLR_SHIFT 5 +#define M98925_SPKCURNT_CLR_WIDTH 1 +#define M98925_WATCHFAIL_CLR_MASK (1<<4) +#define M98925_WATCHFAIL_CLR_SHIFT 4 +#define M98925_WATCHFAIL_CLR_WIDTH 1 +#define M98925_ALCINFH_CLR_MASK (1<<3) +#define M98925_ALCINFH_CLR_SHIFT 3 +#define M98925_ALCINFH_CLR_WIDTH 1 +#define M98925_ALCACT_CLR_MASK (1<<2) +#define M98925_ALCACT_CLR_SHIFT 2 +#define M98925_ALCACT_CLR_WIDTH 1 +#define M98925_ALCMUT_CLR_MASK (1<<1) +#define M98925_ALCMUT_CLR_SHIFT 1 +#define M98925_ALCMUT_CLR_WIDTH 1 +#define M98925_ALCP_CLR_MASK (1<<0) +#define M98925_ALCP_CLR_SHIFT 0 +#define M98925_ALCP_CLR_WIDTH 1 + +/* MAX98925_R010_IRQ_CLEAR2 */ +#define M98925_SLOTOVRN_CLR_MASK (1<<6) +#define M98925_SLOTOVRN_CLR_SHIFT 6 +#define M98925_SLOTOVRN_CLR_WIDTH 1 +#define M98925_INVALSLOT_CLR_MASK (1<<5) +#define M98925_INVALSLOT_CLR_SHIFT 5 +#define M98925_INVALSLOT_CLR_WIDTH 1 +#define M98925_SLOTCNFLT_CLR_MASK (1<<4) +#define M98925_SLOTCNFLT_CLR_SHIFT 4 +#define M98925_SLOTCNFLT_CLR_WIDTH 1 +#define M98925_VBSTOVFL_CLR_MASK (1<<3) +#define M98925_VBSTOVFL_CLR_SHIFT 3 +#define M98925_VBSTOVFL_CLR_WIDTH 1 +#define M98925_VBATOVFL_CLR_MASK (1<<2) +#define M98925_VBATOVFL_CLR_SHIFT 2 +#define M98925_VBATOVFL_CLR_WIDTH 1 +#define M98925_IMONOVFL_CLR_MASK (1<<1) +#define M98925_IMONOVFL_CLR_SHIFT 1 +#define M98925_IMONOVFL_CLR_WIDTH 1 +#define M98925_VMONOVFL_CLR_MASK (1<<0) +#define M98925_VMONOVFL_CLR_SHIFT 0 +#define M98925_VMONOVFL_CLR_WIDTH 1 + +/* MAX98925_R011_MAP0 */ +#define M98925_ER_THERMWARN_EN_MASK (1<<7) +#define M98925_ER_THERMWARN_EN_SHIFT 7 +#define M98925_ER_THERMWARN_EN_WIDTH 1 +#define M98925_ER_THERMWARN_MAP_MASK (0x07<<4) +#define M98925_ER_THERMWARN_MAP_SHIFT 4 +#define M98925_ER_THERMWARN_MAP_WIDTH 3 + +/* MAX98925_R012_MAP1 */ +#define M98925_ER_ALCMUT_EN_MASK (1<<7) +#define M98925_ER_ALCMUT_EN_SHIFT 7 +#define M98925_ER_ALCMUT_EN_WIDTH 1 +#define M98925_ER_ALCMUT_MAP_MASK (0x07<<4) +#define M98925_ER_ALCMUT_MAP_SHIFT 4 +#define M98925_ER_ALCMUT_MAP_WIDTH 3 +#define M98925_ER_ALCP_EN_MASK (1<<3) +#define M98925_ER_ALCP_EN_SHIFT 3 +#define M98925_ER_ALCP_EN_WIDTH 1 +#define M98925_ER_ALCP_MAP_MASK (0x07<<0) +#define M98925_ER_ALCP_MAP_SHIFT 0 +#define M98925_ER_ALCP_MAP_WIDTH 3 + +/* MAX98925_R013_MAP2 */ +#define M98925_ER_ALCINFH_EN_MASK (1<<7) +#define M98925_ER_ALCINFH_EN_SHIFT 7 +#define M98925_ER_ALCINFH_EN_WIDTH 1 +#define M98925_ER_ALCINFH_MAP_MASK (0x07<<4) +#define M98925_ER_ALCINFH_MAP_SHIFT 4 +#define M98925_ER_ALCINFH_MAP_WIDTH 3 +#define M98925_ER_ALCACT_EN_MASK (1<<3) +#define M98925_ER_ALCACT_EN_SHIFT 3 +#define M98925_ER_ALCACT_EN_WIDTH 1 +#define M98925_ER_ALCACT_MAP_MASK (0x07<<0) +#define M98925_ER_ALCACT_MAP_SHIFT 0 +#define M98925_ER_ALCACT_MAP_WIDTH 3 + +/* MAX98925_R014_MAP3 */ +#define M98925_ER_SPKCURNT_EN_MASK (1<<7) +#define M98925_ER_SPKCURNT_EN_SHIFT 7 +#define M98925_ER_SPKCURNT_EN_WIDTH 1 +#define M98925_ER_SPKCURNT_MAP_MASK (0x07<<4) +#define M98925_ER_SPKCURNT_MAP_SHIFT 4 +#define M98925_ER_SPKCURNT_MAP_WIDTH 3 + +/* MAX98925_R015_MAP4 */ +/* RESERVED */ + +/* MAX98925_R016_MAP5 */ +#define M98925_ER_IMONOVFL_EN_MASK (1<<7) +#define M98925_ER_IMONOVFL_EN_SHIFT 7 +#define M98925_ER_IMONOVFL_EN_WIDTH 1 +#define M98925_ER_IMONOVFL_MAP_MASK (0x07<<4) +#define M98925_ER_IMONOVFL_MAP_SHIFT 4 +#define M98925_ER_IMONOVFL_MAP_WIDTH 3 +#define M98925_ER_VMONOVFL_EN_MASK (1<<3) +#define M98925_ER_VMONOVFL_EN_SHIFT 3 +#define M98925_ER_VMONOVFL_EN_WIDTH 1 +#define M98925_ER_VMONOVFL_MAP_MASK (0x07<<0) +#define M98925_ER_VMONOVFL_MAP_SHIFT 0 +#define M98925_ER_VMONOVFL_MAP_WIDTH 3 + +/* MAX98925_R017_MAP6 */ +#define M98925_ER_VBSTOVFL_EN_MASK (1<<7) +#define M98925_ER_VBSTOVFL_EN_SHIFT 7 +#define M98925_ER_VBSTOVFL_EN_WIDTH 1 +#define M98925_ER_VBSTOVFL_MAP_MASK (0x07<<4) +#define M98925_ER_VBSTOVFL_MAP_SHIFT 4 +#define M98925_ER_VBSTOVFL_MAP_WIDTH 3 +#define M98925_ER_VBATOVFL_EN_MASK (1<<3) +#define M98925_ER_VBATOVFL_EN_SHIFT 3 +#define M98925_ER_VBATOVFL_EN_WIDTH 1 +#define M98925_ER_VBATOVFL_MAP_MASK (0x07<<0) +#define M98925_ER_VBATOVFL_MAP_SHIFT 0 +#define M98925_ER_VBATOVFL_MAP_WIDTH 3 + +/* MAX98925_R018_MAP7 */ +#define M98925_ER_INVALSLOT_EN_MASK (1<<7) +#define M98925_ER_INVALSLOT_EN_SHIFT 7 +#define M98925_ER_INVALSLOT_EN_WIDTH 1 +#define M98925_ER_INVALSLOT_MAP_MASK (0x07<<4) +#define M98925_ER_INVALSLOT_MAP_SHIFT 4 +#define M98925_ER_INVALSLOT_MAP_WIDTH 3 +#define M98925_ER_SLOTCNFLT_EN_MASK (1<<3) +#define M98925_ER_SLOTCNFLT_EN_SHIFT 3 +#define M98925_ER_SLOTCNFLT_EN_WIDTH 1 +#define M98925_ER_SLOTCNFLT_MAP_MASK (0x07<<0) +#define M98925_ER_SLOTCNFLT_MAP_SHIFT 0 +#define M98925_ER_SLOTCNFLT_MAP_WIDTH 3 + +/* MAX98925_R019_MAP8 */ +#define M98925_ER_SLOTOVRN_EN_MASK (1<<3) +#define M98925_ER_SLOTOVRN_EN_SHIFT 3 +#define M98925_ER_SLOTOVRN_EN_WIDTH 1 +#define M98925_ER_SLOTOVRN_MAP_MASK (0x07<<0) +#define M98925_ER_SLOTOVRN_MAP_SHIFT 0 +#define M98925_ER_SLOTOVRN_MAP_WIDTH 3 + +/* MAX98925_R01A_DAI_CLK_MODE1 */ +#define M98925_DAI_CLK_SOURCE_MASK (1<<6) +#define M98925_DAI_CLK_SOURCE_SHIFT 6 +#define M98925_DAI_CLK_SOURCE_WIDTH 1 +#define M98925_MDLL_MULT_MASK (0x0F<<0) +#define M98925_MDLL_MULT_SHIFT 0 +#define M98925_MDLL_MULT_WIDTH 4 + +#define M98925_MDLL_MULT_MCLKx8 6 +#define M98925_MDLL_MULT_MCLKx16 8 + +/* MAX98925_R01B_DAI_CLK_MODE2 */ +#define M98925_DAI_SR_MASK (0x0F<<4) +#define M98925_DAI_SR_SHIFT 4 +#define M98925_DAI_SR_WIDTH 4 +#define M98925_DAI_MAS_MASK (1<<3) +#define M98925_DAI_MAS_SHIFT 3 +#define M98925_DAI_MAS_WIDTH 1 +#define M98925_DAI_BSEL_MASK (0x07<<0) +#define M98925_DAI_BSEL_SHIFT 0 +#define M98925_DAI_BSEL_WIDTH 3 + +#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT) +#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT) + +/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */ +#define M98925_DAI_M_MSBS_MASK (0xFF<<0) +#define M98925_DAI_M_MSBS_SHIFT 0 +#define M98925_DAI_M_MSBS_WIDTH 8 + +/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */ +#define M98925_DAI_M_LSBS_MASK (0xFF<<0) +#define M98925_DAI_M_LSBS_SHIFT 0 +#define M98925_DAI_M_LSBS_WIDTH 8 + +/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */ +#define M98925_DAI_N_MSBS_MASK (0x7F<<0) +#define M98925_DAI_N_MSBS_SHIFT 0 +#define M98925_DAI_N_MSBS_WIDTH 7 + +/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */ +#define M98925_DAI_N_LSBS_MASK (0xFF<<0) +#define M98925_DAI_N_LSBS_SHIFT 0 +#define M98925_DAI_N_LSBS_WIDTH 8 + +/* MAX98925_R020_FORMAT */ +#define M98925_DAI_CHANSZ_MASK (0x03<<6) +#define M98925_DAI_CHANSZ_SHIFT 6 +#define M98925_DAI_CHANSZ_WIDTH 2 +#define M98925_DAI_EXTBCLK_HIZ_MASK (1<<4) +#define M98925_DAI_EXTBCLK_HIZ_SHIFT 4 +#define M98925_DAI_EXTBCLK_HIZ_WIDTH 1 +#define M98925_DAI_WCI_MASK (1<<3) +#define M98925_DAI_WCI_SHIFT 3 +#define M98925_DAI_WCI_WIDTH 1 +#define M98925_DAI_BCI_MASK (1<<2) +#define M98925_DAI_BCI_SHIFT 2 +#define M98925_DAI_BCI_WIDTH 1 +#define M98925_DAI_DLY_MASK (1<<1) +#define M98925_DAI_DLY_SHIFT 1 +#define M98925_DAI_DLY_WIDTH 1 +#define M98925_DAI_TDM_MASK (1<<0) +#define M98925_DAI_TDM_SHIFT 0 +#define M98925_DAI_TDM_WIDTH 1 + +#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT) +#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT) +#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT) + +/* MAX98925_R021_TDM_SLOT_SELECT */ +#define M98925_DAI_DO_EN_MASK (1<<7) +#define M98925_DAI_DO_EN_SHIFT 7 +#define M98925_DAI_DO_EN_WIDTH 1 +#define M98925_DAI_DIN_EN_MASK (1<<6) +#define M98925_DAI_DIN_EN_SHIFT 6 +#define M98925_DAI_DIN_EN_WIDTH 1 +#define M98925_DAI_INR_SOURCE_MASK (0x07<<3) +#define M98925_DAI_INR_SOURCE_SHIFT 3 +#define M98925_DAI_INR_SOURCE_WIDTH 3 +#define M98925_DAI_INL_SOURCE_MASK (0x07<<0) +#define M98925_DAI_INL_SOURCE_SHIFT 0 +#define M98925_DAI_INL_SOURCE_WIDTH 3 + +/* MAX98925_R022_DOUT_CFG_VMON */ +#define M98925_DAI_VMON_EN_MASK (1<<5) +#define M98925_DAI_VMON_EN_SHIFT 5 +#define M98925_DAI_VMON_EN_WIDTH 1 +#define M98925_DAI_VMON_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VMON_SLOT_SHIFT 0 +#define M98925_DAI_VMON_SLOT_WIDTH 5 + +#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT) +#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT) + +/* MAX98925_R023_DOUT_CFG_IMON */ +#define M98925_DAI_IMON_EN_MASK (1<<5) +#define M98925_DAI_IMON_EN_SHIFT 5 +#define M98925_DAI_IMON_EN_WIDTH 1 +#define M98925_DAI_IMON_SLOT_MASK (0x1F<<0) +#define M98925_DAI_IMON_SLOT_SHIFT 0 +#define M98925_DAI_IMON_SLOT_WIDTH 5 + +#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT) +#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT) + +/* MAX98925_R024_DOUT_CFG_VBAT */ +#define M98925_DAI_VBAT_EN_MASK (1<<5) +#define M98925_DAI_VBAT_EN_SHIFT 5 +#define M98925_DAI_VBAT_EN_WIDTH 1 +#define M98925_DAI_VBAT_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VBAT_SLOT_SHIFT 0 +#define M98925_DAI_VBAT_SLOT_WIDTH 5 + +/* MAX98925_R025_DOUT_CFG_VBST */ +#define M98925_DAI_VBST_EN_MASK (1<<5) +#define M98925_DAI_VBST_EN_SHIFT 5 +#define M98925_DAI_VBST_EN_WIDTH 1 +#define M98925_DAI_VBST_SLOT_MASK (0x1F<<0) +#define M98925_DAI_VBST_SLOT_SHIFT 0 +#define M98925_DAI_VBST_SLOT_WIDTH 5 + +/* MAX98925_R026_DOUT_CFG_FLAG */ +#define M98925_DAI_FLAG_EN_MASK (1<<5) +#define M98925_DAI_FLAG_EN_SHIFT 5 +#define M98925_DAI_FLAG_EN_WIDTH 1 +#define M98925_DAI_FLAG_SLOT_MASK (0x1F<<0) +#define M98925_DAI_FLAG_SLOT_SHIFT 0 +#define M98925_DAI_FLAG_SLOT_WIDTH 5 + +/* MAX98925_R027_DOUT_HIZ_CFG1 */ +#define M98925_DAI_SLOT_HIZ_CFG1_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH 8 + +/* MAX98925_R028_DOUT_HIZ_CFG2 */ +#define M98925_DAI_SLOT_HIZ_CFG2_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH 8 + +/* MAX98925_R029_DOUT_HIZ_CFG3 */ +#define M98925_DAI_SLOT_HIZ_CFG3_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH 8 + +/* MAX98925_R02A_DOUT_HIZ_CFG4 */ +#define M98925_DAI_SLOT_HIZ_CFG4_MASK (0xFF<<0) +#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT 0 +#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH 8 + +/* MAX98925_R02B_DOUT_DRV_STRENGTH */ +#define M98925_DAI_OUT_DRIVE_MASK (0x03<<0) +#define M98925_DAI_OUT_DRIVE_SHIFT 0 +#define M98925_DAI_OUT_DRIVE_WIDTH 2 + +/* MAX98925_R02C_FILTERS */ +#define M98925_ADC_DITHER_EN_MASK (1<<7) +#define M98925_ADC_DITHER_EN_SHIFT 7 +#define M98925_ADC_DITHER_EN_WIDTH 1 +#define M98925_IV_DCB_EN_MASK (1<<6) +#define M98925_IV_DCB_EN_SHIFT 6 +#define M98925_IV_DCB_EN_WIDTH 1 +#define M98925_DAC_DITHER_EN_MASK (1<<4) +#define M98925_DAC_DITHER_EN_SHIFT 4 +#define M98925_DAC_DITHER_EN_WIDTH 1 +#define M98925_DAC_FILTER_MODE_MASK (1<<3) +#define M98925_DAC_FILTER_MODE_SHIFT 3 +#define M98925_DAC_FILTER_MODE_WIDTH 1 +#define M98925_DAC_HPF_MASK (0x07<<0) +#define M98925_DAC_HPF_SHIFT 0 +#define M98925_DAC_HPF_WIDTH 3 +#define M98925_DAC_HPF_DISABLE (0 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_DC_BLOCK (1 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_100 (2 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_200 (3 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_400 (4 << M98925_DAC_HPF_SHIFT) +#define M98925_DAC_HPF_EN_800 (5 << M98925_DAC_HPF_SHIFT) + +/* MAX98925_R02D_GAIN */ +#define M98925_DAC_IN_SEL_MASK (0x03<<5) +#define M98925_DAC_IN_SEL_SHIFT 5 +#define M98925_DAC_IN_SEL_WIDTH 2 +#define M98925_SPK_GAIN_MASK (0x1F<<0) +#define M98925_SPK_GAIN_SHIFT 0 +#define M98925_SPK_GAIN_WIDTH 5 + +#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT) +#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT) + +/* MAX98925_R02E_GAIN_RAMPING */ +#define M98925_SPK_RMP_EN_MASK (1<<1) +#define M98925_SPK_RMP_EN_SHIFT 1 +#define M98925_SPK_RMP_EN_WIDTH 1 +#define M98925_SPK_ZCD_EN_MASK (1<<0) +#define M98925_SPK_ZCD_EN_SHIFT 0 +#define M98925_SPK_ZCD_EN_WIDTH 1 + +/* MAX98925_R02F_SPK_AMP */ +#define M98925_SPK_MODE_MASK (1<<0) +#define M98925_SPK_MODE_SHIFT 0 +#define M98925_SPK_MODE_WIDTH 1 + +/* MAX98925_R030_THRESHOLD */ +#define M98925_ALC_EN_MASK (1<<5) +#define M98925_ALC_EN_SHIFT 5 +#define M98925_ALC_EN_WIDTH 1 +#define M98925_ALC_TH_MASK (0x1F<<0) +#define M98925_ALC_TH_SHIFT 0 +#define M98925_ALC_TH_WIDTH 5 + +/* MAX98925_R031_ALC_ATTACK */ +#define M98925_ALC_ATK_STEP_MASK (0x0F<<4) +#define M98925_ALC_ATK_STEP_SHIFT 4 +#define M98925_ALC_ATK_STEP_WIDTH 4 +#define M98925_ALC_ATK_RATE_MASK (0x7<<0) +#define M98925_ALC_ATK_RATE_SHIFT 0 +#define M98925_ALC_ATK_RATE_WIDTH 3 + +/* MAX98925_R032_ALC_ATTEN_RLS */ +#define M98925_ALC_MAX_ATTEN_MASK (0x0F<<4) +#define M98925_ALC_MAX_ATTEN_SHIFT 4 +#define M98925_ALC_MAX_ATTEN_WIDTH 4 +#define M98925_ALC_RLS_RATE_MASK (0x7<<0) +#define M98925_ALC_RLS_RATE_SHIFT 0 +#define M98925_ALC_RLS_RATE_WIDTH 3 + +/* MAX98925_R033_ALC_HOLD_RLS */ +#define M98925_ALC_RLS_TGR_MASK (1<<0) +#define M98925_ALC_RLS_TGR_SHIFT 0 +#define M98925_ALC_RLS_TGR_WIDTH 1 + +/* MAX98925_R034_ALC_CONFIGURATION */ +#define M98925_ALC_MUTE_EN_MASK (1<<7) +#define M98925_ALC_MUTE_EN_SHIFT 7 +#define M98925_ALC_MUTE_EN_WIDTH 1 +#define M98925_ALC_MUTE_DLY_MASK (0x07<<4) +#define M98925_ALC_MUTE_DLY_SHIFT 4 +#define M98925_ALC_MUTE_DLY_WIDTH 3 +#define M98925_ALC_RLS_DBT_MASK (0x07<<0) +#define M98925_ALC_RLS_DBT_SHIFT 0 +#define M98925_ALC_RLS_DBT_WIDTH 3 + +/* MAX98925_R035_BOOST_CONVERTER */ +#define M98925_BST_SYNC_MASK (1<<7) +#define M98925_BST_SYNC_SHIFT 7 +#define M98925_BST_SYNC_WIDTH 1 +#define M98925_BST_PHASE_MASK (0x03<<4) +#define M98925_BST_PHASE_SHIFT 4 +#define M98925_BST_PHASE_WIDTH 2 +#define M98925_BST_SKIP_MODE_MASK (0x03<<0) +#define M98925_BST_SKIP_MODE_SHIFT 0 +#define M98925_BST_SKIP_MODE_WIDTH 2 + +/* MAX98925_R036_BLOCK_ENABLE */ +#define M98925_BST_EN_MASK (1<<7) +#define M98925_BST_EN_SHIFT 7 +#define M98925_BST_EN_WIDTH 1 +#define M98925_WATCH_EN_MASK (1<<6) +#define M98925_WATCH_EN_SHIFT 6 +#define M98925_WATCH_EN_WIDTH 1 +#define M98925_CLKMON_EN_MASK (1<<5) +#define M98925_CLKMON_EN_SHIFT 5 +#define M98925_CLKMON_EN_WIDTH 1 +#define M98925_SPK_EN_MASK (1<<4) +#define M98925_SPK_EN_SHIFT 4 +#define M98925_SPK_EN_WIDTH 1 +#define M98925_ADC_VBST_EN_MASK (1<<3) +#define M98925_ADC_VBST_EN_SHIFT 3 +#define M98925_ADC_VBST_EN_WIDTH 1 +#define M98925_ADC_VBAT_EN_MASK (1<<2) +#define M98925_ADC_VBAT_EN_SHIFT 2 +#define M98925_ADC_VBAT_EN_WIDTH 1 +#define M98925_ADC_IMON_EN_MASK (1<<1) +#define M98925_ADC_IMON_EN_SHIFT 1 +#define M98925_ADC_IMON_EN_WIDTH 1 +#define M98925_ADC_VMON_EN_MASK (1<<0) +#define M98925_ADC_VMON_EN_SHIFT 0 +#define M98925_ADC_VMON_EN_WIDTH 1 + +/* MAX98925_R037_CONFIGURATION */ +#define M98925_BST_VOUT_MASK (0x0F<<4) +#define M98925_BST_VOUT_SHIFT 4 +#define M98925_BST_VOUT_WIDTH 4 +#define M98925_THERMWARN_LEVEL_MASK (0x03<<2) +#define M98925_THERMWARN_LEVEL_SHIFT 2 +#define M98925_THERMWARN_LEVEL_WIDTH 2 +#define M98925_WATCH_TIME_MASK (0x03<<0) +#define M98925_WATCH_TIME_SHIFT 0 +#define M98925_WATCH_TIME_WIDTH 2 + +/* MAX98925_R038_GLOBAL_ENABLE */ +#define M98925_EN_MASK (1<<7) +#define M98925_EN_SHIFT 7 +#define M98925_EN_WIDTH 1 + +/* MAX98925_R03A_BOOST_LIMITER */ +#define M98925_BST_ILIM_MASK (0x1F<<3) +#define M98925_BST_ILIM_SHIFT 3 +#define M98925_BST_ILIM_WIDTH 5 + +/* MAX98925_R0FF_VERSION */ +#define M98925_REV_ID_MASK (0xFF<<0) +#define M98925_REV_ID_SHIFT 0 +#define M98925_REV_ID_WIDTH 8 + +struct max98925_priv { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct max98925_pdata *pdata; + unsigned int sysclk; + unsigned int v_slot; + unsigned int i_slot; + unsigned int spk_gain; + unsigned int ch_size; +}; +#endif -- GitLab From 10dcc448d13071ed0d3797233187e79be258d90c Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 12 Mar 2015 03:05:44 +0800 Subject: [PATCH 0317/1910] ASoC: max98925_spk_tlv can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index 74f4f0b60108..34fc4d0441fd 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -186,7 +186,7 @@ static bool max98925_readable_register(struct device *dev, unsigned int reg) } } -DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0); +static DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0); static const struct snd_kcontrol_new max98925_snd_controls[] = { SOC_SINGLE_TLV("Speaker Volume", MAX98925_GAIN, -- GitLab From 66454b3eb31e8109387606c054ae02f3cfd6543e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 15 Jan 2015 12:52:15 +0100 Subject: [PATCH 0318/1910] ASoC: rt5670: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 91d2069a9313..cc7f84a150a7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -699,7 +699,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1) -- GitLab From 652ccae5cc4e1305fb0a4619947f9ee89d8c7f5a Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Mar 2015 09:47:44 +0100 Subject: [PATCH 0319/1910] crypto: arm - move ARM specific Kconfig definitions to a dedicated file This moves all Kconfig symbols defined in crypto/Kconfig that depend on CONFIG_ARM to a dedicated Kconfig file in arch/arm/crypto, which is where the code that implements those features resides as well. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/Kconfig | 3 ++ arch/arm/crypto/Kconfig | 85 +++++++++++++++++++++++++++++++++++++++++ crypto/Kconfig | 75 ------------------------------------ 3 files changed, 88 insertions(+), 75 deletions(-) create mode 100644 arch/arm/crypto/Kconfig diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9f1f09a2bc9b..e60da5ab8aec 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2167,6 +2167,9 @@ source "arch/arm/Kconfig.debug" source "security/Kconfig" source "crypto/Kconfig" +if CRYPTO +source "arch/arm/crypto/Kconfig" +endif source "lib/Kconfig" diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig new file mode 100644 index 000000000000..66fe82857e99 --- /dev/null +++ b/arch/arm/crypto/Kconfig @@ -0,0 +1,85 @@ + +menuconfig ARM_CRYPTO + bool "ARM Accelerated Cryptographic Algorithms" + depends on ARM + help + Say Y here to choose from a selection of cryptographic algorithms + implemented using ARM specific CPU features or instructions. + +if ARM_CRYPTO + +config CRYPTO_SHA1_ARM + tristate "SHA1 digest algorithm (ARM-asm)" + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using optimized ARM assembler. + +config CRYPTO_SHA1_ARM_NEON + tristate "SHA1 digest algorithm (ARM NEON)" + depends on KERNEL_MODE_NEON + select CRYPTO_SHA1_ARM + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using optimized ARM NEON assembly, when NEON instructions are + available. + +config CRYPTO_SHA512_ARM_NEON + tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" + depends on KERNEL_MODE_NEON + select CRYPTO_SHA512 + select CRYPTO_HASH + help + SHA-512 secure hash standard (DFIPS 180-2) implemented + using ARM NEON instructions, when available. + + This version of SHA implements a 512 bit hash with 256 bits of + security against collision attacks. + + This code also includes SHA-384, a 384 bit hash with 192 bits + of security against collision attacks. + +config CRYPTO_AES_ARM + tristate "AES cipher algorithms (ARM-asm)" + depends on ARM + select CRYPTO_ALGAPI + select CRYPTO_AES + help + Use optimized AES assembler routines for ARM platforms. + + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + The AES specifies three key sizes: 128, 192 and 256 bits + + See for more information. + +config CRYPTO_AES_ARM_BS + tristate "Bit sliced AES using NEON instructions" + depends on KERNEL_MODE_NEON + select CRYPTO_ALGAPI + select CRYPTO_AES_ARM + select CRYPTO_ABLK_HELPER + help + Use a faster and more secure NEON based implementation of AES in CBC, + CTR and XTS modes + + Bit sliced AES gives around 45% speedup on Cortex-A15 for CTR mode + and for XTS mode encryption, CBC and XTS mode decryption speedup is + around 25%. (CBC encryption speed is not affected by this driver.) + This implementation does not rely on any lookup tables so it is + believed to be invulnerable to cache timing attacks. + +endif diff --git a/crypto/Kconfig b/crypto/Kconfig index 1afb0f66ad43..88639937a934 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -572,26 +572,6 @@ config CRYPTO_SHA1_SPARC64 SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented using sparc64 crypto instructions, when available. -config CRYPTO_SHA1_ARM - tristate "SHA1 digest algorithm (ARM-asm)" - depends on ARM - select CRYPTO_SHA1 - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using optimized ARM assembler. - -config CRYPTO_SHA1_ARM_NEON - tristate "SHA1 digest algorithm (ARM NEON)" - depends on ARM && KERNEL_MODE_NEON - select CRYPTO_SHA1_ARM - select CRYPTO_SHA1 - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using optimized ARM NEON assembly, when NEON instructions are - available. - config CRYPTO_SHA1_PPC tristate "SHA1 digest algorithm (powerpc)" depends on PPC @@ -691,21 +671,6 @@ config CRYPTO_SHA512_SPARC64 SHA-512 secure hash standard (DFIPS 180-2) implemented using sparc64 crypto instructions, when available. -config CRYPTO_SHA512_ARM_NEON - tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" - depends on ARM && KERNEL_MODE_NEON - select CRYPTO_SHA512 - select CRYPTO_HASH - help - SHA-512 secure hash standard (DFIPS 180-2) implemented - using ARM NEON instructions, when available. - - This version of SHA implements a 512 bit hash with 256 bits of - security against collision attacks. - - This code also includes SHA-384, a 384 bit hash with 192 bits - of security against collision attacks. - config CRYPTO_TGR192 tristate "Tiger digest algorithms" select CRYPTO_HASH @@ -868,46 +833,6 @@ config CRYPTO_AES_SPARC64 for some popular block cipher mode is supported too, including ECB and CBC. -config CRYPTO_AES_ARM - tristate "AES cipher algorithms (ARM-asm)" - depends on ARM - select CRYPTO_ALGAPI - select CRYPTO_AES - help - Use optimized AES assembler routines for ARM platforms. - - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - -config CRYPTO_AES_ARM_BS - tristate "Bit sliced AES using NEON instructions" - depends on ARM && KERNEL_MODE_NEON - select CRYPTO_ALGAPI - select CRYPTO_AES_ARM - select CRYPTO_ABLK_HELPER - help - Use a faster and more secure NEON based implementation of AES in CBC, - CTR and XTS modes - - Bit sliced AES gives around 45% speedup on Cortex-A15 for CTR mode - and for XTS mode encryption, CBC and XTS mode decryption speedup is - around 25%. (CBC encryption speed is not affected by this driver.) - This implementation does not rely on any lookup tables so it is - believed to be invulnerable to cache timing attacks. - config CRYPTO_AES_PPC_SPE tristate "AES cipher algorithms (PPC SPE)" depends on PPC && SPE -- GitLab From 864cbeed4ab22de8c4d9a49101e9fd63c6f7fda2 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Mar 2015 09:47:45 +0100 Subject: [PATCH 0320/1910] crypto: arm - add support for SHA1 using ARMv8 Crypto Instructions This implements the SHA1 secure hash algorithm using the AArch32 versions of the ARMv8 Crypto Extensions for SHA1. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 10 +++ arch/arm/crypto/Makefile | 2 + arch/arm/crypto/sha1-ce-core.S | 134 +++++++++++++++++++++++++++++ arch/arm/crypto/sha1-ce-glue.c | 150 +++++++++++++++++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 arch/arm/crypto/sha1-ce-core.S create mode 100644 arch/arm/crypto/sha1-ce-glue.c diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 66fe82857e99..d7bc10beb8ac 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -27,6 +27,16 @@ config CRYPTO_SHA1_ARM_NEON using optimized ARM NEON assembly, when NEON instructions are available. +config CRYPTO_SHA1_ARM_CE + tristate "SHA1 digest algorithm (ARM v8 Crypto Extensions)" + depends on KERNEL_MODE_NEON + select CRYPTO_SHA1_ARM + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using special ARMv8 Crypto Extensions. + config CRYPTO_SHA512_ARM_NEON tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" depends on KERNEL_MODE_NEON diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index b48fa341648d..d92d05ba646e 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -7,12 +7,14 @@ obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o +obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o aes-arm-y := aes-armv4.o aes_glue.o aes-arm-bs-y := aesbs-core.o aesbs-glue.o sha1-arm-y := sha1-armv4-large.o sha1_glue.o sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o +sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/sha1-ce-core.S b/arch/arm/crypto/sha1-ce-core.S new file mode 100644 index 000000000000..4aad520935d8 --- /dev/null +++ b/arch/arm/crypto/sha1-ce-core.S @@ -0,0 +1,134 @@ +/* + * sha1-ce-core.S - SHA-1 secure hash using ARMv8 Crypto Extensions + * + * Copyright (C) 2015 Linaro Ltd. + * Author: Ard Biesheuvel + * + * This program is free software; you can 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 +#include + + .text + .fpu crypto-neon-fp-armv8 + + k0 .req q0 + k1 .req q1 + k2 .req q2 + k3 .req q3 + + ta0 .req q4 + ta1 .req q5 + tb0 .req q5 + tb1 .req q4 + + dga .req q6 + dgb .req q7 + dgbs .req s28 + + dg0 .req q12 + dg1a0 .req q13 + dg1a1 .req q14 + dg1b0 .req q14 + dg1b1 .req q13 + + .macro add_only, op, ev, rc, s0, dg1 + .ifnb \s0 + vadd.u32 tb\ev, q\s0, \rc + .endif + sha1h.32 dg1b\ev, dg0 + .ifb \dg1 + sha1\op\().32 dg0, dg1a\ev, ta\ev + .else + sha1\op\().32 dg0, \dg1, ta\ev + .endif + .endm + + .macro add_update, op, ev, rc, s0, s1, s2, s3, dg1 + sha1su0.32 q\s0, q\s1, q\s2 + add_only \op, \ev, \rc, \s1, \dg1 + sha1su1.32 q\s0, q\s3 + .endm + + .align 6 +.Lsha1_rcon: + .word 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999 + .word 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1 + .word 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc + .word 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 + + /* + * void sha1_ce_transform(int blocks, u8 const *src, u32 *state, + * u8 *head); + */ +ENTRY(sha1_ce_transform) + /* load round constants */ + adr ip, .Lsha1_rcon + vld1.32 {k0-k1}, [ip, :128]! + vld1.32 {k2-k3}, [ip, :128] + + /* load state */ + vld1.32 {dga}, [r2] + vldr dgbs, [r2, #16] + + /* load partial input (if supplied) */ + teq r3, #0 + beq 0f + vld1.32 {q8-q9}, [r3]! + vld1.32 {q10-q11}, [r3] + teq r0, #0 + b 1f + + /* load input */ +0: vld1.32 {q8-q9}, [r1]! + vld1.32 {q10-q11}, [r1]! + subs r0, r0, #1 + +1: +#ifndef CONFIG_CPU_BIG_ENDIAN + vrev32.8 q8, q8 + vrev32.8 q9, q9 + vrev32.8 q10, q10 + vrev32.8 q11, q11 +#endif + + vadd.u32 ta0, q8, k0 + vmov dg0, dga + + add_update c, 0, k0, 8, 9, 10, 11, dgb + add_update c, 1, k0, 9, 10, 11, 8 + add_update c, 0, k0, 10, 11, 8, 9 + add_update c, 1, k0, 11, 8, 9, 10 + add_update c, 0, k1, 8, 9, 10, 11 + + add_update p, 1, k1, 9, 10, 11, 8 + add_update p, 0, k1, 10, 11, 8, 9 + add_update p, 1, k1, 11, 8, 9, 10 + add_update p, 0, k1, 8, 9, 10, 11 + add_update p, 1, k2, 9, 10, 11, 8 + + add_update m, 0, k2, 10, 11, 8, 9 + add_update m, 1, k2, 11, 8, 9, 10 + add_update m, 0, k2, 8, 9, 10, 11 + add_update m, 1, k2, 9, 10, 11, 8 + add_update m, 0, k3, 10, 11, 8, 9 + + add_update p, 1, k3, 11, 8, 9, 10 + add_only p, 0, k3, 9 + add_only p, 1, k3, 10 + add_only p, 0, k3, 11 + add_only p, 1 + + /* update state */ + vadd.u32 dga, dga, dg0 + vadd.u32 dgb, dgb, dg1a0 + bne 0b + + /* store new state */ + vst1.32 {dga}, [r2] + vstr dgbs, [r2, #16] + bx lr +ENDPROC(sha1_ce_transform) diff --git a/arch/arm/crypto/sha1-ce-glue.c b/arch/arm/crypto/sha1-ce-glue.c new file mode 100644 index 000000000000..a9dd90df9fd7 --- /dev/null +++ b/arch/arm/crypto/sha1-ce-glue.c @@ -0,0 +1,150 @@ +/* + * sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions + * + * Copyright (C) 2015 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions"); +MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_LICENSE("GPL v2"); + +asmlinkage void sha1_ce_transform(int blocks, u8 const *src, u32 *state, + u8 *head); + +static int sha1_init(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, + }; + return 0; +} + +static int sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int partial; + + if (!may_use_simd()) + return sha1_update_arm(desc, data, len); + + partial = sctx->count % SHA1_BLOCK_SIZE; + sctx->count += len; + + if ((partial + len) >= SHA1_BLOCK_SIZE) { + int blocks; + + if (partial) { + int p = SHA1_BLOCK_SIZE - partial; + + memcpy(sctx->buffer + partial, data, p); + data += p; + len -= p; + } + + blocks = len / SHA1_BLOCK_SIZE; + len %= SHA1_BLOCK_SIZE; + + kernel_neon_begin(); + sha1_ce_transform(blocks, data, sctx->state, + partial ? sctx->buffer : NULL); + kernel_neon_end(); + + data += blocks * SHA1_BLOCK_SIZE; + partial = 0; + } + if (len) + memcpy(sctx->buffer + partial, data, len); + return 0; +} + +static int sha1_final(struct shash_desc *desc, u8 *out) +{ + static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; + + struct sha1_state *sctx = shash_desc_ctx(desc); + __be64 bits = cpu_to_be64(sctx->count << 3); + __be32 *dst = (__be32 *)out; + int i; + + u32 padlen = SHA1_BLOCK_SIZE + - ((sctx->count + sizeof(bits)) % SHA1_BLOCK_SIZE); + + sha1_update(desc, padding, padlen); + sha1_update(desc, (const u8 *)&bits, sizeof(bits)); + + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) + put_unaligned_be32(sctx->state[i], dst++); + + *sctx = (struct sha1_state){}; + return 0; +} + +static int sha1_export(struct shash_desc *desc, void *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + struct sha1_state *dst = out; + + *dst = *sctx; + return 0; +} + +static int sha1_import(struct shash_desc *desc, const void *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + struct sha1_state const *src = in; + + *sctx = *src; + return 0; +} + +static struct shash_alg alg = { + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, + .export = sha1_export, + .import = sha1_import, + .descsize = sizeof(struct sha1_state), + .digestsize = SHA1_DIGEST_SIZE, + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-ce", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init sha1_ce_mod_init(void) +{ + if (!(elf_hwcap2 & HWCAP2_SHA1)) + return -ENODEV; + return crypto_register_shash(&alg); +} + +static void __exit sha1_ce_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(sha1_ce_mod_init); +module_exit(sha1_ce_mod_fini); -- GitLab From 006d0624fa0d71787448cacee0195bf20f2d47c8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Mar 2015 09:47:46 +0100 Subject: [PATCH 0321/1910] crypto: arm - add support for SHA-224/256 using ARMv8 Crypto Extensions This implements the SHA-224/256 secure hash algorithm using the AArch32 versions of the ARMv8 Crypto Extensions for SHA2. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 9 ++ arch/arm/crypto/Makefile | 2 + arch/arm/crypto/sha2-ce-core.S | 134 ++++++++++++++++++++++ arch/arm/crypto/sha2-ce-glue.c | 203 +++++++++++++++++++++++++++++++++ 4 files changed, 348 insertions(+) create mode 100644 arch/arm/crypto/sha2-ce-core.S create mode 100644 arch/arm/crypto/sha2-ce-glue.c diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index d7bc10beb8ac..9c1478e55a40 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -37,6 +37,15 @@ config CRYPTO_SHA1_ARM_CE SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented using special ARMv8 Crypto Extensions. +config CRYPTO_SHA2_ARM_CE + tristate "SHA-224/256 digest algorithm (ARM v8 Crypto Extensions)" + depends on KERNEL_MODE_NEON + select CRYPTO_SHA256 + select CRYPTO_HASH + help + SHA-256 secure hash standard (DFIPS 180-2) implemented + using special ARMv8 Crypto Extensions. + config CRYPTO_SHA512_ARM_NEON tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" depends on KERNEL_MODE_NEON diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index d92d05ba646e..4ea9f96c2782 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o +obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o aes-arm-y := aes-armv4.o aes_glue.o aes-arm-bs-y := aesbs-core.o aesbs-glue.o @@ -15,6 +16,7 @@ sha1-arm-y := sha1-armv4-large.o sha1_glue.o sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o +sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/sha2-ce-core.S b/arch/arm/crypto/sha2-ce-core.S new file mode 100644 index 000000000000..96af09fe957b --- /dev/null +++ b/arch/arm/crypto/sha2-ce-core.S @@ -0,0 +1,134 @@ +/* + * sha2-ce-core.S - SHA-224/256 secure hash using ARMv8 Crypto Extensions + * + * Copyright (C) 2015 Linaro Ltd. + * Author: Ard Biesheuvel + * + * This program is free software; you can 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 +#include + + .text + .fpu crypto-neon-fp-armv8 + + k0 .req q7 + k1 .req q8 + rk .req r3 + + ta0 .req q9 + ta1 .req q10 + tb0 .req q10 + tb1 .req q9 + + dga .req q11 + dgb .req q12 + + dg0 .req q13 + dg1 .req q14 + dg2 .req q15 + + .macro add_only, ev, s0 + vmov dg2, dg0 + .ifnb \s0 + vld1.32 {k\ev}, [rk, :128]! + .endif + sha256h.32 dg0, dg1, tb\ev + sha256h2.32 dg1, dg2, tb\ev + .ifnb \s0 + vadd.u32 ta\ev, q\s0, k\ev + .endif + .endm + + .macro add_update, ev, s0, s1, s2, s3 + sha256su0.32 q\s0, q\s1 + add_only \ev, \s1 + sha256su1.32 q\s0, q\s2, q\s3 + .endm + + .align 6 +.Lsha256_rcon: + .word 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5 + .word 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 + .word 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3 + .word 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 + .word 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc + .word 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da + .word 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7 + .word 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 + .word 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13 + .word 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 + .word 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3 + .word 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 + .word 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5 + .word 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 + .word 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208 + .word 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + + /* + * void sha2_ce_transform(int blocks, u8 const *src, u32 *state, + * u8 *head); + */ +ENTRY(sha2_ce_transform) + /* load state */ + vld1.32 {dga-dgb}, [r2] + + /* load partial input (if supplied) */ + teq r3, #0 + beq 0f + vld1.32 {q0-q1}, [r3]! + vld1.32 {q2-q3}, [r3] + teq r0, #0 + b 1f + + /* load input */ +0: vld1.32 {q0-q1}, [r1]! + vld1.32 {q2-q3}, [r1]! + subs r0, r0, #1 + +1: +#ifndef CONFIG_CPU_BIG_ENDIAN + vrev32.8 q0, q0 + vrev32.8 q1, q1 + vrev32.8 q2, q2 + vrev32.8 q3, q3 +#endif + + /* load first round constant */ + adr rk, .Lsha256_rcon + vld1.32 {k0}, [rk, :128]! + + vadd.u32 ta0, q0, k0 + vmov dg0, dga + vmov dg1, dgb + + add_update 1, 0, 1, 2, 3 + add_update 0, 1, 2, 3, 0 + add_update 1, 2, 3, 0, 1 + add_update 0, 3, 0, 1, 2 + add_update 1, 0, 1, 2, 3 + add_update 0, 1, 2, 3, 0 + add_update 1, 2, 3, 0, 1 + add_update 0, 3, 0, 1, 2 + add_update 1, 0, 1, 2, 3 + add_update 0, 1, 2, 3, 0 + add_update 1, 2, 3, 0, 1 + add_update 0, 3, 0, 1, 2 + + add_only 1, 1 + add_only 0, 2 + add_only 1, 3 + add_only 0 + + /* update state */ + vadd.u32 dga, dga, dg0 + vadd.u32 dgb, dgb, dg1 + bne 0b + + /* store new state */ + vst1.32 {dga-dgb}, [r2] + bx lr +ENDPROC(sha2_ce_transform) diff --git a/arch/arm/crypto/sha2-ce-glue.c b/arch/arm/crypto/sha2-ce-glue.c new file mode 100644 index 000000000000..9ffe8ad27402 --- /dev/null +++ b/arch/arm/crypto/sha2-ce-glue.c @@ -0,0 +1,203 @@ +/* + * sha2-ce-glue.c - SHA-224/SHA-256 using ARMv8 Crypto Extensions + * + * Copyright (C) 2015 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions"); +MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_LICENSE("GPL v2"); + +asmlinkage void sha2_ce_transform(int blocks, u8 const *src, u32 *state, + u8 *head); + +static int sha224_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha256_state){ + .state = { + SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, + SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, + } + }; + return 0; +} + +static int sha256_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha256_state){ + .state = { + SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, + SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, + } + }; + return 0; +} + +static int sha2_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + unsigned int partial; + + if (!may_use_simd()) + return crypto_sha256_update(desc, data, len); + + partial = sctx->count % SHA256_BLOCK_SIZE; + sctx->count += len; + + if ((partial + len) >= SHA256_BLOCK_SIZE) { + int blocks; + + if (partial) { + int p = SHA256_BLOCK_SIZE - partial; + + memcpy(sctx->buf + partial, data, p); + data += p; + len -= p; + } + + blocks = len / SHA256_BLOCK_SIZE; + len %= SHA256_BLOCK_SIZE; + + kernel_neon_begin(); + sha2_ce_transform(blocks, data, sctx->state, + partial ? sctx->buf : NULL); + kernel_neon_end(); + + data += blocks * SHA256_BLOCK_SIZE; + partial = 0; + } + if (len) + memcpy(sctx->buf + partial, data, len); + return 0; +} + +static void sha2_final(struct shash_desc *desc) +{ + static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, }; + + struct sha256_state *sctx = shash_desc_ctx(desc); + __be64 bits = cpu_to_be64(sctx->count << 3); + u32 padlen = SHA256_BLOCK_SIZE + - ((sctx->count + sizeof(bits)) % SHA256_BLOCK_SIZE); + + sha2_update(desc, padding, padlen); + sha2_update(desc, (const u8 *)&bits, sizeof(bits)); +} + +static int sha224_final(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + __be32 *dst = (__be32 *)out; + int i; + + sha2_final(desc); + + for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(__be32); i++) + put_unaligned_be32(sctx->state[i], dst++); + + *sctx = (struct sha256_state){}; + return 0; +} + +static int sha256_final(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + __be32 *dst = (__be32 *)out; + int i; + + sha2_final(desc); + + for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(__be32); i++) + put_unaligned_be32(sctx->state[i], dst++); + + *sctx = (struct sha256_state){}; + return 0; +} + +static int sha2_export(struct shash_desc *desc, void *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + struct sha256_state *dst = out; + + *dst = *sctx; + return 0; +} + +static int sha2_import(struct shash_desc *desc, const void *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + struct sha256_state const *src = in; + + *sctx = *src; + return 0; +} + +static struct shash_alg algs[] = { { + .init = sha224_init, + .update = sha2_update, + .final = sha224_final, + .export = sha2_export, + .import = sha2_import, + .descsize = sizeof(struct sha256_state), + .digestsize = SHA224_DIGEST_SIZE, + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha224", + .cra_driver_name = "sha224-ce", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}, { + .init = sha256_init, + .update = sha2_update, + .final = sha256_final, + .export = sha2_export, + .import = sha2_import, + .descsize = sizeof(struct sha256_state), + .digestsize = SHA256_DIGEST_SIZE, + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-ce", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} }; + +static int __init sha2_ce_mod_init(void) +{ + if (!(elf_hwcap2 & HWCAP2_SHA2)) + return -ENODEV; + return crypto_register_shashes(algs, ARRAY_SIZE(algs)); +} + +static void __exit sha2_ce_mod_fini(void) +{ + crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); +} + +module_init(sha2_ce_mod_init); +module_exit(sha2_ce_mod_fini); -- GitLab From 86464859cc77ecfd989ad5c912bef167b1128b0b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Mar 2015 09:47:47 +0100 Subject: [PATCH 0322/1910] crypto: arm - AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions This implements the ECB, CBC, CTR and XTS asynchronous block ciphers using the AArch32 versions of the ARMv8 Crypto Extensions for AES. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 9 + arch/arm/crypto/Makefile | 2 + arch/arm/crypto/aes-ce-core.S | 518 +++++++++++++++++++++++++++++++++ arch/arm/crypto/aes-ce-glue.c | 520 ++++++++++++++++++++++++++++++++++ 4 files changed, 1049 insertions(+) create mode 100644 arch/arm/crypto/aes-ce-core.S create mode 100644 arch/arm/crypto/aes-ce-glue.c diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 9c1478e55a40..63588bdf3b5d 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -101,4 +101,13 @@ config CRYPTO_AES_ARM_BS This implementation does not rely on any lookup tables so it is believed to be invulnerable to cache timing attacks. +config CRYPTO_AES_ARM_CE + tristate "Accelerated AES using ARMv8 Crypto Extensions" + depends on KERNEL_MODE_NEON + select CRYPTO_ALGAPI + select CRYPTO_ABLK_HELPER + help + Use an implementation of AES in CBC, CTR and XTS modes that uses + ARMv8 Crypto Extensions + endif diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 4ea9f96c2782..2514c420e8d3 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o +obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o @@ -17,6 +18,7 @@ sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o +aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/aes-ce-core.S b/arch/arm/crypto/aes-ce-core.S new file mode 100644 index 000000000000..8cfa468ee570 --- /dev/null +++ b/arch/arm/crypto/aes-ce-core.S @@ -0,0 +1,518 @@ +/* + * aes-ce-core.S - AES in CBC/CTR/XTS mode using ARMv8 Crypto Extensions + * + * Copyright (C) 2015 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + + .text + .fpu crypto-neon-fp-armv8 + .align 3 + + .macro enc_round, state, key + aese.8 \state, \key + aesmc.8 \state, \state + .endm + + .macro dec_round, state, key + aesd.8 \state, \key + aesimc.8 \state, \state + .endm + + .macro enc_dround, key1, key2 + enc_round q0, \key1 + enc_round q0, \key2 + .endm + + .macro dec_dround, key1, key2 + dec_round q0, \key1 + dec_round q0, \key2 + .endm + + .macro enc_fround, key1, key2, key3 + enc_round q0, \key1 + aese.8 q0, \key2 + veor q0, q0, \key3 + .endm + + .macro dec_fround, key1, key2, key3 + dec_round q0, \key1 + aesd.8 q0, \key2 + veor q0, q0, \key3 + .endm + + .macro enc_dround_3x, key1, key2 + enc_round q0, \key1 + enc_round q1, \key1 + enc_round q2, \key1 + enc_round q0, \key2 + enc_round q1, \key2 + enc_round q2, \key2 + .endm + + .macro dec_dround_3x, key1, key2 + dec_round q0, \key1 + dec_round q1, \key1 + dec_round q2, \key1 + dec_round q0, \key2 + dec_round q1, \key2 + dec_round q2, \key2 + .endm + + .macro enc_fround_3x, key1, key2, key3 + enc_round q0, \key1 + enc_round q1, \key1 + enc_round q2, \key1 + aese.8 q0, \key2 + aese.8 q1, \key2 + aese.8 q2, \key2 + veor q0, q0, \key3 + veor q1, q1, \key3 + veor q2, q2, \key3 + .endm + + .macro dec_fround_3x, key1, key2, key3 + dec_round q0, \key1 + dec_round q1, \key1 + dec_round q2, \key1 + aesd.8 q0, \key2 + aesd.8 q1, \key2 + aesd.8 q2, \key2 + veor q0, q0, \key3 + veor q1, q1, \key3 + veor q2, q2, \key3 + .endm + + .macro do_block, dround, fround + cmp r3, #12 @ which key size? + vld1.8 {q10-q11}, [ip]! + \dround q8, q9 + vld1.8 {q12-q13}, [ip]! + \dround q10, q11 + vld1.8 {q10-q11}, [ip]! + \dround q12, q13 + vld1.8 {q12-q13}, [ip]! + \dround q10, q11 + blo 0f @ AES-128: 10 rounds + vld1.8 {q10-q11}, [ip]! + beq 1f @ AES-192: 12 rounds + \dround q12, q13 + vld1.8 {q12-q13}, [ip] + \dround q10, q11 +0: \fround q12, q13, q14 + bx lr + +1: \dround q12, q13 + \fround q10, q11, q14 + bx lr + .endm + + /* + * Internal, non-AAPCS compliant functions that implement the core AES + * transforms. These should preserve all registers except q0 - q2 and ip + * Arguments: + * q0 : first in/output block + * q1 : second in/output block (_3x version only) + * q2 : third in/output block (_3x version only) + * q8 : first round key + * q9 : secound round key + * ip : address of 3rd round key + * q14 : final round key + * r3 : number of rounds + */ + .align 6 +aes_encrypt: + add ip, r2, #32 @ 3rd round key +.Laes_encrypt_tweak: + do_block enc_dround, enc_fround +ENDPROC(aes_encrypt) + + .align 6 +aes_decrypt: + add ip, r2, #32 @ 3rd round key + do_block dec_dround, dec_fround +ENDPROC(aes_decrypt) + + .align 6 +aes_encrypt_3x: + add ip, r2, #32 @ 3rd round key + do_block enc_dround_3x, enc_fround_3x +ENDPROC(aes_encrypt_3x) + + .align 6 +aes_decrypt_3x: + add ip, r2, #32 @ 3rd round key + do_block dec_dround_3x, dec_fround_3x +ENDPROC(aes_decrypt_3x) + + .macro prepare_key, rk, rounds + add ip, \rk, \rounds, lsl #4 + vld1.8 {q8-q9}, [\rk] @ load first 2 round keys + vld1.8 {q14}, [ip] @ load last round key + .endm + + /* + * aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * int blocks) + * aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * int blocks) + */ +ENTRY(ce_aes_ecb_encrypt) + push {r4, lr} + ldr r4, [sp, #8] + prepare_key r2, r3 +.Lecbencloop3x: + subs r4, r4, #3 + bmi .Lecbenc1x + vld1.8 {q0-q1}, [r1, :64]! + vld1.8 {q2}, [r1, :64]! + bl aes_encrypt_3x + vst1.8 {q0-q1}, [r0, :64]! + vst1.8 {q2}, [r0, :64]! + b .Lecbencloop3x +.Lecbenc1x: + adds r4, r4, #3 + beq .Lecbencout +.Lecbencloop: + vld1.8 {q0}, [r1, :64]! + bl aes_encrypt + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + bne .Lecbencloop +.Lecbencout: + pop {r4, pc} +ENDPROC(ce_aes_ecb_encrypt) + +ENTRY(ce_aes_ecb_decrypt) + push {r4, lr} + ldr r4, [sp, #8] + prepare_key r2, r3 +.Lecbdecloop3x: + subs r4, r4, #3 + bmi .Lecbdec1x + vld1.8 {q0-q1}, [r1, :64]! + vld1.8 {q2}, [r1, :64]! + bl aes_decrypt_3x + vst1.8 {q0-q1}, [r0, :64]! + vst1.8 {q2}, [r0, :64]! + b .Lecbdecloop3x +.Lecbdec1x: + adds r4, r4, #3 + beq .Lecbdecout +.Lecbdecloop: + vld1.8 {q0}, [r1, :64]! + bl aes_decrypt + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + bne .Lecbdecloop +.Lecbdecout: + pop {r4, pc} +ENDPROC(ce_aes_ecb_decrypt) + + /* + * aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * int blocks, u8 iv[]) + * aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * int blocks, u8 iv[]) + */ +ENTRY(ce_aes_cbc_encrypt) + push {r4-r6, lr} + ldrd r4, r5, [sp, #16] + vld1.8 {q0}, [r5] + prepare_key r2, r3 +.Lcbcencloop: + vld1.8 {q1}, [r1, :64]! @ get next pt block + veor q0, q0, q1 @ ..and xor with iv + bl aes_encrypt + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + bne .Lcbcencloop + vst1.8 {q0}, [r5] + pop {r4-r6, pc} +ENDPROC(ce_aes_cbc_encrypt) + +ENTRY(ce_aes_cbc_decrypt) + push {r4-r6, lr} + ldrd r4, r5, [sp, #16] + vld1.8 {q6}, [r5] @ keep iv in q6 + prepare_key r2, r3 +.Lcbcdecloop3x: + subs r4, r4, #3 + bmi .Lcbcdec1x + vld1.8 {q0-q1}, [r1, :64]! + vld1.8 {q2}, [r1, :64]! + vmov q3, q0 + vmov q4, q1 + vmov q5, q2 + bl aes_decrypt_3x + veor q0, q0, q6 + veor q1, q1, q3 + veor q2, q2, q4 + vmov q6, q5 + vst1.8 {q0-q1}, [r0, :64]! + vst1.8 {q2}, [r0, :64]! + b .Lcbcdecloop3x +.Lcbcdec1x: + adds r4, r4, #3 + beq .Lcbcdecout + vmov q15, q14 @ preserve last round key +.Lcbcdecloop: + vld1.8 {q0}, [r1, :64]! @ get next ct block + veor q14, q15, q6 @ combine prev ct with last key + vmov q6, q0 + bl aes_decrypt + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + bne .Lcbcdecloop +.Lcbcdecout: + vst1.8 {q6}, [r5] @ keep iv in q6 + pop {r4-r6, pc} +ENDPROC(ce_aes_cbc_decrypt) + + /* + * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, + * int blocks, u8 ctr[]) + */ +ENTRY(ce_aes_ctr_encrypt) + push {r4-r6, lr} + ldrd r4, r5, [sp, #16] + vld1.8 {q6}, [r5] @ load ctr + prepare_key r2, r3 + vmov r6, s27 @ keep swabbed ctr in r6 + rev r6, r6 + cmn r6, r4 @ 32 bit overflow? + bcs .Lctrloop +.Lctrloop3x: + subs r4, r4, #3 + bmi .Lctr1x + add r6, r6, #1 + vmov q0, q6 + vmov q1, q6 + rev ip, r6 + add r6, r6, #1 + vmov q2, q6 + vmov s7, ip + rev ip, r6 + add r6, r6, #1 + vmov s11, ip + vld1.8 {q3-q4}, [r1, :64]! + vld1.8 {q5}, [r1, :64]! + bl aes_encrypt_3x + veor q0, q0, q3 + veor q1, q1, q4 + veor q2, q2, q5 + rev ip, r6 + vst1.8 {q0-q1}, [r0, :64]! + vst1.8 {q2}, [r0, :64]! + vmov s27, ip + b .Lctrloop3x +.Lctr1x: + adds r4, r4, #3 + beq .Lctrout +.Lctrloop: + vmov q0, q6 + bl aes_encrypt + subs r4, r4, #1 + bmi .Lctrhalfblock @ blocks < 0 means 1/2 block + vld1.8 {q3}, [r1, :64]! + veor q3, q0, q3 + vst1.8 {q3}, [r0, :64]! + + adds r6, r6, #1 @ increment BE ctr + rev ip, r6 + vmov s27, ip + bcs .Lctrcarry + teq r4, #0 + bne .Lctrloop +.Lctrout: + vst1.8 {q6}, [r5] + pop {r4-r6, pc} + +.Lctrhalfblock: + vld1.8 {d1}, [r1, :64] + veor d0, d0, d1 + vst1.8 {d0}, [r0, :64] + pop {r4-r6, pc} + +.Lctrcarry: + .irp sreg, s26, s25, s24 + vmov ip, \sreg @ load next word of ctr + rev ip, ip @ ... to handle the carry + adds ip, ip, #1 + rev ip, ip + vmov \sreg, ip + bcc 0f + .endr +0: teq r4, #0 + beq .Lctrout + b .Lctrloop +ENDPROC(ce_aes_ctr_encrypt) + + /* + * aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, + * int blocks, u8 iv[], u8 const rk2[], int first) + * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, + * int blocks, u8 iv[], u8 const rk2[], int first) + */ + + .macro next_tweak, out, in, const, tmp + vshr.s64 \tmp, \in, #63 + vand \tmp, \tmp, \const + vadd.u64 \out, \in, \in + vext.8 \tmp, \tmp, \tmp, #8 + veor \out, \out, \tmp + .endm + + .align 3 +.Lxts_mul_x: + .quad 1, 0x87 + +ce_aes_xts_init: + vldr d14, .Lxts_mul_x + vldr d15, .Lxts_mul_x + 8 + + ldrd r4, r5, [sp, #16] @ load args + ldr r6, [sp, #28] + vld1.8 {q0}, [r5] @ load iv + teq r6, #1 @ start of a block? + bxne lr + + @ Encrypt the IV in q0 with the second AES key. This should only + @ be done at the start of a block. + ldr r6, [sp, #24] @ load AES key 2 + prepare_key r6, r3 + add ip, r6, #32 @ 3rd round key of key 2 + b .Laes_encrypt_tweak @ tail call +ENDPROC(ce_aes_xts_init) + +ENTRY(ce_aes_xts_encrypt) + push {r4-r6, lr} + + bl ce_aes_xts_init @ run shared prologue + prepare_key r2, r3 + vmov q3, q0 + + teq r6, #0 @ start of a block? + bne .Lxtsenc3x + +.Lxtsencloop3x: + next_tweak q3, q3, q7, q6 +.Lxtsenc3x: + subs r4, r4, #3 + bmi .Lxtsenc1x + vld1.8 {q0-q1}, [r1, :64]! @ get 3 pt blocks + vld1.8 {q2}, [r1, :64]! + next_tweak q4, q3, q7, q6 + veor q0, q0, q3 + next_tweak q5, q4, q7, q6 + veor q1, q1, q4 + veor q2, q2, q5 + bl aes_encrypt_3x + veor q0, q0, q3 + veor q1, q1, q4 + veor q2, q2, q5 + vst1.8 {q0-q1}, [r0, :64]! @ write 3 ct blocks + vst1.8 {q2}, [r0, :64]! + vmov q3, q5 + teq r4, #0 + beq .Lxtsencout + b .Lxtsencloop3x +.Lxtsenc1x: + adds r4, r4, #3 + beq .Lxtsencout +.Lxtsencloop: + vld1.8 {q0}, [r1, :64]! + veor q0, q0, q3 + bl aes_encrypt + veor q0, q0, q3 + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + beq .Lxtsencout + next_tweak q3, q3, q7, q6 + b .Lxtsencloop +.Lxtsencout: + vst1.8 {q3}, [r5] + pop {r4-r6, pc} +ENDPROC(ce_aes_xts_encrypt) + + +ENTRY(ce_aes_xts_decrypt) + push {r4-r6, lr} + + bl ce_aes_xts_init @ run shared prologue + prepare_key r2, r3 + vmov q3, q0 + + teq r6, #0 @ start of a block? + bne .Lxtsdec3x + +.Lxtsdecloop3x: + next_tweak q3, q3, q7, q6 +.Lxtsdec3x: + subs r4, r4, #3 + bmi .Lxtsdec1x + vld1.8 {q0-q1}, [r1, :64]! @ get 3 ct blocks + vld1.8 {q2}, [r1, :64]! + next_tweak q4, q3, q7, q6 + veor q0, q0, q3 + next_tweak q5, q4, q7, q6 + veor q1, q1, q4 + veor q2, q2, q5 + bl aes_decrypt_3x + veor q0, q0, q3 + veor q1, q1, q4 + veor q2, q2, q5 + vst1.8 {q0-q1}, [r0, :64]! @ write 3 pt blocks + vst1.8 {q2}, [r0, :64]! + vmov q3, q5 + teq r4, #0 + beq .Lxtsdecout + b .Lxtsdecloop3x +.Lxtsdec1x: + adds r4, r4, #3 + beq .Lxtsdecout +.Lxtsdecloop: + vld1.8 {q0}, [r1, :64]! + veor q0, q0, q3 + add ip, r2, #32 @ 3rd round key + bl aes_decrypt + veor q0, q0, q3 + vst1.8 {q0}, [r0, :64]! + subs r4, r4, #1 + beq .Lxtsdecout + next_tweak q3, q3, q7, q6 + b .Lxtsdecloop +.Lxtsdecout: + vst1.8 {q3}, [r5] + pop {r4-r6, pc} +ENDPROC(ce_aes_xts_decrypt) + + /* + * u32 ce_aes_sub(u32 input) - use the aese instruction to perform the + * AES sbox substitution on each byte in + * 'input' + */ +ENTRY(ce_aes_sub) + vdup.32 q1, r0 + veor q0, q0, q0 + aese.8 q0, q1 + vmov r0, s0 + bx lr +ENDPROC(ce_aes_sub) + + /* + * void ce_aes_invert(u8 *dst, u8 *src) - perform the Inverse MixColumns + * operation on round key *src + */ +ENTRY(ce_aes_invert) + vld1.8 {q0}, [r1] + aesimc.8 q0, q0 + vst1.8 {q0}, [r0] + bx lr +ENDPROC(ce_aes_invert) diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c new file mode 100644 index 000000000000..d2ee59157ec7 --- /dev/null +++ b/arch/arm/crypto/aes-ce-glue.c @@ -0,0 +1,520 @@ +/* + * aes-ce-glue.c - wrapper code for ARMv8 AES + * + * Copyright (C) 2015 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); +MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_LICENSE("GPL v2"); + +/* defined in aes-ce-core.S */ +asmlinkage u32 ce_aes_sub(u32 input); +asmlinkage void ce_aes_invert(void *dst, void *src); + +asmlinkage void ce_aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], + int rounds, int blocks); +asmlinkage void ce_aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], + int rounds, int blocks); + +asmlinkage void ce_aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], + int rounds, int blocks, u8 iv[]); +asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], + int rounds, int blocks, u8 iv[]); + +asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], + int rounds, int blocks, u8 ctr[]); + +asmlinkage void ce_aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], + int rounds, int blocks, u8 iv[], + u8 const rk2[], int first); +asmlinkage void ce_aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], + int rounds, int blocks, u8 iv[], + u8 const rk2[], int first); + +struct aes_block { + u8 b[AES_BLOCK_SIZE]; +}; + +static int num_rounds(struct crypto_aes_ctx *ctx) +{ + /* + * # of rounds specified by AES: + * 128 bit key 10 rounds + * 192 bit key 12 rounds + * 256 bit key 14 rounds + * => n byte key => 6 + (n/4) rounds + */ + return 6 + ctx->key_length / 4; +} + +static int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, + unsigned int key_len) +{ + /* + * The AES key schedule round constants + */ + static u8 const rcon[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, + }; + + u32 kwords = key_len / sizeof(u32); + struct aes_block *key_enc, *key_dec; + int i, j; + + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) + return -EINVAL; + + memcpy(ctx->key_enc, in_key, key_len); + ctx->key_length = key_len; + + kernel_neon_begin(); + for (i = 0; i < sizeof(rcon); i++) { + u32 *rki = ctx->key_enc + (i * kwords); + u32 *rko = rki + kwords; + + rko[0] = ror32(ce_aes_sub(rki[kwords - 1]), 8); + rko[0] = rko[0] ^ rki[0] ^ rcon[i]; + rko[1] = rko[0] ^ rki[1]; + rko[2] = rko[1] ^ rki[2]; + rko[3] = rko[2] ^ rki[3]; + + if (key_len == AES_KEYSIZE_192) { + if (i >= 7) + break; + rko[4] = rko[3] ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + } else if (key_len == AES_KEYSIZE_256) { + if (i >= 6) + break; + rko[4] = ce_aes_sub(rko[3]) ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + rko[6] = rko[5] ^ rki[6]; + rko[7] = rko[6] ^ rki[7]; + } + } + + /* + * Generate the decryption keys for the Equivalent Inverse Cipher. + * This involves reversing the order of the round keys, and applying + * the Inverse Mix Columns transformation on all but the first and + * the last one. + */ + key_enc = (struct aes_block *)ctx->key_enc; + key_dec = (struct aes_block *)ctx->key_dec; + j = num_rounds(ctx); + + key_dec[0] = key_enc[j]; + for (i = 1, j--; j > 0; i++, j--) + ce_aes_invert(key_dec + i, key_enc + j); + key_dec[i] = key_enc[0]; + + kernel_neon_end(); + return 0; +} + +static int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); + int ret; + + ret = ce_aes_expandkey(ctx, in_key, key_len); + if (!ret) + return 0; + + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; +} + +struct crypto_aes_xts_ctx { + struct crypto_aes_ctx key1; + struct crypto_aes_ctx __aligned(8) key2; +}; + +static int xts_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); + int ret; + + ret = ce_aes_expandkey(&ctx->key1, in_key, key_len / 2); + if (!ret) + ret = ce_aes_expandkey(&ctx->key2, &in_key[key_len / 2], + key_len / 2); + if (!ret) + return 0; + + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; +} + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int blocks; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + ce_aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key_enc, num_rounds(ctx), blocks); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + return err; +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int blocks; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + ce_aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key_dec, num_rounds(ctx), blocks); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + return err; +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int blocks; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + ce_aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key_enc, num_rounds(ctx), blocks, + walk.iv); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + return err; +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + unsigned int blocks; + int err; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + ce_aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key_dec, num_rounds(ctx), blocks, + walk.iv); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + return err; +} + +static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err, blocks; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); + + kernel_neon_begin(); + while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { + ce_aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key_enc, num_rounds(ctx), blocks, + walk.iv); + nbytes -= blocks * AES_BLOCK_SIZE; + if (nbytes && nbytes == walk.nbytes % AES_BLOCK_SIZE) + break; + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + if (nbytes) { + u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE; + u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE; + u8 __aligned(8) tail[AES_BLOCK_SIZE]; + + /* + * Minimum alignment is 8 bytes, so if nbytes is <= 8, we need + * to tell aes_ctr_encrypt() to only read half a block. + */ + blocks = (nbytes <= 8) ? -1 : 1; + + ce_aes_ctr_encrypt(tail, tsrc, (u8 *)ctx->key_enc, + num_rounds(ctx), blocks, walk.iv); + memcpy(tdst, tail, nbytes); + err = blkcipher_walk_done(desc, &walk, 0); + } + kernel_neon_end(); + + return err; +} + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + int err, first, rounds = num_rounds(&ctx->key1); + struct blkcipher_walk walk; + unsigned int blocks; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + ce_aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key1.key_enc, rounds, blocks, + walk.iv, (u8 *)ctx->key2.key_enc, first); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + + return err; +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypto_aes_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + int err, first, rounds = num_rounds(&ctx->key1); + struct blkcipher_walk walk; + unsigned int blocks; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + kernel_neon_begin(); + for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { + ce_aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, + (u8 *)ctx->key1.key_dec, rounds, blocks, + walk.iv, (u8 *)ctx->key2.key_enc, first); + err = blkcipher_walk_done(desc, &walk, + walk.nbytes % AES_BLOCK_SIZE); + } + kernel_neon_end(); + + return err; +} + +static struct crypto_alg aes_algs[] = { { + .cra_name = "__ecb-aes-ce", + .cra_driver_name = "__driver-ecb-aes-ce", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, +}, { + .cra_name = "__cbc-aes-ce", + .cra_driver_name = "__driver-cbc-aes-ce", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, +}, { + .cra_name = "__ctr-aes-ce", + .cra_driver_name = "__driver-ctr-aes-ce", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct crypto_aes_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ce_aes_setkey, + .encrypt = ctr_encrypt, + .decrypt = ctr_encrypt, + }, +}, { + .cra_name = "__xts-aes-ce", + .cra_driver_name = "__driver-xts-aes-ce", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_xts_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_blkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = xts_set_key, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, +}, { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-ce", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + } +}, { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-ce", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + } +}, { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-ce", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + } +}, { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-ce", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 7, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_ablkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + } +} }; + +static int __init aes_init(void) +{ + if (!(elf_hwcap2 & HWCAP2_AES)) + return -ENODEV; + return crypto_register_algs(aes_algs, ARRAY_SIZE(aes_algs)); +} + +static void __exit aes_exit(void) +{ + crypto_unregister_algs(aes_algs, ARRAY_SIZE(aes_algs)); +} + +module_init(aes_init); +module_exit(aes_exit); -- GitLab From f1e866b10676faf8b9092cb821a9ac8acf31dbd8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Mar 2015 09:47:48 +0100 Subject: [PATCH 0323/1910] crypto: arm - add support for GHASH using ARMv8 Crypto Extensions This implements the GHASH hash algorithm (as used by the GCM AEAD chaining mode) using the AArch32 version of the 64x64 to 128 bit polynomial multiplication instruction (vmull.p64) that is part of the ARMv8 Crypto Extensions. Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 10 + arch/arm/crypto/Makefile | 2 + arch/arm/crypto/ghash-ce-core.S | 94 ++++++++++ arch/arm/crypto/ghash-ce-glue.c | 318 ++++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 arch/arm/crypto/ghash-ce-core.S create mode 100644 arch/arm/crypto/ghash-ce-glue.c diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 63588bdf3b5d..d63f319924d2 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -110,4 +110,14 @@ config CRYPTO_AES_ARM_CE Use an implementation of AES in CBC, CTR and XTS modes that uses ARMv8 Crypto Extensions +config CRYPTO_GHASH_ARM_CE + tristate "PMULL-accelerated GHASH using ARMv8 Crypto Extensions" + depends on KERNEL_MODE_NEON + select CRYPTO_HASH + select CRYPTO_CRYPTD + help + Use an implementation of GHASH (used by the GCM AEAD chaining mode) + that uses the 64x64 to 128 bit polynomial multiplication (vmull.p64) + that is part of the ARMv8 Crypto Extensions + endif diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 2514c420e8d3..9a273bd7dffd 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o obj-$(CONFIG_CRYPTO_SHA2_ARM_CE) += sha2-arm-ce.o +obj-$(CONFIG_CRYPTO_GHASH_ARM_CE) += ghash-arm-ce.o aes-arm-y := aes-armv4.o aes_glue.o aes-arm-bs-y := aesbs-core.o aesbs-glue.o @@ -19,6 +20,7 @@ sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o +ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) diff --git a/arch/arm/crypto/ghash-ce-core.S b/arch/arm/crypto/ghash-ce-core.S new file mode 100644 index 000000000000..e643a15eadf2 --- /dev/null +++ b/arch/arm/crypto/ghash-ce-core.S @@ -0,0 +1,94 @@ +/* + * Accelerated GHASH implementation with ARMv8 vmull.p64 instructions. + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include + + SHASH .req q0 + SHASH2 .req q1 + T1 .req q2 + T2 .req q3 + MASK .req q4 + XL .req q5 + XM .req q6 + XH .req q7 + IN1 .req q7 + + SHASH_L .req d0 + SHASH_H .req d1 + SHASH2_L .req d2 + T1_L .req d4 + MASK_L .req d8 + XL_L .req d10 + XL_H .req d11 + XM_L .req d12 + XM_H .req d13 + XH_L .req d14 + + .text + .fpu crypto-neon-fp-armv8 + + /* + * void pmull_ghash_update(int blocks, u64 dg[], const char *src, + * struct ghash_key const *k, const char *head) + */ +ENTRY(pmull_ghash_update) + vld1.8 {SHASH}, [r3] + vld1.64 {XL}, [r1] + vmov.i8 MASK, #0xe1 + vext.8 SHASH2, SHASH, SHASH, #8 + vshl.u64 MASK, MASK, #57 + veor SHASH2, SHASH2, SHASH + + /* do the head block first, if supplied */ + ldr ip, [sp] + teq ip, #0 + beq 0f + vld1.64 {T1}, [ip] + teq r0, #0 + b 1f + +0: vld1.64 {T1}, [r2]! + subs r0, r0, #1 + +1: /* multiply XL by SHASH in GF(2^128) */ +#ifndef CONFIG_CPU_BIG_ENDIAN + vrev64.8 T1, T1 +#endif + vext.8 T2, XL, XL, #8 + vext.8 IN1, T1, T1, #8 + veor T1, T1, T2 + veor XL, XL, IN1 + + vmull.p64 XH, SHASH_H, XL_H @ a1 * b1 + veor T1, T1, XL + vmull.p64 XL, SHASH_L, XL_L @ a0 * b0 + vmull.p64 XM, SHASH2_L, T1_L @ (a1 + a0)(b1 + b0) + + vext.8 T1, XL, XH, #8 + veor T2, XL, XH + veor XM, XM, T1 + veor XM, XM, T2 + vmull.p64 T2, XL_L, MASK_L + + vmov XH_L, XM_H + vmov XM_H, XL_L + + veor XL, XM, T2 + vext.8 T2, XL, XL, #8 + vmull.p64 XL, XL_L, MASK_L + veor T2, T2, XH + veor XL, XL, T2 + + bne 0b + + vst1.64 {XL}, [r1] + bx lr +ENDPROC(pmull_ghash_update) diff --git a/arch/arm/crypto/ghash-ce-glue.c b/arch/arm/crypto/ghash-ce-glue.c new file mode 100644 index 000000000000..8c959d128065 --- /dev/null +++ b/arch/arm/crypto/ghash-ce-glue.c @@ -0,0 +1,318 @@ +/* + * Accelerated GHASH implementation with ARMv8 vmull.p64 instructions. + * + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("GHASH secure hash using ARMv8 Crypto Extensions"); +MODULE_AUTHOR("Ard Biesheuvel "); +MODULE_LICENSE("GPL v2"); + +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 + +struct ghash_key { + u64 a; + u64 b; +}; + +struct ghash_desc_ctx { + u64 digest[GHASH_DIGEST_SIZE/sizeof(u64)]; + u8 buf[GHASH_BLOCK_SIZE]; + u32 count; +}; + +struct ghash_async_ctx { + struct cryptd_ahash *cryptd_tfm; +}; + +asmlinkage void pmull_ghash_update(int blocks, u64 dg[], const char *src, + struct ghash_key const *k, const char *head); + +static int ghash_init(struct shash_desc *desc) +{ + struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); + + *ctx = (struct ghash_desc_ctx){}; + return 0; +} + +static int ghash_update(struct shash_desc *desc, const u8 *src, + unsigned int len) +{ + struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); + unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; + + ctx->count += len; + + if ((partial + len) >= GHASH_BLOCK_SIZE) { + struct ghash_key *key = crypto_shash_ctx(desc->tfm); + int blocks; + + if (partial) { + int p = GHASH_BLOCK_SIZE - partial; + + memcpy(ctx->buf + partial, src, p); + src += p; + len -= p; + } + + blocks = len / GHASH_BLOCK_SIZE; + len %= GHASH_BLOCK_SIZE; + + kernel_neon_begin(); + pmull_ghash_update(blocks, ctx->digest, src, key, + partial ? ctx->buf : NULL); + kernel_neon_end(); + src += blocks * GHASH_BLOCK_SIZE; + partial = 0; + } + if (len) + memcpy(ctx->buf + partial, src, len); + return 0; +} + +static int ghash_final(struct shash_desc *desc, u8 *dst) +{ + struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); + unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; + + if (partial) { + struct ghash_key *key = crypto_shash_ctx(desc->tfm); + + memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial); + kernel_neon_begin(); + pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL); + kernel_neon_end(); + } + put_unaligned_be64(ctx->digest[1], dst); + put_unaligned_be64(ctx->digest[0], dst + 8); + + *ctx = (struct ghash_desc_ctx){}; + return 0; +} + +static int ghash_setkey(struct crypto_shash *tfm, + const u8 *inkey, unsigned int keylen) +{ + struct ghash_key *key = crypto_shash_ctx(tfm); + u64 a, b; + + if (keylen != GHASH_BLOCK_SIZE) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + /* perform multiplication by 'x' in GF(2^128) */ + b = get_unaligned_be64(inkey); + a = get_unaligned_be64(inkey + 8); + + key->a = (a << 1) | (b >> 63); + key->b = (b << 1) | (a >> 63); + + if (b >> 63) + key->b ^= 0xc200000000000000UL; + + return 0; +} + +static struct shash_alg ghash_alg = { + .digestsize = GHASH_DIGEST_SIZE, + .init = ghash_init, + .update = ghash_update, + .final = ghash_final, + .setkey = ghash_setkey, + .descsize = sizeof(struct ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "__driver-ghash-ce", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ghash_key), + .cra_module = THIS_MODULE, + }, +}; + +static int ghash_async_init(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); + struct ahash_request *cryptd_req = ahash_request_ctx(req); + struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; + + if (!may_use_simd()) { + memcpy(cryptd_req, req, sizeof(*req)); + ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); + return crypto_ahash_init(cryptd_req); + } else { + struct shash_desc *desc = cryptd_shash_desc(cryptd_req); + struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm); + + desc->tfm = child; + desc->flags = req->base.flags; + return crypto_shash_init(desc); + } +} + +static int ghash_async_update(struct ahash_request *req) +{ + struct ahash_request *cryptd_req = ahash_request_ctx(req); + + if (!may_use_simd()) { + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); + struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; + + memcpy(cryptd_req, req, sizeof(*req)); + ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); + return crypto_ahash_update(cryptd_req); + } else { + struct shash_desc *desc = cryptd_shash_desc(cryptd_req); + return shash_ahash_update(req, desc); + } +} + +static int ghash_async_final(struct ahash_request *req) +{ + struct ahash_request *cryptd_req = ahash_request_ctx(req); + + if (!may_use_simd()) { + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); + struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; + + memcpy(cryptd_req, req, sizeof(*req)); + ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); + return crypto_ahash_final(cryptd_req); + } else { + struct shash_desc *desc = cryptd_shash_desc(cryptd_req); + return crypto_shash_final(desc, req->result); + } +} + +static int ghash_async_digest(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); + struct ahash_request *cryptd_req = ahash_request_ctx(req); + struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; + + if (!may_use_simd()) { + memcpy(cryptd_req, req, sizeof(*req)); + ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); + return crypto_ahash_digest(cryptd_req); + } else { + struct shash_desc *desc = cryptd_shash_desc(cryptd_req); + struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm); + + desc->tfm = child; + desc->flags = req->base.flags; + return shash_ahash_digest(req, desc); + } +} + +static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) +{ + struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); + struct crypto_ahash *child = &ctx->cryptd_tfm->base; + int err; + + crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm) + & CRYPTO_TFM_REQ_MASK); + err = crypto_ahash_setkey(child, key, keylen); + crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child) + & CRYPTO_TFM_RES_MASK); + + return err; +} + +static int ghash_async_init_tfm(struct crypto_tfm *tfm) +{ + struct cryptd_ahash *cryptd_tfm; + struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm); + + cryptd_tfm = cryptd_alloc_ahash("__driver-ghash-ce", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ctx->cryptd_tfm = cryptd_tfm; + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct ahash_request) + + crypto_ahash_reqsize(&cryptd_tfm->base)); + + return 0; +} + +static void ghash_async_exit_tfm(struct crypto_tfm *tfm) +{ + struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm); + + cryptd_free_ahash(ctx->cryptd_tfm); +} + +static struct ahash_alg ghash_async_alg = { + .init = ghash_async_init, + .update = ghash_async_update, + .final = ghash_async_final, + .setkey = ghash_async_setkey, + .digest = ghash_async_digest, + .halg.digestsize = GHASH_DIGEST_SIZE, + .halg.base = { + .cra_name = "ghash", + .cra_driver_name = "ghash-ce", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_type = &crypto_ahash_type, + .cra_ctxsize = sizeof(struct ghash_async_ctx), + .cra_module = THIS_MODULE, + .cra_init = ghash_async_init_tfm, + .cra_exit = ghash_async_exit_tfm, + }, +}; + +static int __init ghash_ce_mod_init(void) +{ + int err; + + if (!(elf_hwcap2 & HWCAP2_PMULL)) + return -ENODEV; + + err = crypto_register_shash(&ghash_alg); + if (err) + return err; + err = crypto_register_ahash(&ghash_async_alg); + if (err) + goto err_shash; + + return 0; + +err_shash: + crypto_unregister_shash(&ghash_alg); + return err; +} + +static void __exit ghash_ce_mod_exit(void) +{ + crypto_unregister_ahash(&ghash_async_alg); + crypto_unregister_shash(&ghash_alg); +} + +module_init(ghash_ce_mod_init); +module_exit(ghash_ce_mod_exit); -- GitLab From a308d66f144c9d5a305ceda4345bebbaf6abc43f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Mar 2015 14:08:36 -0700 Subject: [PATCH 0324/1910] hwrng: omap - remove #ifdefery around PM methods Instead of using #ifdefs let's mark suspend and resume methods as __maybe_unused which will suppress compiler warnings about them being unused and provide better compile coverage. Because SIMPLE_DEV_PM_OPS() produces an empty omap_rng_pm structure in case of !CONFIG_PM_SLEEP neither omap_rng_suspend nor omap_rng_resume will end up being referenced and the change will not result in increasing image size. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 7f3597d2a8ac..5c171b18559f 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -422,9 +422,7 @@ static int omap_rng_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP - -static int omap_rng_suspend(struct device *dev) +static int __maybe_unused omap_rng_suspend(struct device *dev) { struct omap_rng_dev *priv = dev_get_drvdata(dev); @@ -434,7 +432,7 @@ static int omap_rng_suspend(struct device *dev) return 0; } -static int omap_rng_resume(struct device *dev) +static int __maybe_unused omap_rng_resume(struct device *dev) { struct omap_rng_dev *priv = dev_get_drvdata(dev); @@ -445,18 +443,11 @@ static int omap_rng_resume(struct device *dev) } static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume); -#define OMAP_RNG_PM (&omap_rng_pm) - -#else - -#define OMAP_RNG_PM NULL - -#endif static struct platform_driver omap_rng_driver = { .driver = { .name = "omap_rng", - .pm = OMAP_RNG_PM, + .pm = &omap_rng_pm, .of_match_table = of_match_ptr(omap_rng_of_match), }, .probe = omap_rng_probe, -- GitLab From f42613c66524c0fc890b448872169746d392f6bb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 12 Mar 2015 14:28:29 +1100 Subject: [PATCH 0325/1910] linux-next: Tree for Mar 11 (powerpc build failure due to vmx crypto code) crypto: vmx - Fix assembler perl to use _GLOBAL Rather than doing things by hand for global symbols to deal with different calling conventions we already have a macro _GLOBAL in Linux to handle this. Signed-off-by: Herbert Xu Tested-by: Guenter Roeck --- drivers/crypto/vmx/aesp8-ppc.pl | 10 ---------- drivers/crypto/vmx/ghashp8-ppc.pl | 6 ------ drivers/crypto/vmx/ppc-xlate.pl | 29 +++++------------------------ 3 files changed, 5 insertions(+), 40 deletions(-) mode change 100755 => 100644 drivers/crypto/vmx/aesp8-ppc.pl mode change 100755 => 100644 drivers/crypto/vmx/ghashp8-ppc.pl mode change 100755 => 100644 drivers/crypto/vmx/ppc-xlate.pl diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl old mode 100755 new mode 100644 index 3ee8979e7625..6c5c20c6108e --- a/drivers/crypto/vmx/aesp8-ppc.pl +++ b/drivers/crypto/vmx/aesp8-ppc.pl @@ -85,8 +85,6 @@ Lconsts: .asciz "AES for PowerISA 2.07, CRYPTOGAMS by " .globl .${prefix}_set_encrypt_key -.align 5 -.${prefix}_set_encrypt_key: Lset_encrypt_key: mflr r11 $PUSH r11,$LRSAVE($sp) @@ -348,8 +346,6 @@ Lenc_key_abort: .size .${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key .globl .${prefix}_set_decrypt_key -.align 5 -.${prefix}_set_decrypt_key: $STU $sp,-$FRAME($sp) mflr r10 $PUSH r10,$FRAME+$LRSAVE($sp) @@ -405,8 +401,6 @@ my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7)); $code.=<<___; .globl .${prefix}_${dir}crypt -.align 5 -.${prefix}_${dir}crypt: lwz $rounds,240($key) lis r0,0xfc00 mfspr $vrsave,256 @@ -484,8 +478,6 @@ my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)= map("v$_",(4..10)); $code.=<<___; .globl .${prefix}_cbc_encrypt -.align 5 -.${prefix}_cbc_encrypt: ${UCMP}i $len,16 bltlr- @@ -1243,8 +1235,6 @@ my $dat=$tmp; $code.=<<___; .globl .${prefix}_ctr32_encrypt_blocks -.align 5 -.${prefix}_ctr32_encrypt_blocks: ${UCMP}i $len,1 bltlr- diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/drivers/crypto/vmx/ghashp8-ppc.pl old mode 100755 new mode 100644 index e76a58c343c1..0a6f899839dd --- a/drivers/crypto/vmx/ghashp8-ppc.pl +++ b/drivers/crypto/vmx/ghashp8-ppc.pl @@ -54,8 +54,6 @@ $code=<<___; .text .globl .gcm_init_p8 -.align 5 -.gcm_init_p8: lis r0,0xfff0 li r8,0x10 mfspr $vrsave,256 @@ -98,8 +96,6 @@ $code=<<___; .size .gcm_init_p8,.-.gcm_init_p8 .globl .gcm_gmult_p8 -.align 5 -.gcm_gmult_p8: lis r0,0xfff8 li r8,0x10 mfspr $vrsave,256 @@ -148,8 +144,6 @@ $code=<<___; .size .gcm_gmult_p8,.-.gcm_gmult_p8 .globl .gcm_ghash_p8 -.align 5 -.gcm_ghash_p8: lis r0,0xfff8 li r8,0x10 mfspr $vrsave,256 diff --git a/drivers/crypto/vmx/ppc-xlate.pl b/drivers/crypto/vmx/ppc-xlate.pl old mode 100755 new mode 100644 index f89e81429931..a59188494af8 --- a/drivers/crypto/vmx/ppc-xlate.pl +++ b/drivers/crypto/vmx/ppc-xlate.pl @@ -27,25 +27,13 @@ my $globl = sub { /osx/ && do { $name = "_$name"; last; }; - /linux.*(32|64le)/ - && do { $ret .= ".globl $name\n"; - $ret .= ".type $name,\@function"; - last; - }; - /linux.*64/ && do { $ret .= ".globl $name\n"; - $ret .= ".type $name,\@function\n"; - $ret .= ".section \".opd\",\"aw\"\n"; - $ret .= ".align 3\n"; - $ret .= "$name:\n"; - $ret .= ".quad .$name,.TOC.\@tocbase,0\n"; - $ret .= ".previous\n"; - - $name = ".$name"; + /linux/ + && do { $ret = "_GLOBAL($name)"; last; }; } - $ret = ".globl $name" if (!$ret); + $ret = ".globl $name\nalign 5\n$name:" if (!$ret); $$global = $name; $ret; }; @@ -187,6 +175,8 @@ my $mtsle = sub { " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); }; +print "#include \n" if $flavour =~ /linux/; + while($line=<>) { $line =~ s|[#!;].*$||; # get rid of asm-style comments... @@ -199,15 +189,6 @@ while($line=<>) { $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); } - { - $line =~ s|(^[\.\w]+)\:\s*||; - my $label = $1; - if ($label) { - printf "%s:",($GLOBALS{$label} or $label); - printf "\n.localentry\t$GLOBALS{$label},0" if ($GLOBALS{$label} && $flavour =~ /linux.*64le/); - } - } - { $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; my $c = $1; $c = "\t" if ($c eq ""); -- GitLab From 76c07b8265c68d9a89fb4c0a634e373a087f11be Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:00 +0800 Subject: [PATCH 0326/1910] ASoC: Intel: add kcontrol to enable/disable sound effect module waves Add kcontrol to enable/disable module waves. IPC is valid only when module is loaded. Also track module state over suspend so it's state can be restored on resume. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 19 +++++++++ sound/soc/intel/sst-haswell-ipc.h | 3 ++ sound/soc/intel/sst-haswell-pcm.c | 68 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 265d754a4090..ebca9035efce 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -337,6 +337,10 @@ struct sst_hsw { /* FW log stream */ struct sst_hsw_log_stream log_stream; + + /* flags bit field to track module state when resume from RTD3, + * each bit represent state (enabled/disabled) of single module */ + u32 enabled_modules_rtd3; }; #define CREATE_TRACE_POINTS @@ -1986,6 +1990,21 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) return false; } +void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + hsw->enabled_modules_rtd3 |= (1 << module_id); +} + +void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + hsw->enabled_modules_rtd3 &= ~(1 << module_id); +} + +bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + return hsw->enabled_modules_rtd3 & (1 << module_id); +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 30c65b28fa60..48290a1cfe5d 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -477,6 +477,9 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); void sst_hsw_init_module_state(struct sst_hsw *hsw); bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); +bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index a604cc442111..b3de87aac373 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -318,6 +318,54 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol, return 0; } +static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + + ucontrol->value.integer.value[0] = + (sst_hsw_is_module_active(hsw, id) || + sst_hsw_is_module_enabled_rtd3(hsw, id)); + return 0; +} + +static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + int ret = 0; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + bool switch_on = (bool)ucontrol->value.integer.value[0]; + + /* if module is in RAM on the DSP, apply user settings to module through + * ipc. If module is not in RAM on the DSP, store user setting for + * track */ + if (sst_hsw_is_module_loaded(hsw, id)) { + if (switch_on == sst_hsw_is_module_active(hsw, id)) + return 0; + + if (switch_on) + ret = sst_hsw_module_enable(hsw, id, 0); + else + ret = sst_hsw_module_disable(hsw, id, 0); + } else { + if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id)) + return 0; + + if (switch_on) + sst_hsw_set_module_enabled_rtd3(hsw, id); + else + sst_hsw_set_module_disabled_rtd3(hsw, id); + } + + return ret; +} + /* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); @@ -339,6 +387,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), + /* enable/disable module waves */ + SOC_SINGLE_BOOL_EXT("Waves Switch", 0, + hsw_waves_switch_get, hsw_waves_switch_put), }; /* Create DMA buffer page table for DSP */ @@ -1118,10 +1169,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev) { struct hsw_priv_data *pdata = dev_get_drvdata(dev); struct sst_hsw *hsw = pdata->hsw; + int ret; if (pdata->pm_state >= HSW_PM_STATE_RTD3) return 0; + /* fw modules will be unloaded on RTD3, set flag to track */ + if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { + ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); + } sst_hsw_dsp_runtime_suspend(hsw); sst_hsw_dsp_runtime_sleep(hsw); pdata->pm_state = HSW_PM_STATE_RTD3; @@ -1156,6 +1215,15 @@ static int hsw_pcm_runtime_resume(struct device *dev) else if (ret == 1) /* no action required */ return 0; + /* check flag when resume */ + if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { + ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + /* unset flag */ + sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES); + } + pdata->pm_state = HSW_PM_STATE_D0; return ret; } -- GitLab From 201892268b8335ae8c9dc7cc9a0d4bf6e1336f0e Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:01 +0800 Subject: [PATCH 0327/1910] ASoC: Intel: add function to set parameter to sound effect module waves Add function to set parameters to module waves. The parameters can be set only when module is enabled, and parameter size is limited to 500 Bytes. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 59 +++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 26 ++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index ebca9035efce..a97324dff8fa 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -2166,6 +2166,65 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, return ret; } +int sst_hsw_module_set_param(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, u32 parameter_id, + u32 param_size, char *param) +{ + int ret; + unsigned char *data = NULL; + u32 header = 0; + u32 payload_size = 0, transfer_parameter_size = 0; + dma_addr_t dma_addr = 0; + struct sst_hsw_transfer_parameter *parameter; + struct device *dev = hsw->dev; + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | + IPC_MODULE_ID(module_id); + dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); + + payload_size = param_size + + sizeof(struct sst_hsw_transfer_parameter) - + sizeof(struct sst_hsw_transfer_list); + dev_dbg(dev, "parameter size : %d\n", param_size); + dev_dbg(dev, "payload size : %d\n", payload_size); + + if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { + /* short parameter, mailbox can contain data */ + dev_dbg(dev, "transfer parameter size : %d\n", + transfer_parameter_size); + + transfer_parameter_size = ALIGN(payload_size, 4); + dev_dbg(dev, "transfer parameter aligned size : %d\n", + transfer_parameter_size); + + parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); + if (parameter == NULL) + return -ENOMEM; + + memcpy(parameter->data, param, param_size); + } else { + dev_warn(dev, "transfer parameter size too large!"); + return 0; + } + + parameter->parameter_id = parameter_id; + parameter->data_size = param_size; + + ret = ipc_tx_message_wait(hsw, header, + parameter, transfer_parameter_size , NULL, 0); + if (ret < 0) + dev_err(dev, "ipc: module set parameter failed - %d\n", ret); + + kfree(parameter); + + if (data) + dma_free_coherent(hsw->dsp->dma_dev, + param_size, (void *)data, dma_addr); + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 48290a1cfe5d..16bec433265c 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -37,6 +37,7 @@ #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 #define SST_HSW_MAX_INFO_SIZE 64 #define SST_HSW_BUILD_HASH_LENGTH 40 +#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 struct sst_hsw; struct sst_hsw_stream; @@ -187,6 +188,28 @@ enum sst_hsw_performance_action { SST_HSW_PERF_STOP = 1, }; +struct sst_hsw_transfer_info { + uint32_t destination; /* destination address */ + uint32_t reverse:1; /* if 1 data flows from destination */ + uint32_t size:31; /* transfer size in bytes.*/ + uint16_t first_page_offset; /* offset to data in the first page. */ + uint8_t packed_pages; /* page addresses. Each occupies 20 bits */ +} __attribute__((packed)); + +struct sst_hsw_transfer_list { + uint32_t transfers_count; + struct sst_hsw_transfer_info transfers; +} __attribute__((packed)); + +struct sst_hsw_transfer_parameter { + uint32_t parameter_id; + uint32_t data_size; + union { + uint8_t data[1]; + struct sst_hsw_transfer_list transfer_list; + }; +} __attribute__((packed)); + /* SST firmware module info */ struct sst_hsw_module_info { u8 name[SST_HSW_MAX_INFO_SIZE]; @@ -487,6 +510,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, u32 module_id, u32 instance_id); int sst_hsw_module_disable(struct sst_hsw *hsw, u32 module_id, u32 instance_id); +int sst_hsw_module_set_param(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, u32 parameter_id, + u32 param_size, char *param); /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, -- GitLab From 3814c204446822cd3c82ec4e8616600732c1f94e Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:02 +0800 Subject: [PATCH 0328/1910] ASoC: Intel: add kcontrol to set parameter to sound effect module waves Each kcontrol command includes a line of parameters up to 128 bytes. kcontrol command to set param: cset "name='Waves Set Param' <0x01,0xff,...>" or cset-bin-file "name='Waves Set Param' " The parameter lines are stored in a buffer array, so can be read back from buffer rather than from DSP, and be relaunched to DSP when resume from RTD3. The buffer size is 160 parameter lines. kcontrol command to reset the buffer: cset "name='Waves Set Param' 0xff" alsa-lib v1.0.29 or commit 6ea14c36 and f47480af are required to support the kcontrol commands. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 64 +++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 6 +++ sound/soc/intel/sst-haswell-pcm.c | 50 ++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index a97324dff8fa..43fb5f339168 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -341,6 +341,11 @@ struct sst_hsw { /* flags bit field to track module state when resume from RTD3, * each bit represent state (enabled/disabled) of single module */ u32 enabled_modules_rtd3; + + /* buffer to store parameter lines */ + u32 param_idx_w; /* write index */ + u32 param_idx_r; /* read index */ + u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT]; }; #define CREATE_TRACE_POINTS @@ -2005,6 +2010,62 @@ bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) return hsw->enabled_modules_rtd3 & (1 << module_id); } +void sst_hsw_reset_param_buf(struct sst_hsw *hsw) +{ + hsw->param_idx_w = 0; + hsw->param_idx_r = 0; + memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf)); +} + +int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf) +{ + /* save line to the first available position of param buffer */ + if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) { + dev_warn(hsw->dev, "warning: param buffer overflow!\n"); + return -EPERM; + } + memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT); + hsw->param_idx_w++; + return 0; +} + +int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf) +{ + u8 id = 0; + + /* read the first matching line from param buffer */ + while (hsw->param_idx_r < WAVES_PARAM_LINES) { + id = hsw->param_buf[hsw->param_idx_r][0]; + hsw->param_idx_r++; + if (buf[0] == id) { + memcpy(buf, hsw->param_buf[hsw->param_idx_r], + WAVES_PARAM_COUNT); + break; + } + } + if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) { + dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n"); + hsw->param_idx_r = 0; + return 0; + } + return 0; +} + +int sst_hsw_launch_param_buf(struct sst_hsw *hsw) +{ + int ret, idx; + + /* put all param lines to DSP through ipc */ + for (idx = 0; idx < hsw->param_idx_w; idx++) { + ret = sst_hsw_module_set_param(hsw, + SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0], + WAVES_PARAM_COUNT, hsw->param_buf[idx]); + if (ret < 0) + return ret; + } + return 0; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -2299,6 +2360,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (ret < 0) goto boot_err; + /* init param buffer */ + sst_hsw_reset_param_buf(hsw); + /* wait for DSP boot completion */ sst_dsp_boot(hsw->dsp); ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 16bec433265c..06d71aefa1fe 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -38,6 +38,8 @@ #define SST_HSW_MAX_INFO_SIZE 64 #define SST_HSW_BUILD_HASH_LENGTH 40 #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 +#define WAVES_PARAM_COUNT 128 +#define WAVES_PARAM_LINES 160 struct sst_hsw; struct sst_hsw_stream; @@ -503,6 +505,10 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_reset_param_buf(struct sst_hsw *hsw); +int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf); +int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf); +int sst_hsw_launch_param_buf(struct sst_hsw *hsw); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index b3de87aac373..b40ec746bc19 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -366,6 +366,49 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, return ret; } +static int hsw_waves_param_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + + /* return a matching line from param buffer */ + return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data); +} + +static int hsw_waves_param_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + int ret; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + int param_id = ucontrol->value.bytes.data[0]; + int param_size = WAVES_PARAM_COUNT; + + /* clear param buffer and reset buffer index */ + if (param_id == 0xFF) { + sst_hsw_reset_param_buf(hsw); + return 0; + } + + /* store params into buffer */ + ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data); + if (ret < 0) + return ret; + + if (sst_hsw_is_module_loaded(hsw, id)) { + if (!sst_hsw_is_module_active(hsw, id)) + return 0; + + ret = sst_hsw_module_set_param(hsw, id, 0, param_id, + param_size, ucontrol->value.bytes.data); + } + return ret; +} + /* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); @@ -390,6 +433,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { /* enable/disable module waves */ SOC_SINGLE_BOOL_EXT("Waves Switch", 0, hsw_waves_switch_get, hsw_waves_switch_put), + /* set parameters to module waves */ + SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT, + hsw_waves_param_get, hsw_waves_param_put), }; /* Create DMA buffer page table for DSP */ @@ -1218,6 +1264,10 @@ static int hsw_pcm_runtime_resume(struct device *dev) /* check flag when resume */ if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + /* put parameters from buffer to dsp */ + ret = sst_hsw_launch_param_buf(hsw); if (ret < 0) return ret; /* unset flag */ -- GitLab From 42ce5b8ab81e94089c79791fc682a7f46af9790a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 12 Mar 2015 20:25:07 +0800 Subject: [PATCH 0329/1910] ASoC: rt5645: Add TDM support for rt5650 rt5650 and rt5645 use different register bits for TDM configuration. This patch modifies rt5645_set_tdm_slot to support both codecs. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 41 ++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c9a4c5be083b..b79347688873 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2285,23 +2285,42 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_codec *codec = dai->codec; - unsigned int val = 0; + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + unsigned int i_slot_sft, o_slot_sft, i_width_sht, o_width_sht, en_sft; + unsigned int mask, val = 0; + switch (rt5645->codec_type) { + case CODEC_TYPE_RT5650: + en_sft = 15; + i_slot_sft = 10; + o_slot_sft = 8; + i_width_sht = 6; + o_width_sht = 4; + mask = 0x8ff0; + break; + default: + en_sft = 14; + i_slot_sft = o_slot_sft = 12; + i_width_sht = o_width_sht = 10; + mask = 0x7c00; + break; + } if (rx_mask || tx_mask) { - val |= (1 << 14); - snd_soc_update_bits(codec, RT5645_BASS_BACK, - RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB); + val |= (1 << en_sft); + if (rt5645->codec_type == CODEC_TYPE_RT5645) + snd_soc_update_bits(codec, RT5645_BASS_BACK, + RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB); } switch (slots) { case 4: - val |= (1 << 12); + val |= (1 << i_slot_sft) | (1 << o_slot_sft); break; case 6: - val |= (2 << 12); + val |= (2 << i_slot_sft) | (2 << o_slot_sft); break; case 8: - val |= (3 << 12); + val |= (3 << i_slot_sft) | (3 << o_slot_sft); break; case 2: default: @@ -2310,20 +2329,20 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, switch (slot_width) { case 20: - val |= (1 << 10); + val |= (1 << i_width_sht) | (1 << o_width_sht); break; case 24: - val |= (2 << 10); + val |= (2 << i_width_sht) | (2 << o_width_sht); break; case 32: - val |= (3 << 10); + val |= (3 << i_width_sht) | (3 << o_width_sht); break; case 16: default: break; } - snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, 0x7c00, val); + snd_soc_update_bits(codec, RT5645_TDM_CTRL_1, mask, val); return 0; } -- GitLab From 718b25c803df8c1f8f2090c115911d123e34c78a Mon Sep 17 00:00:00 2001 From: Anish Kumar Date: Wed, 11 Mar 2015 15:13:16 -0700 Subject: [PATCH 0330/1910] ASoC: max98925: trivial duplicate typo fix in set_fmt Signed-off-by: Anish Kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index 34fc4d0441fd..1f8e80315749 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -346,7 +346,7 @@ static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, } regmap_update_bits(max98925->regmap, MAX98925_FORMAT, - M98925_DAI_BCI_MASK | M98925_DAI_BCI_MASK, invert); + M98925_DAI_BCI_MASK, invert); return 0; } -- GitLab From e79d74ab25339437447478e4dfe2b35c5b560512 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Mar 2015 16:57:51 +0100 Subject: [PATCH 0331/1910] ALSA: control: Fix breakage of user ctl element addition In the commit [2225e79b9b03: 'ALSA: core: reduce stack usage related to snd_ctl_new()'], the id field of the newly added kctl is untouched, thus all attribute like name string remain empty. The fix is just to add the forgotten memcpy of the id field. Fixes: 2225e79b9b03 ('ALSA: core: reduce stack usage related to snd_ctl_new()') Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/control.c b/sound/core/control.c index 54a412af3224..d677c27746e9 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1267,6 +1267,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, err = snd_ctl_new(&kctl, count, access, file); if (err < 0) return err; + memcpy(&kctl->id, &info->id, sizeof(kctl->id)); kctl->private_data = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); if (kctl->private_data == NULL) { -- GitLab From 19e60e1392d110be03d794e2286dd6cfd779cbe3 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Tue, 10 Mar 2015 17:00:36 +0100 Subject: [PATCH 0332/1910] crypto: testmgr - fix RNG return code enforcement Due to the change to RNGs to always return zero in success case, the invocation of the RNGs in the test manager must be updated as otherwise the RNG self tests are not properly executed any more. Signed-off-by: Stephan Mueller Signed-off-by: Alexander Bergmann Signed-off-by: Herbert Xu --- crypto/testmgr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index f4ed6d4205e7..1f879adf495a 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1474,11 +1474,11 @@ static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template, for (j = 0; j < template[i].loops; j++) { err = crypto_rng_get_bytes(tfm, result, template[i].rlen); - if (err != template[i].rlen) { + if (err < 0) { printk(KERN_ERR "alg: cprng: Failed to obtain " "the correct amount of random data for " - "%s (requested %d, got %d)\n", algo, - template[i].rlen, err); + "%s (requested %d)\n", algo, + template[i].rlen); goto out; } } @@ -1759,7 +1759,7 @@ static int drbg_cavs_test(struct drbg_testvec *test, int pr, ret = crypto_drbg_get_bytes_addtl(drng, buf, test->expectedlen, &addtl); } - if (ret <= 0) { + if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); goto outbuf; @@ -1774,7 +1774,7 @@ static int drbg_cavs_test(struct drbg_testvec *test, int pr, ret = crypto_drbg_get_bytes_addtl(drng, buf, test->expectedlen, &addtl); } - if (ret <= 0) { + if (ret < 0) { printk(KERN_ERR "alg: drbg: could not obtain random data for " "driver %s\n", driver); goto outbuf; -- GitLab From 05713ba9055f1a209d50e480626f36c401bda3ad Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Mar 2015 17:56:26 +0100 Subject: [PATCH 0333/1910] crypto: don't export static symbol The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ type T; identifier f; @@ static T f (...) { ... } @@ identifier r.f; declarer name EXPORT_SYMBOL_GPL; @@ -EXPORT_SYMBOL_GPL(f); // Signed-off-by: Julia Lawall Signed-off-by: Herbert Xu --- arch/x86/crypto/glue_helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/crypto/glue_helper.c b/arch/x86/crypto/glue_helper.c index 432f1d76ceb8..6a85598931b5 100644 --- a/arch/x86/crypto/glue_helper.c +++ b/arch/x86/crypto/glue_helper.c @@ -232,7 +232,6 @@ static void glue_ctr_crypt_final_128bit(const common_glue_ctr_func_t fn_ctr, le128_to_be128((be128 *)walk->iv, &ctrblk); } -EXPORT_SYMBOL_GPL(glue_ctr_crypt_final_128bit); static unsigned int __glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx, struct blkcipher_desc *desc, -- GitLab From b52551e0d0e659db43f5cfa813ae09d4c3744761 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 13 Mar 2015 10:50:26 +0800 Subject: [PATCH 0334/1910] ASoC: rt5645: Remove adc stereo2 filter Remove adc stereo2 filter since it is not in rt5645/rt5650 codec. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 3 --- sound/soc/codecs/rt5645.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index b79347688873..4c384a14de1d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1538,8 +1538,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2, RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("adc stereo2 filter", 1, RT5645_PWR_DIG2, - RT5645_PWR_ADC_S2F_BIT, 0, NULL, 0), SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix), NULL, 0), @@ -1729,7 +1727,6 @@ static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, - { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc }, diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index dbfd98c22f4d..db78e9462876 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -804,8 +804,6 @@ #define RT5645_PWR_DAC_MF_L_BIT 10 #define RT5645_PWR_DAC_MF_R (0x1 << 9) #define RT5645_PWR_DAC_MF_R_BIT 9 -#define RT5645_PWR_ADC_S2F (0x1 << 8) -#define RT5645_PWR_ADC_S2F_BIT 8 #define RT5645_PWR_PDM1 (0x1 << 7) #define RT5645_PWR_PDM1_BIT 7 #define RT5645_PWR_PDM2 (0x1 << 6) -- GitLab From b62c21b71f08b7a4bfd025616ff1da2913a82904 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 12 Mar 2015 23:56:02 -0400 Subject: [PATCH 0335/1910] blk-mq: add blk_mq_init_allocated_queue and export blk_mq_register_disk Add a variant of blk_mq_init_queue that allows a previously allocated queue to be initialized. blk_mq_init_allocated_queue models blk_init_allocated_queue -- which was also created for DM's use. DM's approach to device creation requires a placeholder request_queue be allocated for use with alloc_dev() but the decision about what type of request_queue will be ultimately created is deferred until all component devices referenced in the DM table are processed to determine the table type (request-based, blk-mq request-based, or bio-based). Also, because of DM's late finalization of the request_queue type the call to blk_mq_register_disk() doesn't happen during alloc_dev(). Must export blk_mq_register_disk() so that DM can backfill the 'mq' dir once the blk-mq queue is fully allocated. Signed-off-by: Mike Snitzer Reviewed-by: Ming Lei Signed-off-by: Jens Axboe --- block/blk-mq-sysfs.c | 1 + block/blk-mq.c | 30 ++++++++++++++++++++---------- include/linux/blk-mq.h | 2 ++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index 1630a20d5dcf..b79685e06b70 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c @@ -436,6 +436,7 @@ int blk_mq_register_disk(struct gendisk *disk) return 0; } +EXPORT_SYMBOL_GPL(blk_mq_register_disk); void blk_mq_sysfs_unregister(struct request_queue *q) { diff --git a/block/blk-mq.c b/block/blk-mq.c index b7b8933ec241..3000121840bb 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1890,10 +1890,26 @@ void blk_mq_release(struct request_queue *q) } struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) +{ + struct request_queue *uninit_q, *q; + + uninit_q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node); + if (!uninit_q) + return ERR_PTR(-ENOMEM); + + q = blk_mq_init_allocated_queue(set, uninit_q); + if (IS_ERR(q)) + blk_cleanup_queue(uninit_q); + + return q; +} +EXPORT_SYMBOL(blk_mq_init_queue); + +struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, + struct request_queue *q) { struct blk_mq_hw_ctx **hctxs; struct blk_mq_ctx __percpu *ctx; - struct request_queue *q; unsigned int *map; int i; @@ -1928,17 +1944,13 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) hctxs[i]->queue_num = i; } - q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node); - if (!q) - goto err_hctxs; - /* * Init percpu_ref in atomic mode so that it's faster to shutdown. * See blk_register_queue() for details. */ if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release, PERCPU_REF_INIT_ATOMIC, GFP_KERNEL)) - goto err_mq_usage; + goto err_hctxs; setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q); blk_queue_rq_timeout(q, 30000); @@ -1981,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) blk_mq_init_cpu_queues(q, set->nr_hw_queues); if (blk_mq_init_hw_queues(q, set)) - goto err_mq_usage; + goto err_hctxs; mutex_lock(&all_q_mutex); list_add_tail(&q->all_q_node, &all_q_list); @@ -1993,8 +2005,6 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) return q; -err_mq_usage: - blk_cleanup_queue(q); err_hctxs: kfree(map); for (i = 0; i < set->nr_hw_queues; i++) { @@ -2009,7 +2019,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) free_percpu(ctx); return ERR_PTR(-ENOMEM); } -EXPORT_SYMBOL(blk_mq_init_queue); +EXPORT_SYMBOL(blk_mq_init_allocated_queue); void blk_mq_free_queue(struct request_queue *q) { diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 7aec86127335..9a75c88e8908 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -164,6 +164,8 @@ enum { << BLK_MQ_F_ALLOC_POLICY_START_BIT) struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); +struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, + struct request_queue *q); void blk_mq_finish_init(struct request_queue *q); int blk_mq_register_disk(struct gendisk *); void blk_mq_unregister_disk(struct gendisk *); -- GitLab From b94ec296403e99d5ac9a8c48332cec4118d44b94 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 11 Mar 2015 23:56:38 -0400 Subject: [PATCH 0336/1910] blk-mq: export blk_mq_run_hw_queues Rename blk_mq_run_queues to blk_mq_run_hw_queues, add async argument, and export it. DM's suspend support must be able to run the queue without starting stopped hw queues. Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- block/blk-mq.c | 8 ++++---- include/linux/blk-mq.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 3000121840bb..06614ce0f475 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -33,7 +33,6 @@ static DEFINE_MUTEX(all_q_mutex); static LIST_HEAD(all_q_list); static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx); -static void blk_mq_run_queues(struct request_queue *q); /* * Check if any of the ctx's have pending work in this hardware queue @@ -118,7 +117,7 @@ void blk_mq_freeze_queue_start(struct request_queue *q) if (freeze) { percpu_ref_kill(&q->mq_usage_counter); - blk_mq_run_queues(q); + blk_mq_run_hw_queues(q, false); } } EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_start); @@ -904,7 +903,7 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async) &hctx->run_work, 0); } -static void blk_mq_run_queues(struct request_queue *q) +void blk_mq_run_hw_queues(struct request_queue *q, bool async) { struct blk_mq_hw_ctx *hctx; int i; @@ -915,9 +914,10 @@ static void blk_mq_run_queues(struct request_queue *q) test_bit(BLK_MQ_S_STOPPED, &hctx->state)) continue; - blk_mq_run_hw_queue(hctx, false); + blk_mq_run_hw_queue(hctx, async); } } +EXPORT_SYMBOL(blk_mq_run_hw_queues); void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx) { diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 9a75c88e8908..ebfe707cf722 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -220,6 +220,7 @@ void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx); void blk_mq_stop_hw_queues(struct request_queue *q); void blk_mq_start_hw_queues(struct request_queue *q); void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async); +void blk_mq_run_hw_queues(struct request_queue *q, bool async); void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs); void blk_mq_tag_busy_iter(struct blk_mq_hw_ctx *hctx, busy_iter_fn *fn, void *priv); -- GitLab From b2a0bafa758256442e04d1f34d6d0746b846d23d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Mar 2015 17:21:32 +0100 Subject: [PATCH 0337/1910] ALSA: hda - Use shutdown driver ops instead of reboot notifier The driver shutdown ops is simpler than registering reboot notifier manually. There should be no functional change by this -- the codec driver calls its own callback while the bus driver just calls azx_stop() like before. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_bind.c | 10 ++++++++++ sound/pci/hda/hda_codec.c | 18 ------------------ sound/pci/hda/hda_codec.h | 1 - sound/pci/hda/hda_controller.c | 26 -------------------------- sound/pci/hda/hda_controller.h | 6 ------ sound/pci/hda/hda_intel.c | 16 +++++++++++++--- sound/pci/hda/hda_tegra.c | 16 +++++++++++++--- 7 files changed, 36 insertions(+), 57 deletions(-) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index a49bc45c2ea5..1f40ce3c1696 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -142,6 +143,14 @@ static int hda_codec_driver_remove(struct device *dev) return 0; } +static void hda_codec_driver_shutdown(struct device *dev) +{ + struct hda_codec *codec = dev_to_hda_codec(dev); + + if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify) + codec->patch_ops.reboot_notify(codec); +} + int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, struct module *owner) { @@ -150,6 +159,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, drv->driver.bus = &snd_hda_bus_type; drv->driver.probe = hda_codec_driver_probe; drv->driver.remove = hda_codec_driver_remove; + drv->driver.shutdown = hda_codec_driver_shutdown; drv->driver.pm = &hda_codec_driver_pm; return driver_register(&drv->driver); } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6fecf57c8d7c..3e4fb7a8fdcb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4941,24 +4941,6 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) } } -/** - * snd_hda_bus_reboot_notify - call the reboot notifier of each codec - * @bus: HD-audio bus - */ -void snd_hda_bus_reboot_notify(struct hda_bus *bus) -{ - struct hda_codec *codec; - - if (!bus) - return; - list_for_each_entry(codec, &bus->codec_list, list) { - if (hda_codec_is_power_on(codec) && - codec->patch_ops.reboot_notify) - codec->patch_ops.reboot_notify(codec); - } -} -EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify); - /** * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode * @codec: the HDA codec diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index bf9efb7e1b9a..70851e6d5f10 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -563,7 +563,6 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[]; * Misc */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); -void snd_hda_bus_reboot_notify(struct hda_bus *bus); void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index cae50d5ffb81..b1143f22a0c2 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include "hda_controller.h" @@ -1972,30 +1971,5 @@ int azx_init_stream(struct azx *chip) } EXPORT_SYMBOL_GPL(azx_init_stream); -/* - * reboot notifier for hang-up problem at power-down - */ -static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) -{ - struct azx *chip = container_of(nb, struct azx, reboot_notifier); - snd_hda_bus_reboot_notify(chip->bus); - azx_stop_chip(chip); - return NOTIFY_OK; -} - -void azx_notifier_register(struct azx *chip) -{ - chip->reboot_notifier.notifier_call = azx_halt; - register_reboot_notifier(&chip->reboot_notifier); -} -EXPORT_SYMBOL_GPL(azx_notifier_register); - -void azx_notifier_unregister(struct azx *chip) -{ - if (chip->reboot_notifier.notifier_call) - unregister_reboot_notifier(&chip->reboot_notifier); -} -EXPORT_SYMBOL_GPL(azx_notifier_unregister); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Common HDA driver functions"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 94c1a4719f7f..be1b7ded8d82 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -362,9 +362,6 @@ struct azx { /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; - /* reboot notifier (for mysterious hangup problem at power-down) */ - struct notifier_block reboot_notifier; - #ifdef CONFIG_SND_HDA_DSP_LOADER struct azx_dev saved_azx_dev; #endif @@ -437,7 +434,4 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); int azx_init_stream(struct azx *chip); -void azx_notifier_register(struct azx *chip); -void azx_notifier_unregister(struct azx *chip); - #endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dbc5a593da46..25668fde8480 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1066,8 +1066,6 @@ static int azx_free(struct azx *chip) azx_del_card_list(chip); - azx_notifier_unregister(chip); - hda->init_failed = 1; /* to be sure */ complete_all(&hda->probe_wait); @@ -1900,7 +1898,6 @@ static int azx_probe_continue(struct azx *chip) goto out_free; chip->running = 1; - azx_notifier_register(chip); azx_add_card_list(chip); snd_hda_set_power_save(chip->bus, power_save * 1000); if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) @@ -1921,6 +1918,18 @@ static void azx_remove(struct pci_dev *pci) snd_card_free(card); } +static void azx_shutdown(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + /* PCI IDs */ static const struct pci_device_id azx_ids[] = { /* CPT */ @@ -2143,6 +2152,7 @@ static struct pci_driver azx_driver = { .id_table = azx_ids, .probe = azx_probe, .remove = azx_remove, + .shutdown = azx_shutdown, .driver = { .pm = AZX_PM_OPS, }, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 7586abe91dfb..2e4fd5c56d3b 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -290,8 +290,6 @@ static int hda_tegra_dev_free(struct snd_device *device) int i; struct azx *chip = device->device_data; - azx_notifier_unregister(chip); - if (chip->initialized) { for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); @@ -502,7 +500,6 @@ static int hda_tegra_probe(struct platform_device *pdev) goto out_free; chip->running = 1; - azx_notifier_register(chip); snd_hda_set_power_save(chip->bus, power_save * 1000); return 0; @@ -517,6 +514,18 @@ static int hda_tegra_remove(struct platform_device *pdev) return snd_card_free(dev_get_drvdata(&pdev->dev)); } +static void hda_tegra_shutdown(struct platform_device *pdev) +{ + struct snd_card *card = dev_get_drvdata(&pdev->dev); + struct azx *chip; + + if (!card) + return; + chip = card->private_data; + if (chip && chip->running) + azx_stop_chip(chip); +} + static struct platform_driver tegra_platform_hda = { .driver = { .name = "tegra-hda", @@ -525,6 +534,7 @@ static struct platform_driver tegra_platform_hda = { }, .probe = hda_tegra_probe, .remove = hda_tegra_remove, + .shutdown = hda_tegra_shutdown, }; module_platform_driver(tegra_platform_hda); -- GitLab From bfd343aa1718457d34b99ce6573085ac340da288 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 11 Mar 2015 23:56:39 -0400 Subject: [PATCH 0338/1910] blk-mq: don't wait in blk_mq_queue_enter() if __GFP_WAIT isn't set Return -EBUSY if we're unable to enter a queue immediately when allocating a blk-mq request without __GFP_WAIT. Signed-off-by: Keith Busch Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- block/blk-mq.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 06614ce0f475..59fa23935a0f 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -77,7 +77,7 @@ static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx, clear_bit(CTX_TO_BIT(hctx, ctx), &bm->word); } -static int blk_mq_queue_enter(struct request_queue *q) +static int blk_mq_queue_enter(struct request_queue *q, gfp_t gfp) { while (true) { int ret; @@ -85,6 +85,9 @@ static int blk_mq_queue_enter(struct request_queue *q) if (percpu_ref_tryget_live(&q->mq_usage_counter)) return 0; + if (!(gfp & __GFP_WAIT)) + return -EBUSY; + ret = wait_event_interruptible(q->mq_freeze_wq, !q->mq_freeze_depth || blk_queue_dying(q)); if (blk_queue_dying(q)) @@ -256,7 +259,7 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp, struct blk_mq_alloc_data alloc_data; int ret; - ret = blk_mq_queue_enter(q); + ret = blk_mq_queue_enter(q, gfp); if (ret) return ERR_PTR(ret); @@ -1186,7 +1189,7 @@ static struct request *blk_mq_map_request(struct request_queue *q, int rw = bio_data_dir(bio); struct blk_mq_alloc_data alloc_data; - if (unlikely(blk_mq_queue_enter(q))) { + if (unlikely(blk_mq_queue_enter(q, GFP_KERNEL))) { bio_endio(bio, -EIO); return NULL; } -- GitLab From f4a45c99ae38d53ebb7f26ba3a05c7edab797ce7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 10 Mar 2015 21:44:31 +0100 Subject: [PATCH 0339/1910] udf: remove unused variable in udf_table_free_blocks() Fix set but not used warning. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/balloc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 1ba2baaf4367..02948f04da56 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -358,7 +358,6 @@ static void udf_table_free_blocks(struct super_block *sb, struct kernel_lb_addr eloc; struct extent_position oepos, epos; int8_t etype; - int i; struct udf_inode_info *iinfo; mutex_lock(&sbi->s_alloc_mutex); @@ -425,7 +424,6 @@ static void udf_table_free_blocks(struct super_block *sb, } if (epos.bh != oepos.bh) { - i = -1; oepos.block = epos.block; brelse(oepos.bh); get_bh(epos.bh); -- GitLab From 6fbaad879ae7ba75196b55bab216b9b4d0a541b3 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 10 Mar 2015 21:44:33 +0100 Subject: [PATCH 0340/1910] udf: remove else after return in __load_block_bitmap() else after return is not needed. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/balloc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 02948f04da56..0ee257a32e45 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -63,15 +63,14 @@ static int __load_block_bitmap(struct super_block *sb, block_group, nr_groups); } - if (bitmap->s_block_bitmap[block_group]) { + if (bitmap->s_block_bitmap[block_group]) return block_group; - } else { - retval = read_block_bitmap(sb, bitmap, block_group, - block_group); - if (retval < 0) - return retval; - return block_group; - } + + retval = read_block_bitmap(sb, bitmap, block_group, block_group); + if (retval < 0) + return retval; + + return block_group; } static inline int load_block_bitmap(struct super_block *sb, -- GitLab From 13f0c2b0f67d6f04b21cedce726284b67457bd2f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 10 Mar 2015 21:44:35 +0100 Subject: [PATCH 0341/1910] udf: remove redundant buffer_head.h includes buffer_head.h was already included in udfdecl.h Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/balloc.c | 1 - fs/udf/dir.c | 1 - fs/udf/directory.c | 1 - fs/udf/file.c | 1 - fs/udf/inode.c | 1 - fs/udf/misc.c | 1 - fs/udf/namei.c | 1 - fs/udf/partition.c | 1 - fs/udf/super.c | 1 - fs/udf/symlink.c | 1 - fs/udf/truncate.c | 1 - 11 files changed, 11 deletions(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 0ee257a32e45..acd8e0519ac5 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -21,7 +21,6 @@ #include "udfdecl.h" -#include #include #include "udf_i.h" diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 05e90edd1992..541a12b5792d 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "udf_i.h" #include "udf_sb.h" diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 3e44f575fb9c..c763fda257bf 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -16,7 +16,6 @@ #include #include -#include struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, struct udf_fileident_bh *fibh, diff --git a/fs/udf/file.c b/fs/udf/file.c index 08f3555fbeac..dda8ea7012c6 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "udf_i.h" diff --git a/fs/udf/inode.c b/fs/udf/inode.c index a445d599098d..0001ece68f45 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/udf/misc.c b/fs/udf/misc.c index c175b4dabc14..71d1c25f360d 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "udf_i.h" diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 33b246b82c98..fbf3d90967ea 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/udf/partition.c b/fs/udf/partition.c index d6caf01a2097..5f861ed287c3 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -24,7 +24,6 @@ #include #include -#include #include uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, diff --git a/fs/udf/super.c b/fs/udf/super.c index f169411c4ea0..6299f341967b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index ac10ca939f26..8dfbc4025e2f 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "udf_i.h" static int udf_pc_to_char(struct super_block *sb, unsigned char *from, diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index 8a9657d7f7c6..42b8c57795cb 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -22,7 +22,6 @@ #include "udfdecl.h" #include #include -#include #include "udf_i.h" #include "udf_sb.h" -- GitLab From 1be440de2ac5181495a7295fa9a4c8ad0793f056 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 15 Mar 2015 10:54:23 +0100 Subject: [PATCH 0342/1910] udf: use int for allocated blocks instead of sector_t Fix the following warnings: fs/udf/balloc.c:768:15: warning: conversion to 'sector_t' from 'int' may change the sign of the result [-Wsign-conversion] allocated = udf_bitmap_prealloc_blocks(sb, ^ fs/udf/balloc.c:773:15: warning: conversion to 'sector_t' from 'int' may change the sign of the result [-Wsign-conversion] allocated = udf_table_prealloc_blocks(sb, ^ fs/udf/balloc.c:778:15: warning: conversion to 'sector_t' from 'int' may change the sign of the result [-Wsign-conversion] allocated = udf_bitmap_prealloc_blocks(sb, ^ fs/udf/balloc.c:783:15: warning: conversion to 'sector_t' from 'int' may change the sign of the result [-Wsign-conversion] allocated = udf_table_prealloc_blocks(sb, ^ fs/udf/balloc.c:791:26: warning: conversion to 'loff_t' from 'sector_t' may change the sign of the result [-Wsign-conversion] inode_add_bytes(inode, allocated << sb->s_blocksize_bits); ^ fs/udf/balloc.c:792:2: warning: conversion to 'int' from 'sector_t' may alter its value [-Wconversion] return allocated; Suggested-by: Jan Kara Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/balloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index acd8e0519ac5..6d6a96b4e73f 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -758,7 +758,7 @@ inline int udf_prealloc_blocks(struct super_block *sb, uint32_t block_count) { struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; - sector_t allocated; + int allocated; if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) allocated = udf_bitmap_prealloc_blocks(sb, -- GitLab From c2ce6f9f3dc00daca5714ef070a9a2d4e78eb336 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 10 Feb 2015 09:51:22 +1100 Subject: [PATCH 0343/1910] powerpc: Change vrX register defines to vX to match gcc and glibc As our various loops (copy, string, crypto etc) get more complicated, we want to share implementations between userspace (eg glibc) and the kernel. We also want to write userspace test harnesses to put in tools/testing/selftest. One gratuitous difference between userspace and the kernel is the VMX register definitions - the kernel uses vrX whereas both gcc and glibc use vX. Change the kernel to match userspace. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc_asm.h | 64 ++--- arch/powerpc/include/uapi/asm/ptrace.h | 2 +- arch/powerpc/kernel/tm.S | 8 +- arch/powerpc/kernel/vector.S | 24 +- arch/powerpc/lib/copypage_power7.S | 32 +-- arch/powerpc/lib/copyuser_power7.S | 226 +++++++++--------- arch/powerpc/lib/crtsavres.S | 96 ++++---- arch/powerpc/lib/ldstfp.S | 26 +- arch/powerpc/lib/memcpy_power7.S | 226 +++++++++--------- .../selftests/powerpc/copyloops/asm/ppc_asm.h | 33 --- 10 files changed, 352 insertions(+), 385 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 7e4612528546..c7461032b469 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -637,38 +637,38 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945) /* AltiVec Registers (VPRs) */ -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 +#define v0 0 +#define v1 1 +#define v2 2 +#define v3 3 +#define v4 4 +#define v5 5 +#define v6 6 +#define v7 7 +#define v8 8 +#define v9 9 +#define v10 10 +#define v11 11 +#define v12 12 +#define v13 13 +#define v14 14 +#define v15 15 +#define v16 16 +#define v17 17 +#define v18 18 +#define v19 19 +#define v20 20 +#define v21 21 +#define v22 22 +#define v23 23 +#define v24 24 +#define v25 25 +#define v26 26 +#define v27 27 +#define v28 28 +#define v29 29 +#define v30 30 +#define v31 31 /* VSX Registers (VSRs) */ diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h index 77d2ed35b111..8036b385417d 100644 --- a/arch/powerpc/include/uapi/asm/ptrace.h +++ b/arch/powerpc/include/uapi/asm/ptrace.h @@ -136,7 +136,7 @@ struct pt_regs { #endif /* __powerpc64__ */ /* - * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. + * Get/set all the altivec registers v0..v31, vscr, vrsave, in one go. * The transfer totals 34 quadword. Quadwords 0-31 contain the * corresponding vector registers. Quadword 32 contains the vscr as the * last word (offset 12) within that quadword. Quadword 33 contains the diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 2a324f4cb1b9..5754b226da7e 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -152,9 +152,9 @@ _GLOBAL(tm_reclaim) addi r7, r3, THREAD_TRANSACT_VRSTATE SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */ - mfvscr vr0 + mfvscr v0 li r6, VRSTATE_VSCR - stvx vr0, r7, r6 + stvx v0, r7, r6 dont_backup_vec: mfspr r0, SPRN_VRSAVE std r0, THREAD_TRANSACT_VRSAVE(r3) @@ -359,8 +359,8 @@ _GLOBAL(__tm_recheckpoint) addi r8, r3, THREAD_VRSTATE li r5, VRSTATE_VSCR - lvx vr0, r8, r5 - mtvscr vr0 + lvx v0, r8, r5 + mtvscr v0 REST_32VRS(0, r5, r8) /* r5 scratch, r8 ptr */ dont_restore_vec: ld r5, THREAD_VRSAVE(r3) diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 74f8050518d6..f5c80d567d8d 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -24,8 +24,8 @@ _GLOBAL(do_load_up_transact_altivec) stw r4,THREAD_USED_VR(r3) li r10,THREAD_TRANSACT_VRSTATE+VRSTATE_VSCR - lvx vr0,r10,r3 - mtvscr vr0 + lvx v0,r10,r3 + mtvscr v0 addi r10,r3,THREAD_TRANSACT_VRSTATE REST_32VRS(0,r4,r10) @@ -52,8 +52,8 @@ _GLOBAL(vec_enable) */ _GLOBAL(load_vr_state) li r4,VRSTATE_VSCR - lvx vr0,r4,r3 - mtvscr vr0 + lvx v0,r4,r3 + mtvscr v0 REST_32VRS(0,r4,r3) blr @@ -63,9 +63,9 @@ _GLOBAL(load_vr_state) */ _GLOBAL(store_vr_state) SAVE_32VRS(0, r4, r3) - mfvscr vr0 + mfvscr v0 li r4, VRSTATE_VSCR - stvx vr0, r4, r3 + stvx v0, r4, r3 blr /* @@ -104,9 +104,9 @@ _GLOBAL(load_up_altivec) addi r4,r4,THREAD addi r6,r4,THREAD_VRSTATE SAVE_32VRS(0,r5,r6) - mfvscr vr0 + mfvscr v0 li r10,VRSTATE_VSCR - stvx vr0,r10,r6 + stvx v0,r10,r6 /* Disable VMX for last_task_used_altivec */ PPC_LL r5,PT_REGS(r4) toreal(r5) @@ -142,8 +142,8 @@ _GLOBAL(load_up_altivec) li r4,1 li r10,VRSTATE_VSCR stw r4,THREAD_USED_VR(r5) - lvx vr0,r10,r6 - mtvscr vr0 + lvx v0,r10,r6 + mtvscr v0 REST_32VRS(0,r4,r6) #ifndef CONFIG_SMP /* Update last_task_used_altivec to 'current' */ @@ -186,9 +186,9 @@ _GLOBAL(giveup_altivec) addi r7,r3,THREAD_VRSTATE 2: PPC_LCMPI 0,r5,0 SAVE_32VRS(0,r4,r7) - mfvscr vr0 + mfvscr v0 li r4,VRSTATE_VSCR - stvx vr0,r4,r7 + stvx v0,r4,r7 beq 1f PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) #ifdef CONFIG_VSX diff --git a/arch/powerpc/lib/copypage_power7.S b/arch/powerpc/lib/copypage_power7.S index d7dafb3777ac..a84d333ecb09 100644 --- a/arch/powerpc/lib/copypage_power7.S +++ b/arch/powerpc/lib/copypage_power7.S @@ -83,23 +83,23 @@ _GLOBAL(copypage_power7) li r12,112 .align 5 -1: lvx vr7,r0,r4 - lvx vr6,r4,r6 - lvx vr5,r4,r7 - lvx vr4,r4,r8 - lvx vr3,r4,r9 - lvx vr2,r4,r10 - lvx vr1,r4,r11 - lvx vr0,r4,r12 +1: lvx v7,r0,r4 + lvx v6,r4,r6 + lvx v5,r4,r7 + lvx v4,r4,r8 + lvx v3,r4,r9 + lvx v2,r4,r10 + lvx v1,r4,r11 + lvx v0,r4,r12 addi r4,r4,128 - stvx vr7,r0,r3 - stvx vr6,r3,r6 - stvx vr5,r3,r7 - stvx vr4,r3,r8 - stvx vr3,r3,r9 - stvx vr2,r3,r10 - stvx vr1,r3,r11 - stvx vr0,r3,r12 + stvx v7,r0,r3 + stvx v6,r3,r6 + stvx v5,r3,r7 + stvx v4,r3,r8 + stvx v3,r3,r9 + stvx v2,r3,r10 + stvx v1,r3,r11 + stvx v0,r3,r12 addi r3,r3,128 bdnz 1b diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S index 92ee840529bc..da0c568d18c4 100644 --- a/arch/powerpc/lib/copyuser_power7.S +++ b/arch/powerpc/lib/copyuser_power7.S @@ -388,29 +388,29 @@ err3; std r0,0(r3) li r11,48 bf cr7*4+3,5f -err3; lvx vr1,r0,r4 +err3; lvx v1,r0,r4 addi r4,r4,16 -err3; stvx vr1,r0,r3 +err3; stvx v1,r0,r3 addi r3,r3,16 5: bf cr7*4+2,6f -err3; lvx vr1,r0,r4 -err3; lvx vr0,r4,r9 +err3; lvx v1,r0,r4 +err3; lvx v0,r4,r9 addi r4,r4,32 -err3; stvx vr1,r0,r3 -err3; stvx vr0,r3,r9 +err3; stvx v1,r0,r3 +err3; stvx v0,r3,r9 addi r3,r3,32 6: bf cr7*4+1,7f -err3; lvx vr3,r0,r4 -err3; lvx vr2,r4,r9 -err3; lvx vr1,r4,r10 -err3; lvx vr0,r4,r11 +err3; lvx v3,r0,r4 +err3; lvx v2,r4,r9 +err3; lvx v1,r4,r10 +err3; lvx v0,r4,r11 addi r4,r4,64 -err3; stvx vr3,r0,r3 -err3; stvx vr2,r3,r9 -err3; stvx vr1,r3,r10 -err3; stvx vr0,r3,r11 +err3; stvx v3,r0,r3 +err3; stvx v2,r3,r9 +err3; stvx v1,r3,r10 +err3; stvx v0,r3,r11 addi r3,r3,64 7: sub r5,r5,r6 @@ -433,23 +433,23 @@ err3; stvx vr0,r3,r11 */ .align 5 8: -err4; lvx vr7,r0,r4 -err4; lvx vr6,r4,r9 -err4; lvx vr5,r4,r10 -err4; lvx vr4,r4,r11 -err4; lvx vr3,r4,r12 -err4; lvx vr2,r4,r14 -err4; lvx vr1,r4,r15 -err4; lvx vr0,r4,r16 +err4; lvx v7,r0,r4 +err4; lvx v6,r4,r9 +err4; lvx v5,r4,r10 +err4; lvx v4,r4,r11 +err4; lvx v3,r4,r12 +err4; lvx v2,r4,r14 +err4; lvx v1,r4,r15 +err4; lvx v0,r4,r16 addi r4,r4,128 -err4; stvx vr7,r0,r3 -err4; stvx vr6,r3,r9 -err4; stvx vr5,r3,r10 -err4; stvx vr4,r3,r11 -err4; stvx vr3,r3,r12 -err4; stvx vr2,r3,r14 -err4; stvx vr1,r3,r15 -err4; stvx vr0,r3,r16 +err4; stvx v7,r0,r3 +err4; stvx v6,r3,r9 +err4; stvx v5,r3,r10 +err4; stvx v4,r3,r11 +err4; stvx v3,r3,r12 +err4; stvx v2,r3,r14 +err4; stvx v1,r3,r15 +err4; stvx v0,r3,r16 addi r3,r3,128 bdnz 8b @@ -463,29 +463,29 @@ err4; stvx vr0,r3,r16 mtocrf 0x01,r6 bf cr7*4+1,9f -err3; lvx vr3,r0,r4 -err3; lvx vr2,r4,r9 -err3; lvx vr1,r4,r10 -err3; lvx vr0,r4,r11 +err3; lvx v3,r0,r4 +err3; lvx v2,r4,r9 +err3; lvx v1,r4,r10 +err3; lvx v0,r4,r11 addi r4,r4,64 -err3; stvx vr3,r0,r3 -err3; stvx vr2,r3,r9 -err3; stvx vr1,r3,r10 -err3; stvx vr0,r3,r11 +err3; stvx v3,r0,r3 +err3; stvx v2,r3,r9 +err3; stvx v1,r3,r10 +err3; stvx v0,r3,r11 addi r3,r3,64 9: bf cr7*4+2,10f -err3; lvx vr1,r0,r4 -err3; lvx vr0,r4,r9 +err3; lvx v1,r0,r4 +err3; lvx v0,r4,r9 addi r4,r4,32 -err3; stvx vr1,r0,r3 -err3; stvx vr0,r3,r9 +err3; stvx v1,r0,r3 +err3; stvx v0,r3,r9 addi r3,r3,32 10: bf cr7*4+3,11f -err3; lvx vr1,r0,r4 +err3; lvx v1,r0,r4 addi r4,r4,16 -err3; stvx vr1,r0,r3 +err3; stvx v1,r0,r3 addi r3,r3,16 /* Up to 15B to go */ @@ -560,42 +560,42 @@ err3; stw r7,4(r3) li r10,32 li r11,48 - LVS(vr16,0,r4) /* Setup permute control vector */ -err3; lvx vr0,0,r4 + LVS(v16,0,r4) /* Setup permute control vector */ +err3; lvx v0,0,r4 addi r4,r4,16 bf cr7*4+3,5f -err3; lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) +err3; lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) addi r4,r4,16 -err3; stvx vr8,r0,r3 +err3; stvx v8,r0,r3 addi r3,r3,16 - vor vr0,vr1,vr1 + vor v0,v1,v1 5: bf cr7*4+2,6f -err3; lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) -err3; lvx vr0,r4,r9 - VPERM(vr9,vr1,vr0,vr16) +err3; lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) +err3; lvx v0,r4,r9 + VPERM(v9,v1,v0,v16) addi r4,r4,32 -err3; stvx vr8,r0,r3 -err3; stvx vr9,r3,r9 +err3; stvx v8,r0,r3 +err3; stvx v9,r3,r9 addi r3,r3,32 6: bf cr7*4+1,7f -err3; lvx vr3,r0,r4 - VPERM(vr8,vr0,vr3,vr16) -err3; lvx vr2,r4,r9 - VPERM(vr9,vr3,vr2,vr16) -err3; lvx vr1,r4,r10 - VPERM(vr10,vr2,vr1,vr16) -err3; lvx vr0,r4,r11 - VPERM(vr11,vr1,vr0,vr16) +err3; lvx v3,r0,r4 + VPERM(v8,v0,v3,v16) +err3; lvx v2,r4,r9 + VPERM(v9,v3,v2,v16) +err3; lvx v1,r4,r10 + VPERM(v10,v2,v1,v16) +err3; lvx v0,r4,r11 + VPERM(v11,v1,v0,v16) addi r4,r4,64 -err3; stvx vr8,r0,r3 -err3; stvx vr9,r3,r9 -err3; stvx vr10,r3,r10 -err3; stvx vr11,r3,r11 +err3; stvx v8,r0,r3 +err3; stvx v9,r3,r9 +err3; stvx v10,r3,r10 +err3; stvx v11,r3,r11 addi r3,r3,64 7: sub r5,r5,r6 @@ -618,31 +618,31 @@ err3; stvx vr11,r3,r11 */ .align 5 8: -err4; lvx vr7,r0,r4 - VPERM(vr8,vr0,vr7,vr16) -err4; lvx vr6,r4,r9 - VPERM(vr9,vr7,vr6,vr16) -err4; lvx vr5,r4,r10 - VPERM(vr10,vr6,vr5,vr16) -err4; lvx vr4,r4,r11 - VPERM(vr11,vr5,vr4,vr16) -err4; lvx vr3,r4,r12 - VPERM(vr12,vr4,vr3,vr16) -err4; lvx vr2,r4,r14 - VPERM(vr13,vr3,vr2,vr16) -err4; lvx vr1,r4,r15 - VPERM(vr14,vr2,vr1,vr16) -err4; lvx vr0,r4,r16 - VPERM(vr15,vr1,vr0,vr16) +err4; lvx v7,r0,r4 + VPERM(v8,v0,v7,v16) +err4; lvx v6,r4,r9 + VPERM(v9,v7,v6,v16) +err4; lvx v5,r4,r10 + VPERM(v10,v6,v5,v16) +err4; lvx v4,r4,r11 + VPERM(v11,v5,v4,v16) +err4; lvx v3,r4,r12 + VPERM(v12,v4,v3,v16) +err4; lvx v2,r4,r14 + VPERM(v13,v3,v2,v16) +err4; lvx v1,r4,r15 + VPERM(v14,v2,v1,v16) +err4; lvx v0,r4,r16 + VPERM(v15,v1,v0,v16) addi r4,r4,128 -err4; stvx vr8,r0,r3 -err4; stvx vr9,r3,r9 -err4; stvx vr10,r3,r10 -err4; stvx vr11,r3,r11 -err4; stvx vr12,r3,r12 -err4; stvx vr13,r3,r14 -err4; stvx vr14,r3,r15 -err4; stvx vr15,r3,r16 +err4; stvx v8,r0,r3 +err4; stvx v9,r3,r9 +err4; stvx v10,r3,r10 +err4; stvx v11,r3,r11 +err4; stvx v12,r3,r12 +err4; stvx v13,r3,r14 +err4; stvx v14,r3,r15 +err4; stvx v15,r3,r16 addi r3,r3,128 bdnz 8b @@ -656,36 +656,36 @@ err4; stvx vr15,r3,r16 mtocrf 0x01,r6 bf cr7*4+1,9f -err3; lvx vr3,r0,r4 - VPERM(vr8,vr0,vr3,vr16) -err3; lvx vr2,r4,r9 - VPERM(vr9,vr3,vr2,vr16) -err3; lvx vr1,r4,r10 - VPERM(vr10,vr2,vr1,vr16) -err3; lvx vr0,r4,r11 - VPERM(vr11,vr1,vr0,vr16) +err3; lvx v3,r0,r4 + VPERM(v8,v0,v3,v16) +err3; lvx v2,r4,r9 + VPERM(v9,v3,v2,v16) +err3; lvx v1,r4,r10 + VPERM(v10,v2,v1,v16) +err3; lvx v0,r4,r11 + VPERM(v11,v1,v0,v16) addi r4,r4,64 -err3; stvx vr8,r0,r3 -err3; stvx vr9,r3,r9 -err3; stvx vr10,r3,r10 -err3; stvx vr11,r3,r11 +err3; stvx v8,r0,r3 +err3; stvx v9,r3,r9 +err3; stvx v10,r3,r10 +err3; stvx v11,r3,r11 addi r3,r3,64 9: bf cr7*4+2,10f -err3; lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) -err3; lvx vr0,r4,r9 - VPERM(vr9,vr1,vr0,vr16) +err3; lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) +err3; lvx v0,r4,r9 + VPERM(v9,v1,v0,v16) addi r4,r4,32 -err3; stvx vr8,r0,r3 -err3; stvx vr9,r3,r9 +err3; stvx v8,r0,r3 +err3; stvx v9,r3,r9 addi r3,r3,32 10: bf cr7*4+3,11f -err3; lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) +err3; lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) addi r4,r4,16 -err3; stvx vr8,r0,r3 +err3; stvx v8,r0,r3 addi r3,r3,16 /* Up to 15B to go */ diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S index a5b30c71a8d3..18af0b3d3eb2 100644 --- a/arch/powerpc/lib/crtsavres.S +++ b/arch/powerpc/lib/crtsavres.S @@ -236,78 +236,78 @@ _GLOBAL(_rest32gpr_31_x) _GLOBAL(_savevr_20) li r11,-192 - stvx vr20,r11,r0 + stvx v20,r11,r0 _GLOBAL(_savevr_21) li r11,-176 - stvx vr21,r11,r0 + stvx v21,r11,r0 _GLOBAL(_savevr_22) li r11,-160 - stvx vr22,r11,r0 + stvx v22,r11,r0 _GLOBAL(_savevr_23) li r11,-144 - stvx vr23,r11,r0 + stvx v23,r11,r0 _GLOBAL(_savevr_24) li r11,-128 - stvx vr24,r11,r0 + stvx v24,r11,r0 _GLOBAL(_savevr_25) li r11,-112 - stvx vr25,r11,r0 + stvx v25,r11,r0 _GLOBAL(_savevr_26) li r11,-96 - stvx vr26,r11,r0 + stvx v26,r11,r0 _GLOBAL(_savevr_27) li r11,-80 - stvx vr27,r11,r0 + stvx v27,r11,r0 _GLOBAL(_savevr_28) li r11,-64 - stvx vr28,r11,r0 + stvx v28,r11,r0 _GLOBAL(_savevr_29) li r11,-48 - stvx vr29,r11,r0 + stvx v29,r11,r0 _GLOBAL(_savevr_30) li r11,-32 - stvx vr30,r11,r0 + stvx v30,r11,r0 _GLOBAL(_savevr_31) li r11,-16 - stvx vr31,r11,r0 + stvx v31,r11,r0 blr _GLOBAL(_restvr_20) li r11,-192 - lvx vr20,r11,r0 + lvx v20,r11,r0 _GLOBAL(_restvr_21) li r11,-176 - lvx vr21,r11,r0 + lvx v21,r11,r0 _GLOBAL(_restvr_22) li r11,-160 - lvx vr22,r11,r0 + lvx v22,r11,r0 _GLOBAL(_restvr_23) li r11,-144 - lvx vr23,r11,r0 + lvx v23,r11,r0 _GLOBAL(_restvr_24) li r11,-128 - lvx vr24,r11,r0 + lvx v24,r11,r0 _GLOBAL(_restvr_25) li r11,-112 - lvx vr25,r11,r0 + lvx v25,r11,r0 _GLOBAL(_restvr_26) li r11,-96 - lvx vr26,r11,r0 + lvx v26,r11,r0 _GLOBAL(_restvr_27) li r11,-80 - lvx vr27,r11,r0 + lvx v27,r11,r0 _GLOBAL(_restvr_28) li r11,-64 - lvx vr28,r11,r0 + lvx v28,r11,r0 _GLOBAL(_restvr_29) li r11,-48 - lvx vr29,r11,r0 + lvx v29,r11,r0 _GLOBAL(_restvr_30) li r11,-32 - lvx vr30,r11,r0 + lvx v30,r11,r0 _GLOBAL(_restvr_31) li r11,-16 - lvx vr31,r11,r0 + lvx v31,r11,r0 blr #endif /* CONFIG_ALTIVEC */ @@ -443,101 +443,101 @@ _restgpr0_31: .globl _savevr_20 _savevr_20: li r12,-192 - stvx vr20,r12,r0 + stvx v20,r12,r0 .globl _savevr_21 _savevr_21: li r12,-176 - stvx vr21,r12,r0 + stvx v21,r12,r0 .globl _savevr_22 _savevr_22: li r12,-160 - stvx vr22,r12,r0 + stvx v22,r12,r0 .globl _savevr_23 _savevr_23: li r12,-144 - stvx vr23,r12,r0 + stvx v23,r12,r0 .globl _savevr_24 _savevr_24: li r12,-128 - stvx vr24,r12,r0 + stvx v24,r12,r0 .globl _savevr_25 _savevr_25: li r12,-112 - stvx vr25,r12,r0 + stvx v25,r12,r0 .globl _savevr_26 _savevr_26: li r12,-96 - stvx vr26,r12,r0 + stvx v26,r12,r0 .globl _savevr_27 _savevr_27: li r12,-80 - stvx vr27,r12,r0 + stvx v27,r12,r0 .globl _savevr_28 _savevr_28: li r12,-64 - stvx vr28,r12,r0 + stvx v28,r12,r0 .globl _savevr_29 _savevr_29: li r12,-48 - stvx vr29,r12,r0 + stvx v29,r12,r0 .globl _savevr_30 _savevr_30: li r12,-32 - stvx vr30,r12,r0 + stvx v30,r12,r0 .globl _savevr_31 _savevr_31: li r12,-16 - stvx vr31,r12,r0 + stvx v31,r12,r0 blr .globl _restvr_20 _restvr_20: li r12,-192 - lvx vr20,r12,r0 + lvx v20,r12,r0 .globl _restvr_21 _restvr_21: li r12,-176 - lvx vr21,r12,r0 + lvx v21,r12,r0 .globl _restvr_22 _restvr_22: li r12,-160 - lvx vr22,r12,r0 + lvx v22,r12,r0 .globl _restvr_23 _restvr_23: li r12,-144 - lvx vr23,r12,r0 + lvx v23,r12,r0 .globl _restvr_24 _restvr_24: li r12,-128 - lvx vr24,r12,r0 + lvx v24,r12,r0 .globl _restvr_25 _restvr_25: li r12,-112 - lvx vr25,r12,r0 + lvx v25,r12,r0 .globl _restvr_26 _restvr_26: li r12,-96 - lvx vr26,r12,r0 + lvx v26,r12,r0 .globl _restvr_27 _restvr_27: li r12,-80 - lvx vr27,r12,r0 + lvx v27,r12,r0 .globl _restvr_28 _restvr_28: li r12,-64 - lvx vr28,r12,r0 + lvx v28,r12,r0 .globl _restvr_29 _restvr_29: li r12,-48 - lvx vr29,r12,r0 + lvx v29,r12,r0 .globl _restvr_30 _restvr_30: li r12,-32 - lvx vr30,r12,r0 + lvx v30,r12,r0 .globl _restvr_31 _restvr_31: li r12,-16 - lvx vr31,r12,r0 + lvx v31,r12,r0 blr #endif /* CONFIG_ALTIVEC */ diff --git a/arch/powerpc/lib/ldstfp.S b/arch/powerpc/lib/ldstfp.S index 85aec08ab234..659c7ca1f4f2 100644 --- a/arch/powerpc/lib/ldstfp.S +++ b/arch/powerpc/lib/ldstfp.S @@ -184,16 +184,16 @@ _GLOBAL(do_stfd) extab 2b,3b #ifdef CONFIG_ALTIVEC -/* Get the contents of vrN into vr0; N is in r3. */ +/* Get the contents of vrN into v0; N is in r3. */ _GLOBAL(get_vr) mflr r0 rlwinm r3,r3,3,0xf8 bcl 20,31,1f - blr /* vr0 is already in vr0 */ + blr /* v0 is already in v0 */ nop reg = 1 .rept 31 - vor vr0,reg,reg /* assembler doesn't know vmr? */ + vor v0,reg,reg /* assembler doesn't know vmr? */ blr reg = reg + 1 .endr @@ -203,16 +203,16 @@ reg = reg + 1 mtlr r0 bctr -/* Put the contents of vr0 into vrN; N is in r3. */ +/* Put the contents of v0 into vrN; N is in r3. */ _GLOBAL(put_vr) mflr r0 rlwinm r3,r3,3,0xf8 bcl 20,31,1f - blr /* vr0 is already in vr0 */ + blr /* v0 is already in v0 */ nop reg = 1 .rept 31 - vor reg,vr0,vr0 + vor reg,v0,v0 blr reg = reg + 1 .endr @@ -234,13 +234,13 @@ _GLOBAL(do_lvx) MTMSRD(r7) isync beq cr7,1f - stvx vr0,r1,r8 + stvx v0,r1,r8 1: li r9,-EFAULT -2: lvx vr0,0,r4 +2: lvx v0,0,r4 li r9,0 3: beq cr7,4f bl put_vr - lvx vr0,r1,r8 + lvx v0,r1,r8 4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) mtlr r0 MTMSRD(r6) @@ -262,13 +262,13 @@ _GLOBAL(do_stvx) MTMSRD(r7) isync beq cr7,1f - stvx vr0,r1,r8 + stvx v0,r1,r8 bl get_vr 1: li r9,-EFAULT -2: stvx vr0,0,r4 +2: stvx v0,0,r4 li r9,0 3: beq cr7,4f - lvx vr0,r1,r8 + lvx v0,r1,r8 4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1) mtlr r0 MTMSRD(r6) @@ -304,7 +304,7 @@ _GLOBAL(put_vsr) mflr r0 rlwinm r3,r3,3,0x1f8 bcl 20,31,1f - blr /* vr0 is already in vr0 */ + blr /* v0 is already in v0 */ nop reg = 1 .rept 63 diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index 0830587df16e..786234fd4e91 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -321,29 +321,29 @@ _GLOBAL(memcpy_power7) li r11,48 bf cr7*4+3,5f - lvx vr1,r0,r4 + lvx v1,r0,r4 addi r4,r4,16 - stvx vr1,r0,r3 + stvx v1,r0,r3 addi r3,r3,16 5: bf cr7*4+2,6f - lvx vr1,r0,r4 - lvx vr0,r4,r9 + lvx v1,r0,r4 + lvx v0,r4,r9 addi r4,r4,32 - stvx vr1,r0,r3 - stvx vr0,r3,r9 + stvx v1,r0,r3 + stvx v0,r3,r9 addi r3,r3,32 6: bf cr7*4+1,7f - lvx vr3,r0,r4 - lvx vr2,r4,r9 - lvx vr1,r4,r10 - lvx vr0,r4,r11 + lvx v3,r0,r4 + lvx v2,r4,r9 + lvx v1,r4,r10 + lvx v0,r4,r11 addi r4,r4,64 - stvx vr3,r0,r3 - stvx vr2,r3,r9 - stvx vr1,r3,r10 - stvx vr0,r3,r11 + stvx v3,r0,r3 + stvx v2,r3,r9 + stvx v1,r3,r10 + stvx v0,r3,r11 addi r3,r3,64 7: sub r5,r5,r6 @@ -366,23 +366,23 @@ _GLOBAL(memcpy_power7) */ .align 5 8: - lvx vr7,r0,r4 - lvx vr6,r4,r9 - lvx vr5,r4,r10 - lvx vr4,r4,r11 - lvx vr3,r4,r12 - lvx vr2,r4,r14 - lvx vr1,r4,r15 - lvx vr0,r4,r16 + lvx v7,r0,r4 + lvx v6,r4,r9 + lvx v5,r4,r10 + lvx v4,r4,r11 + lvx v3,r4,r12 + lvx v2,r4,r14 + lvx v1,r4,r15 + lvx v0,r4,r16 addi r4,r4,128 - stvx vr7,r0,r3 - stvx vr6,r3,r9 - stvx vr5,r3,r10 - stvx vr4,r3,r11 - stvx vr3,r3,r12 - stvx vr2,r3,r14 - stvx vr1,r3,r15 - stvx vr0,r3,r16 + stvx v7,r0,r3 + stvx v6,r3,r9 + stvx v5,r3,r10 + stvx v4,r3,r11 + stvx v3,r3,r12 + stvx v2,r3,r14 + stvx v1,r3,r15 + stvx v0,r3,r16 addi r3,r3,128 bdnz 8b @@ -396,29 +396,29 @@ _GLOBAL(memcpy_power7) mtocrf 0x01,r6 bf cr7*4+1,9f - lvx vr3,r0,r4 - lvx vr2,r4,r9 - lvx vr1,r4,r10 - lvx vr0,r4,r11 + lvx v3,r0,r4 + lvx v2,r4,r9 + lvx v1,r4,r10 + lvx v0,r4,r11 addi r4,r4,64 - stvx vr3,r0,r3 - stvx vr2,r3,r9 - stvx vr1,r3,r10 - stvx vr0,r3,r11 + stvx v3,r0,r3 + stvx v2,r3,r9 + stvx v1,r3,r10 + stvx v0,r3,r11 addi r3,r3,64 9: bf cr7*4+2,10f - lvx vr1,r0,r4 - lvx vr0,r4,r9 + lvx v1,r0,r4 + lvx v0,r4,r9 addi r4,r4,32 - stvx vr1,r0,r3 - stvx vr0,r3,r9 + stvx v1,r0,r3 + stvx v0,r3,r9 addi r3,r3,32 10: bf cr7*4+3,11f - lvx vr1,r0,r4 + lvx v1,r0,r4 addi r4,r4,16 - stvx vr1,r0,r3 + stvx v1,r0,r3 addi r3,r3,16 /* Up to 15B to go */ @@ -494,42 +494,42 @@ _GLOBAL(memcpy_power7) li r10,32 li r11,48 - LVS(vr16,0,r4) /* Setup permute control vector */ - lvx vr0,0,r4 + LVS(v16,0,r4) /* Setup permute control vector */ + lvx v0,0,r4 addi r4,r4,16 bf cr7*4+3,5f - lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) + lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) addi r4,r4,16 - stvx vr8,r0,r3 + stvx v8,r0,r3 addi r3,r3,16 - vor vr0,vr1,vr1 + vor v0,v1,v1 5: bf cr7*4+2,6f - lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) - lvx vr0,r4,r9 - VPERM(vr9,vr1,vr0,vr16) + lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) + lvx v0,r4,r9 + VPERM(v9,v1,v0,v16) addi r4,r4,32 - stvx vr8,r0,r3 - stvx vr9,r3,r9 + stvx v8,r0,r3 + stvx v9,r3,r9 addi r3,r3,32 6: bf cr7*4+1,7f - lvx vr3,r0,r4 - VPERM(vr8,vr0,vr3,vr16) - lvx vr2,r4,r9 - VPERM(vr9,vr3,vr2,vr16) - lvx vr1,r4,r10 - VPERM(vr10,vr2,vr1,vr16) - lvx vr0,r4,r11 - VPERM(vr11,vr1,vr0,vr16) + lvx v3,r0,r4 + VPERM(v8,v0,v3,v16) + lvx v2,r4,r9 + VPERM(v9,v3,v2,v16) + lvx v1,r4,r10 + VPERM(v10,v2,v1,v16) + lvx v0,r4,r11 + VPERM(v11,v1,v0,v16) addi r4,r4,64 - stvx vr8,r0,r3 - stvx vr9,r3,r9 - stvx vr10,r3,r10 - stvx vr11,r3,r11 + stvx v8,r0,r3 + stvx v9,r3,r9 + stvx v10,r3,r10 + stvx v11,r3,r11 addi r3,r3,64 7: sub r5,r5,r6 @@ -552,31 +552,31 @@ _GLOBAL(memcpy_power7) */ .align 5 8: - lvx vr7,r0,r4 - VPERM(vr8,vr0,vr7,vr16) - lvx vr6,r4,r9 - VPERM(vr9,vr7,vr6,vr16) - lvx vr5,r4,r10 - VPERM(vr10,vr6,vr5,vr16) - lvx vr4,r4,r11 - VPERM(vr11,vr5,vr4,vr16) - lvx vr3,r4,r12 - VPERM(vr12,vr4,vr3,vr16) - lvx vr2,r4,r14 - VPERM(vr13,vr3,vr2,vr16) - lvx vr1,r4,r15 - VPERM(vr14,vr2,vr1,vr16) - lvx vr0,r4,r16 - VPERM(vr15,vr1,vr0,vr16) + lvx v7,r0,r4 + VPERM(v8,v0,v7,v16) + lvx v6,r4,r9 + VPERM(v9,v7,v6,v16) + lvx v5,r4,r10 + VPERM(v10,v6,v5,v16) + lvx v4,r4,r11 + VPERM(v11,v5,v4,v16) + lvx v3,r4,r12 + VPERM(v12,v4,v3,v16) + lvx v2,r4,r14 + VPERM(v13,v3,v2,v16) + lvx v1,r4,r15 + VPERM(v14,v2,v1,v16) + lvx v0,r4,r16 + VPERM(v15,v1,v0,v16) addi r4,r4,128 - stvx vr8,r0,r3 - stvx vr9,r3,r9 - stvx vr10,r3,r10 - stvx vr11,r3,r11 - stvx vr12,r3,r12 - stvx vr13,r3,r14 - stvx vr14,r3,r15 - stvx vr15,r3,r16 + stvx v8,r0,r3 + stvx v9,r3,r9 + stvx v10,r3,r10 + stvx v11,r3,r11 + stvx v12,r3,r12 + stvx v13,r3,r14 + stvx v14,r3,r15 + stvx v15,r3,r16 addi r3,r3,128 bdnz 8b @@ -590,36 +590,36 @@ _GLOBAL(memcpy_power7) mtocrf 0x01,r6 bf cr7*4+1,9f - lvx vr3,r0,r4 - VPERM(vr8,vr0,vr3,vr16) - lvx vr2,r4,r9 - VPERM(vr9,vr3,vr2,vr16) - lvx vr1,r4,r10 - VPERM(vr10,vr2,vr1,vr16) - lvx vr0,r4,r11 - VPERM(vr11,vr1,vr0,vr16) + lvx v3,r0,r4 + VPERM(v8,v0,v3,v16) + lvx v2,r4,r9 + VPERM(v9,v3,v2,v16) + lvx v1,r4,r10 + VPERM(v10,v2,v1,v16) + lvx v0,r4,r11 + VPERM(v11,v1,v0,v16) addi r4,r4,64 - stvx vr8,r0,r3 - stvx vr9,r3,r9 - stvx vr10,r3,r10 - stvx vr11,r3,r11 + stvx v8,r0,r3 + stvx v9,r3,r9 + stvx v10,r3,r10 + stvx v11,r3,r11 addi r3,r3,64 9: bf cr7*4+2,10f - lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) - lvx vr0,r4,r9 - VPERM(vr9,vr1,vr0,vr16) + lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) + lvx v0,r4,r9 + VPERM(v9,v1,v0,v16) addi r4,r4,32 - stvx vr8,r0,r3 - stvx vr9,r3,r9 + stvx v8,r0,r3 + stvx v9,r3,r9 addi r3,r3,32 10: bf cr7*4+3,11f - lvx vr1,r0,r4 - VPERM(vr8,vr0,vr1,vr16) + lvx v1,r0,r4 + VPERM(v8,v0,v1,v16) addi r4,r4,16 - stvx vr8,r0,r3 + stvx v8,r0,r3 addi r3,r3,16 /* Up to 15B to go */ diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h index d1dc37425510..50ae7d2091ce 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h @@ -4,39 +4,6 @@ #define r1 1 -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 - #define R14 r14 #define R15 r15 #define R16 r16 -- GitLab From df99e6eb3f5279a211ee50b2321357c0d9ed8224 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 10 Feb 2015 09:51:23 +1100 Subject: [PATCH 0344/1910] powerpc: Change vsrX register defines to vsX to match gcc and glibc As our various loops (copy, string, crypto etc) get more complicated, we want to share implementations between userspace (eg glibc) and the kernel. We also want to write userspace test harnesses to put in tools/testing/selftest. One gratuitous difference between userspace and the kernel is the VSX register definitions - the kernel uses vsrX whereas gcc uses vsX. Change the kernel to match userspace. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc_asm.h | 128 ++++++++++++++--------------- arch/powerpc/lib/ldstfp.S | 6 +- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index c7461032b469..dd0fc18d8103 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -672,70 +672,70 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945) /* VSX Registers (VSRs) */ -#define vsr0 0 -#define vsr1 1 -#define vsr2 2 -#define vsr3 3 -#define vsr4 4 -#define vsr5 5 -#define vsr6 6 -#define vsr7 7 -#define vsr8 8 -#define vsr9 9 -#define vsr10 10 -#define vsr11 11 -#define vsr12 12 -#define vsr13 13 -#define vsr14 14 -#define vsr15 15 -#define vsr16 16 -#define vsr17 17 -#define vsr18 18 -#define vsr19 19 -#define vsr20 20 -#define vsr21 21 -#define vsr22 22 -#define vsr23 23 -#define vsr24 24 -#define vsr25 25 -#define vsr26 26 -#define vsr27 27 -#define vsr28 28 -#define vsr29 29 -#define vsr30 30 -#define vsr31 31 -#define vsr32 32 -#define vsr33 33 -#define vsr34 34 -#define vsr35 35 -#define vsr36 36 -#define vsr37 37 -#define vsr38 38 -#define vsr39 39 -#define vsr40 40 -#define vsr41 41 -#define vsr42 42 -#define vsr43 43 -#define vsr44 44 -#define vsr45 45 -#define vsr46 46 -#define vsr47 47 -#define vsr48 48 -#define vsr49 49 -#define vsr50 50 -#define vsr51 51 -#define vsr52 52 -#define vsr53 53 -#define vsr54 54 -#define vsr55 55 -#define vsr56 56 -#define vsr57 57 -#define vsr58 58 -#define vsr59 59 -#define vsr60 60 -#define vsr61 61 -#define vsr62 62 -#define vsr63 63 +#define vs0 0 +#define vs1 1 +#define vs2 2 +#define vs3 3 +#define vs4 4 +#define vs5 5 +#define vs6 6 +#define vs7 7 +#define vs8 8 +#define vs9 9 +#define vs10 10 +#define vs11 11 +#define vs12 12 +#define vs13 13 +#define vs14 14 +#define vs15 15 +#define vs16 16 +#define vs17 17 +#define vs18 18 +#define vs19 19 +#define vs20 20 +#define vs21 21 +#define vs22 22 +#define vs23 23 +#define vs24 24 +#define vs25 25 +#define vs26 26 +#define vs27 27 +#define vs28 28 +#define vs29 29 +#define vs30 30 +#define vs31 31 +#define vs32 32 +#define vs33 33 +#define vs34 34 +#define vs35 35 +#define vs36 36 +#define vs37 37 +#define vs38 38 +#define vs39 39 +#define vs40 40 +#define vs41 41 +#define vs42 42 +#define vs43 43 +#define vs44 44 +#define vs45 45 +#define vs46 46 +#define vs47 47 +#define vs48 48 +#define vs49 49 +#define vs50 50 +#define vs51 51 +#define vs52 52 +#define vs53 53 +#define vs54 54 +#define vs55 55 +#define vs56 56 +#define vs57 57 +#define vs58 58 +#define vs59 59 +#define vs60 60 +#define vs61 61 +#define vs62 62 +#define vs63 63 /* SPE Registers (EVPRs) */ diff --git a/arch/powerpc/lib/ldstfp.S b/arch/powerpc/lib/ldstfp.S index 659c7ca1f4f2..5d0cdbfbe3f2 100644 --- a/arch/powerpc/lib/ldstfp.S +++ b/arch/powerpc/lib/ldstfp.S @@ -280,12 +280,12 @@ _GLOBAL(do_stvx) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_VSX -/* Get the contents of vsrN into vsr0; N is in r3. */ +/* Get the contents of vsN into vs0; N is in r3. */ _GLOBAL(get_vsr) mflr r0 rlwinm r3,r3,3,0x1f8 bcl 20,31,1f - blr /* vsr0 is already in vsr0 */ + blr /* vs0 is already in vs0 */ nop reg = 1 .rept 63 @@ -299,7 +299,7 @@ reg = reg + 1 mtlr r0 bctr -/* Put the contents of vsr0 into vsrN; N is in r3. */ +/* Put the contents of vs0 into vsN; N is in r3. */ _GLOBAL(put_vsr) mflr r0 rlwinm r3,r3,3,0x1f8 -- GitLab From b962f5a446d8cf4f313a2cef728e7e71b2f20811 Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 12 Feb 2015 16:25:27 +1100 Subject: [PATCH 0345/1910] powerpc/powernv: only register log if OPAL supports doing so Correct use of REGISTER/UNREGISTER is to check if the token exists before calling. If we don't we get a "OPAL: Called with bad token 101 !" error, which is harmless but may be alarming to some. Signed-off-by: Stewart Smith Acked-by: Vasant Hegde Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/opal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 18fd4e71c9c1..45f0d9aa3733 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -665,6 +665,9 @@ static void __init opal_dump_region_init(void) uint64_t size; int rc; + if (!opal_check_token(OPAL_REGISTER_DUMP_REGION)) + return; + /* Register kernel log buffer */ addr = log_buf_addr_get(); if (addr == NULL) @@ -823,7 +826,8 @@ void opal_shutdown(void) } /* Unregister memory dump region */ - opal_unregister_dump_region(OPAL_DUMP_REGION_LOG_BUF); + if (opal_check_token(OPAL_UNREGISTER_DUMP_REGION)) + opal_unregister_dump_region(OPAL_DUMP_REGION_LOG_BUF); } /* Export this so that test modules can use it */ -- GitLab From fc81de63104e7603e6695225c2573f27aaeb4a28 Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 12 Feb 2015 16:25:28 +1100 Subject: [PATCH 0346/1910] powerpc/powernv: only call OPAL_ELOG_RESEND if firmware supports it Otherwise firmware complains: "OPAL: Called with bad token 74 !" as not all OPAL systems have the ability to resend error logs. Signed-off-by: Stewart Smith Acked-by: Vasant Hegde Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/opal-elog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c index 518fe95dbf24..38ce757e5e2a 100644 --- a/arch/powerpc/platforms/powernv/opal-elog.c +++ b/arch/powerpc/platforms/powernv/opal-elog.c @@ -313,7 +313,8 @@ int __init opal_elog_init(void) } /* We are now ready to pull error logs from opal. */ - opal_resend_pending_logs(); + if (opal_check_token(OPAL_ELOG_RESEND)) + opal_resend_pending_logs(); return 0; } -- GitLab From 7e73a3b7f34240871fa5556d952e801178970741 Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 12 Feb 2015 16:25:29 +1100 Subject: [PATCH 0347/1910] powerpc/powernv: only call OPAL_RESEND_DUMP if firmware supports it Not all OPAL platforms support resending system dumps, so check that current firmware supports it first. Otherwise we get firmware complaining: "OPAL: Called with bad token 91 !" Signed-off-by: Stewart Smith Acked-by: Vasant Hegde Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/opal-dump.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c index 23260f7dfa7a..5aa9c1ce4de3 100644 --- a/arch/powerpc/platforms/powernv/opal-dump.c +++ b/arch/powerpc/platforms/powernv/opal-dump.c @@ -452,5 +452,6 @@ void __init opal_platform_dump_init(void) return; } - opal_dump_resend_notification(); + if (opal_check_token(OPAL_DUMP_RESEND)) + opal_dump_resend_notification(); } -- GitLab From 7f4eec395351ef25166276ad9dc3390b83ab41b6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 3 Feb 2015 13:55:53 +0100 Subject: [PATCH 0348/1910] powerpc: Delete unnecessary checks before kfree() The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Michael Ellerman --- arch/powerpc/lib/rheap.c | 2 +- arch/powerpc/platforms/cell/celleb_pci.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c index a1060a868e69..69abf844c2c3 100644 --- a/arch/powerpc/lib/rheap.c +++ b/arch/powerpc/lib/rheap.c @@ -284,7 +284,7 @@ EXPORT_SYMBOL_GPL(rh_create); */ void rh_destroy(rh_info_t * info) { - if ((info->flags & RHIF_STATIC_BLOCK) == 0 && info->block != NULL) + if ((info->flags & RHIF_STATIC_BLOCK) == 0) kfree(info->block); if ((info->flags & RHIF_STATIC_INFO) == 0) diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 3ce70ded2d6a..9b11b5dd8b7c 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -393,11 +393,10 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, error: if (mem_init_done) { - if (config && *config) + if (config) kfree(*config); - if (res && *res) + if (res) kfree(*res); - } else { if (config && *config) { size = 256; -- GitLab From 755457f992b7382298cda685b3ed1fea06d80fea Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Thu, 2 Oct 2014 15:49:15 +0200 Subject: [PATCH 0349/1910] powerpc/boot: Makefile cleanup The $(image-n) variable will never exist, because unset Kconfig options are '' and not 'n'. Signed-off-by: Michal Marek Signed-off-by: Michael Ellerman --- arch/powerpc/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8a5bc1cfc6aa..73a19fac4850 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -317,7 +317,7 @@ endif # Allow extra targets to be added to the defconfig image-y += $(subst ",,$(CONFIG_EXTRA_TARGETS)) -initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-)) +initrd- := $(patsubst zImage%, zImage.initrd%, $(image-)) initrd-y := $(patsubst zImage%, zImage.initrd%, \ $(patsubst dtbImage%, dtbImage.initrd%, \ $(patsubst simpleImage%, simpleImage.initrd%, \ -- GitLab From d800ba1218799efb07b3d11a84f38bf05a94daf5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Feb 2015 20:01:53 +1100 Subject: [PATCH 0350/1910] powerpc/powernv: Move OPAL API definitions to opal-api.h We'd like to get to the stage where the OPAL API is defined in a header that is identical between Linux and Skiboot. As step one, split the bits that actually define the API into opal-api.h. The Linux specific parts stay in opal.h. Signed-off-by: Michael Ellerman Acked-by: Stewart Smith --- arch/powerpc/include/asm/opal-api.h | 763 ++++++++++++++++++++++++++++ arch/powerpc/include/asm/opal.h | 757 +-------------------------- 2 files changed, 769 insertions(+), 751 deletions(-) create mode 100644 arch/powerpc/include/asm/opal-api.h diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h new file mode 100644 index 000000000000..a90176a428ee --- /dev/null +++ b/arch/powerpc/include/asm/opal-api.h @@ -0,0 +1,763 @@ +/* + * PowerNV OPAL definitions. + * + * Copyright 2011 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __OPAL_API_H +#define __OPAL_API_H + +/****** OPAL APIs ******/ + +/* Return codes */ +#define OPAL_SUCCESS 0 +#define OPAL_PARAMETER -1 +#define OPAL_BUSY -2 +#define OPAL_PARTIAL -3 +#define OPAL_CONSTRAINED -4 +#define OPAL_CLOSED -5 +#define OPAL_HARDWARE -6 +#define OPAL_UNSUPPORTED -7 +#define OPAL_PERMISSION -8 +#define OPAL_NO_MEM -9 +#define OPAL_RESOURCE -10 +#define OPAL_INTERNAL_ERROR -11 +#define OPAL_BUSY_EVENT -12 +#define OPAL_HARDWARE_FROZEN -13 +#define OPAL_WRONG_STATE -14 +#define OPAL_ASYNC_COMPLETION -15 +#define OPAL_I2C_TIMEOUT -17 +#define OPAL_I2C_INVALID_CMD -18 +#define OPAL_I2C_LBUS_PARITY -19 +#define OPAL_I2C_BKEND_OVERRUN -20 +#define OPAL_I2C_BKEND_ACCESS -21 +#define OPAL_I2C_ARBT_LOST -22 +#define OPAL_I2C_NACK_RCVD -23 +#define OPAL_I2C_STOP_ERR -24 + +/* API Tokens (in r0) */ +#define OPAL_INVALID_CALL -1 +#define OPAL_CONSOLE_WRITE 1 +#define OPAL_CONSOLE_READ 2 +#define OPAL_RTC_READ 3 +#define OPAL_RTC_WRITE 4 +#define OPAL_CEC_POWER_DOWN 5 +#define OPAL_CEC_REBOOT 6 +#define OPAL_READ_NVRAM 7 +#define OPAL_WRITE_NVRAM 8 +#define OPAL_HANDLE_INTERRUPT 9 +#define OPAL_POLL_EVENTS 10 +#define OPAL_PCI_SET_HUB_TCE_MEMORY 11 +#define OPAL_PCI_SET_PHB_TCE_MEMORY 12 +#define OPAL_PCI_CONFIG_READ_BYTE 13 +#define OPAL_PCI_CONFIG_READ_HALF_WORD 14 +#define OPAL_PCI_CONFIG_READ_WORD 15 +#define OPAL_PCI_CONFIG_WRITE_BYTE 16 +#define OPAL_PCI_CONFIG_WRITE_HALF_WORD 17 +#define OPAL_PCI_CONFIG_WRITE_WORD 18 +#define OPAL_SET_XIVE 19 +#define OPAL_GET_XIVE 20 +#define OPAL_GET_COMPLETION_TOKEN_STATUS 21 /* obsolete */ +#define OPAL_REGISTER_OPAL_EXCEPTION_HANDLER 22 +#define OPAL_PCI_EEH_FREEZE_STATUS 23 +#define OPAL_PCI_SHPC 24 +#define OPAL_CONSOLE_WRITE_BUFFER_SPACE 25 +#define OPAL_PCI_EEH_FREEZE_CLEAR 26 +#define OPAL_PCI_PHB_MMIO_ENABLE 27 +#define OPAL_PCI_SET_PHB_MEM_WINDOW 28 +#define OPAL_PCI_MAP_PE_MMIO_WINDOW 29 +#define OPAL_PCI_SET_PHB_TABLE_MEMORY 30 +#define OPAL_PCI_SET_PE 31 +#define OPAL_PCI_SET_PELTV 32 +#define OPAL_PCI_SET_MVE 33 +#define OPAL_PCI_SET_MVE_ENABLE 34 +#define OPAL_PCI_GET_XIVE_REISSUE 35 +#define OPAL_PCI_SET_XIVE_REISSUE 36 +#define OPAL_PCI_SET_XIVE_PE 37 +#define OPAL_GET_XIVE_SOURCE 38 +#define OPAL_GET_MSI_32 39 +#define OPAL_GET_MSI_64 40 +#define OPAL_START_CPU 41 +#define OPAL_QUERY_CPU_STATUS 42 +#define OPAL_WRITE_OPPANEL 43 +#define OPAL_PCI_MAP_PE_DMA_WINDOW 44 +#define OPAL_PCI_MAP_PE_DMA_WINDOW_REAL 45 +#define OPAL_PCI_RESET 49 +#define OPAL_PCI_GET_HUB_DIAG_DATA 50 +#define OPAL_PCI_GET_PHB_DIAG_DATA 51 +#define OPAL_PCI_FENCE_PHB 52 +#define OPAL_PCI_REINIT 53 +#define OPAL_PCI_MASK_PE_ERROR 54 +#define OPAL_SET_SLOT_LED_STATUS 55 +#define OPAL_GET_EPOW_STATUS 56 +#define OPAL_SET_SYSTEM_ATTENTION_LED 57 +#define OPAL_RESERVED1 58 +#define OPAL_RESERVED2 59 +#define OPAL_PCI_NEXT_ERROR 60 +#define OPAL_PCI_EEH_FREEZE_STATUS2 61 +#define OPAL_PCI_POLL 62 +#define OPAL_PCI_MSI_EOI 63 +#define OPAL_PCI_GET_PHB_DIAG_DATA2 64 +#define OPAL_XSCOM_READ 65 +#define OPAL_XSCOM_WRITE 66 +#define OPAL_LPC_READ 67 +#define OPAL_LPC_WRITE 68 +#define OPAL_RETURN_CPU 69 +#define OPAL_REINIT_CPUS 70 +#define OPAL_ELOG_READ 71 +#define OPAL_ELOG_WRITE 72 +#define OPAL_ELOG_ACK 73 +#define OPAL_ELOG_RESEND 74 +#define OPAL_ELOG_SIZE 75 +#define OPAL_FLASH_VALIDATE 76 +#define OPAL_FLASH_MANAGE 77 +#define OPAL_FLASH_UPDATE 78 +#define OPAL_RESYNC_TIMEBASE 79 +#define OPAL_CHECK_TOKEN 80 +#define OPAL_DUMP_INIT 81 +#define OPAL_DUMP_INFO 82 +#define OPAL_DUMP_READ 83 +#define OPAL_DUMP_ACK 84 +#define OPAL_GET_MSG 85 +#define OPAL_CHECK_ASYNC_COMPLETION 86 +#define OPAL_SYNC_HOST_REBOOT 87 +#define OPAL_SENSOR_READ 88 +#define OPAL_GET_PARAM 89 +#define OPAL_SET_PARAM 90 +#define OPAL_DUMP_RESEND 91 +#define OPAL_PCI_SET_PHB_CXL_MODE 93 +#define OPAL_DUMP_INFO2 94 +#define OPAL_PCI_ERR_INJECT 96 +#define OPAL_PCI_EEH_FREEZE_SET 97 +#define OPAL_HANDLE_HMI 98 +#define OPAL_CONFIG_CPU_IDLE_STATE 99 +#define OPAL_SLW_SET_REG 100 +#define OPAL_REGISTER_DUMP_REGION 101 +#define OPAL_UNREGISTER_DUMP_REGION 102 +#define OPAL_WRITE_TPO 103 +#define OPAL_READ_TPO 104 +#define OPAL_IPMI_SEND 107 +#define OPAL_IPMI_RECV 108 +#define OPAL_I2C_REQUEST 109 + +/* Device tree flags */ + +/* Flags set in power-mgmt nodes in device tree if + * respective idle states are supported in the platform. + */ +#define OPAL_PM_NAP_ENABLED 0x00010000 +#define OPAL_PM_SLEEP_ENABLED 0x00020000 +#define OPAL_PM_WINKLE_ENABLED 0x00040000 +#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 + +#ifndef __ASSEMBLY__ + +/* Other enums */ +enum OpalVendorApiTokens { + OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999 +}; + +enum OpalFreezeState { + OPAL_EEH_STOPPED_NOT_FROZEN = 0, + OPAL_EEH_STOPPED_MMIO_FREEZE = 1, + OPAL_EEH_STOPPED_DMA_FREEZE = 2, + OPAL_EEH_STOPPED_MMIO_DMA_FREEZE = 3, + OPAL_EEH_STOPPED_RESET = 4, + OPAL_EEH_STOPPED_TEMP_UNAVAIL = 5, + OPAL_EEH_STOPPED_PERM_UNAVAIL = 6 +}; + +enum OpalEehFreezeActionToken { + OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1, + OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3, + + OPAL_EEH_ACTION_SET_FREEZE_MMIO = 1, + OPAL_EEH_ACTION_SET_FREEZE_DMA = 2, + OPAL_EEH_ACTION_SET_FREEZE_ALL = 3 +}; + +enum OpalPciStatusToken { + OPAL_EEH_NO_ERROR = 0, + OPAL_EEH_IOC_ERROR = 1, + OPAL_EEH_PHB_ERROR = 2, + OPAL_EEH_PE_ERROR = 3, + OPAL_EEH_PE_MMIO_ERROR = 4, + OPAL_EEH_PE_DMA_ERROR = 5 +}; + +enum OpalPciErrorSeverity { + OPAL_EEH_SEV_NO_ERROR = 0, + OPAL_EEH_SEV_IOC_DEAD = 1, + OPAL_EEH_SEV_PHB_DEAD = 2, + OPAL_EEH_SEV_PHB_FENCED = 3, + OPAL_EEH_SEV_PE_ER = 4, + OPAL_EEH_SEV_INF = 5 +}; + +enum OpalErrinjectType { + OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR = 0, + OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64 = 1, +}; + +enum OpalErrinjectFunc { + /* IOA bus specific errors */ + OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR = 0, + OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA = 1, + OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR = 2, + OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA = 3, + OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR = 4, + OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA = 5, + OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR = 6, + OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA = 7, + OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR = 8, + OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA = 9, + OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR = 10, + OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA = 11, + OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR = 12, + OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA = 13, + OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER = 14, + OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET = 15, + OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR = 16, + OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA = 17, + OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER = 18, + OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET = 19, +}; + +enum OpalShpcAction { + OPAL_SHPC_GET_LINK_STATE = 0, + OPAL_SHPC_GET_SLOT_STATE = 1 +}; + +enum OpalShpcLinkState { + OPAL_SHPC_LINK_DOWN = 0, + OPAL_SHPC_LINK_UP = 1 +}; + +enum OpalMmioWindowType { + OPAL_M32_WINDOW_TYPE = 1, + OPAL_M64_WINDOW_TYPE = 2, + OPAL_IO_WINDOW_TYPE = 3 +}; + +enum OpalShpcSlotState { + OPAL_SHPC_DEV_NOT_PRESENT = 0, + OPAL_SHPC_DEV_PRESENT = 1 +}; + +enum OpalExceptionHandler { + OPAL_MACHINE_CHECK_HANDLER = 1, + OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2, + OPAL_SOFTPATCH_HANDLER = 3 +}; + +enum OpalPendingState { + OPAL_EVENT_OPAL_INTERNAL = 0x1, + OPAL_EVENT_NVRAM = 0x2, + OPAL_EVENT_RTC = 0x4, + OPAL_EVENT_CONSOLE_OUTPUT = 0x8, + OPAL_EVENT_CONSOLE_INPUT = 0x10, + OPAL_EVENT_ERROR_LOG_AVAIL = 0x20, + OPAL_EVENT_ERROR_LOG = 0x40, + OPAL_EVENT_EPOW = 0x80, + OPAL_EVENT_LED_STATUS = 0x100, + OPAL_EVENT_PCI_ERROR = 0x200, + OPAL_EVENT_DUMP_AVAIL = 0x400, + OPAL_EVENT_MSG_PENDING = 0x800, +}; + +enum OpalMessageType { + OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc, + * additional params function-specific + */ + OPAL_MSG_MEM_ERR, + OPAL_MSG_EPOW, + OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */ + OPAL_MSG_HMI_EVT, + OPAL_MSG_TYPE_MAX, +}; + +enum OpalThreadStatus { + OPAL_THREAD_INACTIVE = 0x0, + OPAL_THREAD_STARTED = 0x1, + OPAL_THREAD_UNAVAILABLE = 0x2 /* opal-v3 */ +}; + +enum OpalPciBusCompare { + OpalPciBusAny = 0, /* Any bus number match */ + OpalPciBus3Bits = 2, /* Match top 3 bits of bus number */ + OpalPciBus4Bits = 3, /* Match top 4 bits of bus number */ + OpalPciBus5Bits = 4, /* Match top 5 bits of bus number */ + OpalPciBus6Bits = 5, /* Match top 6 bits of bus number */ + OpalPciBus7Bits = 6, /* Match top 7 bits of bus number */ + OpalPciBusAll = 7, /* Match bus number exactly */ +}; + +enum OpalDeviceCompare { + OPAL_IGNORE_RID_DEVICE_NUMBER = 0, + OPAL_COMPARE_RID_DEVICE_NUMBER = 1 +}; + +enum OpalFuncCompare { + OPAL_IGNORE_RID_FUNCTION_NUMBER = 0, + OPAL_COMPARE_RID_FUNCTION_NUMBER = 1 +}; + +enum OpalPeAction { + OPAL_UNMAP_PE = 0, + OPAL_MAP_PE = 1 +}; + +enum OpalPeltvAction { + OPAL_REMOVE_PE_FROM_DOMAIN = 0, + OPAL_ADD_PE_TO_DOMAIN = 1 +}; + +enum OpalMveEnableAction { + OPAL_DISABLE_MVE = 0, + OPAL_ENABLE_MVE = 1 +}; + +enum OpalM64EnableAction { + OPAL_DISABLE_M64 = 0, + OPAL_ENABLE_M64_SPLIT = 1, + OPAL_ENABLE_M64_NON_SPLIT = 2 +}; + +enum OpalPciResetScope { + OPAL_RESET_PHB_COMPLETE = 1, + OPAL_RESET_PCI_LINK = 2, + OPAL_RESET_PHB_ERROR = 3, + OPAL_RESET_PCI_HOT = 4, + OPAL_RESET_PCI_FUNDAMENTAL = 5, + OPAL_RESET_PCI_IODA_TABLE = 6 +}; + +enum OpalPciReinitScope { + OPAL_REINIT_PCI_DEV = 1000 +}; + +enum OpalPciResetState { + OPAL_DEASSERT_RESET = 0, + OPAL_ASSERT_RESET = 1 +}; + +enum OpalPciMaskAction { + OPAL_UNMASK_ERROR_TYPE = 0, + OPAL_MASK_ERROR_TYPE = 1 +}; + +enum OpalSlotLedType { + OPAL_SLOT_LED_ID_TYPE = 0, + OPAL_SLOT_LED_FAULT_TYPE = 1 +}; + +enum OpalLedAction { + OPAL_TURN_OFF_LED = 0, + OPAL_TURN_ON_LED = 1, + OPAL_QUERY_LED_STATE_AFTER_BUSY = 2 +}; + +enum OpalEpowStatus { + OPAL_EPOW_NONE = 0, + OPAL_EPOW_UPS = 1, + OPAL_EPOW_OVER_AMBIENT_TEMP = 2, + OPAL_EPOW_OVER_INTERNAL_TEMP = 3 +}; + +/* + * Address cycle types for LPC accesses. These also correspond + * to the content of the first cell of the "reg" property for + * device nodes on the LPC bus + */ +enum OpalLPCAddressType { + OPAL_LPC_MEM = 0, + OPAL_LPC_IO = 1, + OPAL_LPC_FW = 2, +}; + +/* System parameter permission */ +enum OpalSysparamPerm { + OPAL_SYSPARAM_READ = 0x1, + OPAL_SYSPARAM_WRITE = 0x2, + OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE), +}; + +struct opal_msg { + __be32 msg_type; + __be32 reserved; + __be64 params[8]; +}; + +enum { + OPAL_IPMI_MSG_FORMAT_VERSION_1 = 1, +}; + +struct opal_ipmi_msg { + uint8_t version; + uint8_t netfn; + uint8_t cmd; + uint8_t data[]; +}; + +/* FSP memory errors handling */ +enum OpalMemErr_Version { + OpalMemErr_V1 = 1, +}; + +enum OpalMemErrType { + OPAL_MEM_ERR_TYPE_RESILIENCE = 0, + OPAL_MEM_ERR_TYPE_DYN_DALLOC, + OPAL_MEM_ERR_TYPE_SCRUB, +}; + +/* Memory Reilience error type */ +enum OpalMemErr_ResilErrType { + OPAL_MEM_RESILIENCE_CE = 0, + OPAL_MEM_RESILIENCE_UE, + OPAL_MEM_RESILIENCE_UE_SCRUB, +}; + +/* Dynamic Memory Deallocation type */ +enum OpalMemErr_DynErrType { + OPAL_MEM_DYNAMIC_DEALLOC = 0, +}; + +/* OpalMemoryErrorData->flags */ +#define OPAL_MEM_CORRECTED_ERROR 0x0001 +#define OPAL_MEM_THRESHOLD_EXCEEDED 0x0002 +#define OPAL_MEM_ACK_REQUIRED 0x8000 + +struct OpalMemoryErrorData { + enum OpalMemErr_Version version:8; /* 0x00 */ + enum OpalMemErrType type:8; /* 0x01 */ + __be16 flags; /* 0x02 */ + uint8_t reserved_1[4]; /* 0x04 */ + + union { + /* Memory Resilience corrected/uncorrected error info */ + struct { + enum OpalMemErr_ResilErrType resil_err_type:8; + uint8_t reserved_1[7]; + __be64 physical_address_start; + __be64 physical_address_end; + } resilience; + /* Dynamic memory deallocation error info */ + struct { + enum OpalMemErr_DynErrType dyn_err_type:8; + uint8_t reserved_1[7]; + __be64 physical_address_start; + __be64 physical_address_end; + } dyn_dealloc; + } u; +}; + +/* HMI interrupt event */ +enum OpalHMI_Version { + OpalHMIEvt_V1 = 1, +}; + +enum OpalHMI_Severity { + OpalHMI_SEV_NO_ERROR = 0, + OpalHMI_SEV_WARNING = 1, + OpalHMI_SEV_ERROR_SYNC = 2, + OpalHMI_SEV_FATAL = 3, +}; + +enum OpalHMI_Disposition { + OpalHMI_DISPOSITION_RECOVERED = 0, + OpalHMI_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum OpalHMI_ErrType { + OpalHMI_ERROR_MALFUNC_ALERT = 0, + OpalHMI_ERROR_PROC_RECOV_DONE, + OpalHMI_ERROR_PROC_RECOV_DONE_AGAIN, + OpalHMI_ERROR_PROC_RECOV_MASKED, + OpalHMI_ERROR_TFAC, + OpalHMI_ERROR_TFMR_PARITY, + OpalHMI_ERROR_HA_OVERFLOW_WARN, + OpalHMI_ERROR_XSCOM_FAIL, + OpalHMI_ERROR_XSCOM_DONE, + OpalHMI_ERROR_SCOM_FIR, + OpalHMI_ERROR_DEBUG_TRIG_FIR, + OpalHMI_ERROR_HYP_RESOURCE, +}; + +struct OpalHMIEvent { + uint8_t version; /* 0x00 */ + uint8_t severity; /* 0x01 */ + uint8_t type; /* 0x02 */ + uint8_t disposition; /* 0x03 */ + uint8_t reserved_1[4]; /* 0x04 */ + + __be64 hmer; + /* TFMR register. Valid only for TFAC and TFMR_PARITY error type. */ + __be64 tfmr; +}; + +enum { + OPAL_P7IOC_DIAG_TYPE_NONE = 0, + OPAL_P7IOC_DIAG_TYPE_RGC = 1, + OPAL_P7IOC_DIAG_TYPE_BI = 2, + OPAL_P7IOC_DIAG_TYPE_CI = 3, + OPAL_P7IOC_DIAG_TYPE_MISC = 4, + OPAL_P7IOC_DIAG_TYPE_I2C = 5, + OPAL_P7IOC_DIAG_TYPE_LAST = 6 +}; + +struct OpalIoP7IOCErrorData { + __be16 type; + + /* GEM */ + __be64 gemXfir; + __be64 gemRfir; + __be64 gemRirqfir; + __be64 gemMask; + __be64 gemRwof; + + /* LEM */ + __be64 lemFir; + __be64 lemErrMask; + __be64 lemAction0; + __be64 lemAction1; + __be64 lemWof; + + union { + struct OpalIoP7IOCRgcErrorData { + __be64 rgcStatus; /* 3E1C10 */ + __be64 rgcLdcp; /* 3E1C18 */ + }rgc; + struct OpalIoP7IOCBiErrorData { + __be64 biLdcp0; /* 3C0100, 3C0118 */ + __be64 biLdcp1; /* 3C0108, 3C0120 */ + __be64 biLdcp2; /* 3C0110, 3C0128 */ + __be64 biFenceStatus; /* 3C0130, 3C0130 */ + + u8 biDownbound; /* BI Downbound or Upbound */ + }bi; + struct OpalIoP7IOCCiErrorData { + __be64 ciPortStatus; /* 3Dn008 */ + __be64 ciPortLdcp; /* 3Dn010 */ + + u8 ciPort; /* Index of CI port: 0/1 */ + }ci; + }; +}; + +/** + * This structure defines the overlay which will be used to store PHB error + * data upon request. + */ +enum { + OPAL_PHB_ERROR_DATA_VERSION_1 = 1, +}; + +enum { + OPAL_PHB_ERROR_DATA_TYPE_P7IOC = 1, + OPAL_PHB_ERROR_DATA_TYPE_PHB3 = 2 +}; + +enum { + OPAL_P7IOC_NUM_PEST_REGS = 128, + OPAL_PHB3_NUM_PEST_REGS = 256 +}; + +/* CAPI modes for PHB */ +enum { + OPAL_PHB_CAPI_MODE_PCIE = 0, + OPAL_PHB_CAPI_MODE_CAPI = 1, + OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, + OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, +}; + +struct OpalIoPhbErrorCommon { + __be32 version; + __be32 ioType; + __be32 len; +}; + +struct OpalIoP7IOCPhbErrorData { + struct OpalIoPhbErrorCommon common; + + __be32 brdgCtl; + + // P7IOC utl regs + __be32 portStatusReg; + __be32 rootCmplxStatus; + __be32 busAgentStatus; + + // P7IOC cfg regs + __be32 deviceStatus; + __be32 slotStatus; + __be32 linkStatus; + __be32 devCmdStatus; + __be32 devSecStatus; + + // cfg AER regs + __be32 rootErrorStatus; + __be32 uncorrErrorStatus; + __be32 corrErrorStatus; + __be32 tlpHdr1; + __be32 tlpHdr2; + __be32 tlpHdr3; + __be32 tlpHdr4; + __be32 sourceId; + + __be32 rsv3; + + // Record data about the call to allocate a buffer. + __be64 errorClass; + __be64 correlator; + + //P7IOC MMIO Error Regs + __be64 p7iocPlssr; // n120 + __be64 p7iocCsr; // n110 + __be64 lemFir; // nC00 + __be64 lemErrorMask; // nC18 + __be64 lemWOF; // nC40 + __be64 phbErrorStatus; // nC80 + __be64 phbFirstErrorStatus; // nC88 + __be64 phbErrorLog0; // nCC0 + __be64 phbErrorLog1; // nCC8 + __be64 mmioErrorStatus; // nD00 + __be64 mmioFirstErrorStatus; // nD08 + __be64 mmioErrorLog0; // nD40 + __be64 mmioErrorLog1; // nD48 + __be64 dma0ErrorStatus; // nD80 + __be64 dma0FirstErrorStatus; // nD88 + __be64 dma0ErrorLog0; // nDC0 + __be64 dma0ErrorLog1; // nDC8 + __be64 dma1ErrorStatus; // nE00 + __be64 dma1FirstErrorStatus; // nE08 + __be64 dma1ErrorLog0; // nE40 + __be64 dma1ErrorLog1; // nE48 + __be64 pestA[OPAL_P7IOC_NUM_PEST_REGS]; + __be64 pestB[OPAL_P7IOC_NUM_PEST_REGS]; +}; + +struct OpalIoPhb3ErrorData { + struct OpalIoPhbErrorCommon common; + + __be32 brdgCtl; + + /* PHB3 UTL regs */ + __be32 portStatusReg; + __be32 rootCmplxStatus; + __be32 busAgentStatus; + + /* PHB3 cfg regs */ + __be32 deviceStatus; + __be32 slotStatus; + __be32 linkStatus; + __be32 devCmdStatus; + __be32 devSecStatus; + + /* cfg AER regs */ + __be32 rootErrorStatus; + __be32 uncorrErrorStatus; + __be32 corrErrorStatus; + __be32 tlpHdr1; + __be32 tlpHdr2; + __be32 tlpHdr3; + __be32 tlpHdr4; + __be32 sourceId; + + __be32 rsv3; + + /* Record data about the call to allocate a buffer */ + __be64 errorClass; + __be64 correlator; + + __be64 nFir; /* 000 */ + __be64 nFirMask; /* 003 */ + __be64 nFirWOF; /* 008 */ + + /* PHB3 MMIO Error Regs */ + __be64 phbPlssr; /* 120 */ + __be64 phbCsr; /* 110 */ + __be64 lemFir; /* C00 */ + __be64 lemErrorMask; /* C18 */ + __be64 lemWOF; /* C40 */ + __be64 phbErrorStatus; /* C80 */ + __be64 phbFirstErrorStatus; /* C88 */ + __be64 phbErrorLog0; /* CC0 */ + __be64 phbErrorLog1; /* CC8 */ + __be64 mmioErrorStatus; /* D00 */ + __be64 mmioFirstErrorStatus; /* D08 */ + __be64 mmioErrorLog0; /* D40 */ + __be64 mmioErrorLog1; /* D48 */ + __be64 dma0ErrorStatus; /* D80 */ + __be64 dma0FirstErrorStatus; /* D88 */ + __be64 dma0ErrorLog0; /* DC0 */ + __be64 dma0ErrorLog1; /* DC8 */ + __be64 dma1ErrorStatus; /* E00 */ + __be64 dma1FirstErrorStatus; /* E08 */ + __be64 dma1ErrorLog0; /* E40 */ + __be64 dma1ErrorLog1; /* E48 */ + __be64 pestA[OPAL_PHB3_NUM_PEST_REGS]; + __be64 pestB[OPAL_PHB3_NUM_PEST_REGS]; +}; + +enum { + OPAL_REINIT_CPUS_HILE_BE = (1 << 0), + OPAL_REINIT_CPUS_HILE_LE = (1 << 1), +}; + +typedef struct oppanel_line { + const char * line; + uint64_t line_len; +} oppanel_line_t; + +/* + * SG entries + * + * WARNING: The current implementation requires each entry + * to represent a block that is 4k aligned *and* each block + * size except the last one in the list to be as well. + */ +struct opal_sg_entry { + __be64 data; + __be64 length; +}; + +/* SG list */ +struct opal_sg_list { + __be64 length; + __be64 next; + struct opal_sg_entry entry[]; +}; + +/* + * Dump region ID range usable by the OS + */ +#define OPAL_DUMP_REGION_HOST_START 0x80 +#define OPAL_DUMP_REGION_LOG_BUF 0x80 +#define OPAL_DUMP_REGION_HOST_END 0xFF + +/* OPAL I2C request */ +struct opal_i2c_request { + uint8_t type; +#define OPAL_I2C_RAW_READ 0 +#define OPAL_I2C_RAW_WRITE 1 +#define OPAL_I2C_SM_READ 2 +#define OPAL_I2C_SM_WRITE 3 + uint8_t flags; +#define OPAL_I2C_ADDR_10 0x01 /* Not supported yet */ + uint8_t subaddr_sz; /* Max 4 */ + uint8_t reserved; + __be16 addr; /* 7 or 10 bit address */ + __be16 reserved2; + __be32 subaddr; /* Sub-address if any */ + __be32 size; /* Data size */ + __be64 buffer_ra; /* Buffer real address */ +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* __OPAL_API_H */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 9ee0a30a02ce..65c89dd2f604 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -9,755 +9,17 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef __OPAL_H -#define __OPAL_H +#ifndef _ASM_POWERPC_OPAL_H +#define _ASM_POWERPC_OPAL_H -#ifndef __ASSEMBLY__ -/* - * SG entry - * - * WARNING: The current implementation requires each entry - * to represent a block that is 4k aligned *and* each block - * size except the last one in the list to be as well. - */ -struct opal_sg_entry { - __be64 data; - __be64 length; -}; - -/* SG list */ -struct opal_sg_list { - __be64 length; - __be64 next; - struct opal_sg_entry entry[]; -}; - -/* We calculate number of sg entries based on PAGE_SIZE */ -#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) - -#endif /* __ASSEMBLY__ */ - -/****** OPAL APIs ******/ - -/* Return codes */ -#define OPAL_SUCCESS 0 -#define OPAL_PARAMETER -1 -#define OPAL_BUSY -2 -#define OPAL_PARTIAL -3 -#define OPAL_CONSTRAINED -4 -#define OPAL_CLOSED -5 -#define OPAL_HARDWARE -6 -#define OPAL_UNSUPPORTED -7 -#define OPAL_PERMISSION -8 -#define OPAL_NO_MEM -9 -#define OPAL_RESOURCE -10 -#define OPAL_INTERNAL_ERROR -11 -#define OPAL_BUSY_EVENT -12 -#define OPAL_HARDWARE_FROZEN -13 -#define OPAL_WRONG_STATE -14 -#define OPAL_ASYNC_COMPLETION -15 -#define OPAL_I2C_TIMEOUT -17 -#define OPAL_I2C_INVALID_CMD -18 -#define OPAL_I2C_LBUS_PARITY -19 -#define OPAL_I2C_BKEND_OVERRUN -20 -#define OPAL_I2C_BKEND_ACCESS -21 -#define OPAL_I2C_ARBT_LOST -22 -#define OPAL_I2C_NACK_RCVD -23 -#define OPAL_I2C_STOP_ERR -24 - -/* API Tokens (in r0) */ -#define OPAL_INVALID_CALL -1 -#define OPAL_CONSOLE_WRITE 1 -#define OPAL_CONSOLE_READ 2 -#define OPAL_RTC_READ 3 -#define OPAL_RTC_WRITE 4 -#define OPAL_CEC_POWER_DOWN 5 -#define OPAL_CEC_REBOOT 6 -#define OPAL_READ_NVRAM 7 -#define OPAL_WRITE_NVRAM 8 -#define OPAL_HANDLE_INTERRUPT 9 -#define OPAL_POLL_EVENTS 10 -#define OPAL_PCI_SET_HUB_TCE_MEMORY 11 -#define OPAL_PCI_SET_PHB_TCE_MEMORY 12 -#define OPAL_PCI_CONFIG_READ_BYTE 13 -#define OPAL_PCI_CONFIG_READ_HALF_WORD 14 -#define OPAL_PCI_CONFIG_READ_WORD 15 -#define OPAL_PCI_CONFIG_WRITE_BYTE 16 -#define OPAL_PCI_CONFIG_WRITE_HALF_WORD 17 -#define OPAL_PCI_CONFIG_WRITE_WORD 18 -#define OPAL_SET_XIVE 19 -#define OPAL_GET_XIVE 20 -#define OPAL_GET_COMPLETION_TOKEN_STATUS 21 /* obsolete */ -#define OPAL_REGISTER_OPAL_EXCEPTION_HANDLER 22 -#define OPAL_PCI_EEH_FREEZE_STATUS 23 -#define OPAL_PCI_SHPC 24 -#define OPAL_CONSOLE_WRITE_BUFFER_SPACE 25 -#define OPAL_PCI_EEH_FREEZE_CLEAR 26 -#define OPAL_PCI_PHB_MMIO_ENABLE 27 -#define OPAL_PCI_SET_PHB_MEM_WINDOW 28 -#define OPAL_PCI_MAP_PE_MMIO_WINDOW 29 -#define OPAL_PCI_SET_PHB_TABLE_MEMORY 30 -#define OPAL_PCI_SET_PE 31 -#define OPAL_PCI_SET_PELTV 32 -#define OPAL_PCI_SET_MVE 33 -#define OPAL_PCI_SET_MVE_ENABLE 34 -#define OPAL_PCI_GET_XIVE_REISSUE 35 -#define OPAL_PCI_SET_XIVE_REISSUE 36 -#define OPAL_PCI_SET_XIVE_PE 37 -#define OPAL_GET_XIVE_SOURCE 38 -#define OPAL_GET_MSI_32 39 -#define OPAL_GET_MSI_64 40 -#define OPAL_START_CPU 41 -#define OPAL_QUERY_CPU_STATUS 42 -#define OPAL_WRITE_OPPANEL 43 -#define OPAL_PCI_MAP_PE_DMA_WINDOW 44 -#define OPAL_PCI_MAP_PE_DMA_WINDOW_REAL 45 -#define OPAL_PCI_RESET 49 -#define OPAL_PCI_GET_HUB_DIAG_DATA 50 -#define OPAL_PCI_GET_PHB_DIAG_DATA 51 -#define OPAL_PCI_FENCE_PHB 52 -#define OPAL_PCI_REINIT 53 -#define OPAL_PCI_MASK_PE_ERROR 54 -#define OPAL_SET_SLOT_LED_STATUS 55 -#define OPAL_GET_EPOW_STATUS 56 -#define OPAL_SET_SYSTEM_ATTENTION_LED 57 -#define OPAL_RESERVED1 58 -#define OPAL_RESERVED2 59 -#define OPAL_PCI_NEXT_ERROR 60 -#define OPAL_PCI_EEH_FREEZE_STATUS2 61 -#define OPAL_PCI_POLL 62 -#define OPAL_PCI_MSI_EOI 63 -#define OPAL_PCI_GET_PHB_DIAG_DATA2 64 -#define OPAL_XSCOM_READ 65 -#define OPAL_XSCOM_WRITE 66 -#define OPAL_LPC_READ 67 -#define OPAL_LPC_WRITE 68 -#define OPAL_RETURN_CPU 69 -#define OPAL_REINIT_CPUS 70 -#define OPAL_ELOG_READ 71 -#define OPAL_ELOG_WRITE 72 -#define OPAL_ELOG_ACK 73 -#define OPAL_ELOG_RESEND 74 -#define OPAL_ELOG_SIZE 75 -#define OPAL_FLASH_VALIDATE 76 -#define OPAL_FLASH_MANAGE 77 -#define OPAL_FLASH_UPDATE 78 -#define OPAL_RESYNC_TIMEBASE 79 -#define OPAL_CHECK_TOKEN 80 -#define OPAL_DUMP_INIT 81 -#define OPAL_DUMP_INFO 82 -#define OPAL_DUMP_READ 83 -#define OPAL_DUMP_ACK 84 -#define OPAL_GET_MSG 85 -#define OPAL_CHECK_ASYNC_COMPLETION 86 -#define OPAL_SYNC_HOST_REBOOT 87 -#define OPAL_SENSOR_READ 88 -#define OPAL_GET_PARAM 89 -#define OPAL_SET_PARAM 90 -#define OPAL_DUMP_RESEND 91 -#define OPAL_PCI_SET_PHB_CXL_MODE 93 -#define OPAL_DUMP_INFO2 94 -#define OPAL_PCI_ERR_INJECT 96 -#define OPAL_PCI_EEH_FREEZE_SET 97 -#define OPAL_HANDLE_HMI 98 -#define OPAL_CONFIG_CPU_IDLE_STATE 99 -#define OPAL_SLW_SET_REG 100 -#define OPAL_REGISTER_DUMP_REGION 101 -#define OPAL_UNREGISTER_DUMP_REGION 102 -#define OPAL_WRITE_TPO 103 -#define OPAL_READ_TPO 104 -#define OPAL_IPMI_SEND 107 -#define OPAL_IPMI_RECV 108 -#define OPAL_I2C_REQUEST 109 - -/* Device tree flags */ - -/* Flags set in power-mgmt nodes in device tree if - * respective idle states are supported in the platform. - */ -#define OPAL_PM_NAP_ENABLED 0x00010000 -#define OPAL_PM_SLEEP_ENABLED 0x00020000 -#define OPAL_PM_WINKLE_ENABLED 0x00040000 -#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 +#include #ifndef __ASSEMBLY__ #include -/* Other enums */ -enum OpalVendorApiTokens { - OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999 -}; - -enum OpalFreezeState { - OPAL_EEH_STOPPED_NOT_FROZEN = 0, - OPAL_EEH_STOPPED_MMIO_FREEZE = 1, - OPAL_EEH_STOPPED_DMA_FREEZE = 2, - OPAL_EEH_STOPPED_MMIO_DMA_FREEZE = 3, - OPAL_EEH_STOPPED_RESET = 4, - OPAL_EEH_STOPPED_TEMP_UNAVAIL = 5, - OPAL_EEH_STOPPED_PERM_UNAVAIL = 6 -}; - -enum OpalEehFreezeActionToken { - OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1, - OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2, - OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3, - - OPAL_EEH_ACTION_SET_FREEZE_MMIO = 1, - OPAL_EEH_ACTION_SET_FREEZE_DMA = 2, - OPAL_EEH_ACTION_SET_FREEZE_ALL = 3 -}; - -enum OpalPciStatusToken { - OPAL_EEH_NO_ERROR = 0, - OPAL_EEH_IOC_ERROR = 1, - OPAL_EEH_PHB_ERROR = 2, - OPAL_EEH_PE_ERROR = 3, - OPAL_EEH_PE_MMIO_ERROR = 4, - OPAL_EEH_PE_DMA_ERROR = 5 -}; - -enum OpalPciErrorSeverity { - OPAL_EEH_SEV_NO_ERROR = 0, - OPAL_EEH_SEV_IOC_DEAD = 1, - OPAL_EEH_SEV_PHB_DEAD = 2, - OPAL_EEH_SEV_PHB_FENCED = 3, - OPAL_EEH_SEV_PE_ER = 4, - OPAL_EEH_SEV_INF = 5 -}; - -enum OpalErrinjectType { - OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR = 0, - OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64 = 1, -}; - -enum OpalErrinjectFunc { - /* IOA bus specific errors */ - OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR = 0, - OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA = 1, - OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR = 2, - OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA = 3, - OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR = 4, - OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA = 5, - OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR = 6, - OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA = 7, - OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR = 8, - OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA = 9, - OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR = 10, - OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA = 11, - OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR = 12, - OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA = 13, - OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER = 14, - OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET = 15, - OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR = 16, - OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA = 17, - OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER = 18, - OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET = 19, -}; - -enum OpalShpcAction { - OPAL_SHPC_GET_LINK_STATE = 0, - OPAL_SHPC_GET_SLOT_STATE = 1 -}; - -enum OpalShpcLinkState { - OPAL_SHPC_LINK_DOWN = 0, - OPAL_SHPC_LINK_UP = 1 -}; - -enum OpalMmioWindowType { - OPAL_M32_WINDOW_TYPE = 1, - OPAL_M64_WINDOW_TYPE = 2, - OPAL_IO_WINDOW_TYPE = 3 -}; - -enum OpalShpcSlotState { - OPAL_SHPC_DEV_NOT_PRESENT = 0, - OPAL_SHPC_DEV_PRESENT = 1 -}; - -enum OpalExceptionHandler { - OPAL_MACHINE_CHECK_HANDLER = 1, - OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2, - OPAL_SOFTPATCH_HANDLER = 3 -}; - -enum OpalPendingState { - OPAL_EVENT_OPAL_INTERNAL = 0x1, - OPAL_EVENT_NVRAM = 0x2, - OPAL_EVENT_RTC = 0x4, - OPAL_EVENT_CONSOLE_OUTPUT = 0x8, - OPAL_EVENT_CONSOLE_INPUT = 0x10, - OPAL_EVENT_ERROR_LOG_AVAIL = 0x20, - OPAL_EVENT_ERROR_LOG = 0x40, - OPAL_EVENT_EPOW = 0x80, - OPAL_EVENT_LED_STATUS = 0x100, - OPAL_EVENT_PCI_ERROR = 0x200, - OPAL_EVENT_DUMP_AVAIL = 0x400, - OPAL_EVENT_MSG_PENDING = 0x800, -}; - -enum OpalMessageType { - OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc, - * additional params function-specific - */ - OPAL_MSG_MEM_ERR, - OPAL_MSG_EPOW, - OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */ - OPAL_MSG_HMI_EVT, - OPAL_MSG_TYPE_MAX, -}; - -enum OpalThreadStatus { - OPAL_THREAD_INACTIVE = 0x0, - OPAL_THREAD_STARTED = 0x1, - OPAL_THREAD_UNAVAILABLE = 0x2 /* opal-v3 */ -}; - -enum OpalPciBusCompare { - OpalPciBusAny = 0, /* Any bus number match */ - OpalPciBus3Bits = 2, /* Match top 3 bits of bus number */ - OpalPciBus4Bits = 3, /* Match top 4 bits of bus number */ - OpalPciBus5Bits = 4, /* Match top 5 bits of bus number */ - OpalPciBus6Bits = 5, /* Match top 6 bits of bus number */ - OpalPciBus7Bits = 6, /* Match top 7 bits of bus number */ - OpalPciBusAll = 7, /* Match bus number exactly */ -}; - -enum OpalDeviceCompare { - OPAL_IGNORE_RID_DEVICE_NUMBER = 0, - OPAL_COMPARE_RID_DEVICE_NUMBER = 1 -}; - -enum OpalFuncCompare { - OPAL_IGNORE_RID_FUNCTION_NUMBER = 0, - OPAL_COMPARE_RID_FUNCTION_NUMBER = 1 -}; - -enum OpalPeAction { - OPAL_UNMAP_PE = 0, - OPAL_MAP_PE = 1 -}; - -enum OpalPeltvAction { - OPAL_REMOVE_PE_FROM_DOMAIN = 0, - OPAL_ADD_PE_TO_DOMAIN = 1 -}; - -enum OpalMveEnableAction { - OPAL_DISABLE_MVE = 0, - OPAL_ENABLE_MVE = 1 -}; - -enum OpalM64EnableAction { - OPAL_DISABLE_M64 = 0, - OPAL_ENABLE_M64_SPLIT = 1, - OPAL_ENABLE_M64_NON_SPLIT = 2 -}; - -enum OpalPciResetScope { - OPAL_RESET_PHB_COMPLETE = 1, - OPAL_RESET_PCI_LINK = 2, - OPAL_RESET_PHB_ERROR = 3, - OPAL_RESET_PCI_HOT = 4, - OPAL_RESET_PCI_FUNDAMENTAL = 5, - OPAL_RESET_PCI_IODA_TABLE = 6 -}; - -enum OpalPciReinitScope { - OPAL_REINIT_PCI_DEV = 1000 -}; - -enum OpalPciResetState { - OPAL_DEASSERT_RESET = 0, - OPAL_ASSERT_RESET = 1 -}; - -enum OpalPciMaskAction { - OPAL_UNMASK_ERROR_TYPE = 0, - OPAL_MASK_ERROR_TYPE = 1 -}; - -enum OpalSlotLedType { - OPAL_SLOT_LED_ID_TYPE = 0, - OPAL_SLOT_LED_FAULT_TYPE = 1 -}; - -enum OpalLedAction { - OPAL_TURN_OFF_LED = 0, - OPAL_TURN_ON_LED = 1, - OPAL_QUERY_LED_STATE_AFTER_BUSY = 2 -}; - -enum OpalEpowStatus { - OPAL_EPOW_NONE = 0, - OPAL_EPOW_UPS = 1, - OPAL_EPOW_OVER_AMBIENT_TEMP = 2, - OPAL_EPOW_OVER_INTERNAL_TEMP = 3 -}; - -/* - * Address cycle types for LPC accesses. These also correspond - * to the content of the first cell of the "reg" property for - * device nodes on the LPC bus - */ -enum OpalLPCAddressType { - OPAL_LPC_MEM = 0, - OPAL_LPC_IO = 1, - OPAL_LPC_FW = 2, -}; - -/* System parameter permission */ -enum OpalSysparamPerm { - OPAL_SYSPARAM_READ = 0x1, - OPAL_SYSPARAM_WRITE = 0x2, - OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE), -}; - -struct opal_msg { - __be32 msg_type; - __be32 reserved; - __be64 params[8]; -}; - -enum { - OPAL_IPMI_MSG_FORMAT_VERSION_1 = 1, -}; - -struct opal_ipmi_msg { - uint8_t version; - uint8_t netfn; - uint8_t cmd; - uint8_t data[]; -}; - -/* FSP memory errors handling */ -enum OpalMemErr_Version { - OpalMemErr_V1 = 1, -}; - -enum OpalMemErrType { - OPAL_MEM_ERR_TYPE_RESILIENCE = 0, - OPAL_MEM_ERR_TYPE_DYN_DALLOC, - OPAL_MEM_ERR_TYPE_SCRUB, -}; - -/* Memory Reilience error type */ -enum OpalMemErr_ResilErrType { - OPAL_MEM_RESILIENCE_CE = 0, - OPAL_MEM_RESILIENCE_UE, - OPAL_MEM_RESILIENCE_UE_SCRUB, -}; - -/* Dynamic Memory Deallocation type */ -enum OpalMemErr_DynErrType { - OPAL_MEM_DYNAMIC_DEALLOC = 0, -}; - -/* OpalMemoryErrorData->flags */ -#define OPAL_MEM_CORRECTED_ERROR 0x0001 -#define OPAL_MEM_THRESHOLD_EXCEEDED 0x0002 -#define OPAL_MEM_ACK_REQUIRED 0x8000 - -struct OpalMemoryErrorData { - enum OpalMemErr_Version version:8; /* 0x00 */ - enum OpalMemErrType type:8; /* 0x01 */ - __be16 flags; /* 0x02 */ - uint8_t reserved_1[4]; /* 0x04 */ - - union { - /* Memory Resilience corrected/uncorrected error info */ - struct { - enum OpalMemErr_ResilErrType resil_err_type:8; - uint8_t reserved_1[7]; - __be64 physical_address_start; - __be64 physical_address_end; - } resilience; - /* Dynamic memory deallocation error info */ - struct { - enum OpalMemErr_DynErrType dyn_err_type:8; - uint8_t reserved_1[7]; - __be64 physical_address_start; - __be64 physical_address_end; - } dyn_dealloc; - } u; -}; - -/* HMI interrupt event */ -enum OpalHMI_Version { - OpalHMIEvt_V1 = 1, -}; - -enum OpalHMI_Severity { - OpalHMI_SEV_NO_ERROR = 0, - OpalHMI_SEV_WARNING = 1, - OpalHMI_SEV_ERROR_SYNC = 2, - OpalHMI_SEV_FATAL = 3, -}; - -enum OpalHMI_Disposition { - OpalHMI_DISPOSITION_RECOVERED = 0, - OpalHMI_DISPOSITION_NOT_RECOVERED = 1, -}; - -enum OpalHMI_ErrType { - OpalHMI_ERROR_MALFUNC_ALERT = 0, - OpalHMI_ERROR_PROC_RECOV_DONE, - OpalHMI_ERROR_PROC_RECOV_DONE_AGAIN, - OpalHMI_ERROR_PROC_RECOV_MASKED, - OpalHMI_ERROR_TFAC, - OpalHMI_ERROR_TFMR_PARITY, - OpalHMI_ERROR_HA_OVERFLOW_WARN, - OpalHMI_ERROR_XSCOM_FAIL, - OpalHMI_ERROR_XSCOM_DONE, - OpalHMI_ERROR_SCOM_FIR, - OpalHMI_ERROR_DEBUG_TRIG_FIR, - OpalHMI_ERROR_HYP_RESOURCE, -}; - -struct OpalHMIEvent { - uint8_t version; /* 0x00 */ - uint8_t severity; /* 0x01 */ - uint8_t type; /* 0x02 */ - uint8_t disposition; /* 0x03 */ - uint8_t reserved_1[4]; /* 0x04 */ - - __be64 hmer; - /* TFMR register. Valid only for TFAC and TFMR_PARITY error type. */ - __be64 tfmr; -}; - -enum { - OPAL_P7IOC_DIAG_TYPE_NONE = 0, - OPAL_P7IOC_DIAG_TYPE_RGC = 1, - OPAL_P7IOC_DIAG_TYPE_BI = 2, - OPAL_P7IOC_DIAG_TYPE_CI = 3, - OPAL_P7IOC_DIAG_TYPE_MISC = 4, - OPAL_P7IOC_DIAG_TYPE_I2C = 5, - OPAL_P7IOC_DIAG_TYPE_LAST = 6 -}; - -struct OpalIoP7IOCErrorData { - __be16 type; - - /* GEM */ - __be64 gemXfir; - __be64 gemRfir; - __be64 gemRirqfir; - __be64 gemMask; - __be64 gemRwof; - - /* LEM */ - __be64 lemFir; - __be64 lemErrMask; - __be64 lemAction0; - __be64 lemAction1; - __be64 lemWof; - - union { - struct OpalIoP7IOCRgcErrorData { - __be64 rgcStatus; /* 3E1C10 */ - __be64 rgcLdcp; /* 3E1C18 */ - }rgc; - struct OpalIoP7IOCBiErrorData { - __be64 biLdcp0; /* 3C0100, 3C0118 */ - __be64 biLdcp1; /* 3C0108, 3C0120 */ - __be64 biLdcp2; /* 3C0110, 3C0128 */ - __be64 biFenceStatus; /* 3C0130, 3C0130 */ - - u8 biDownbound; /* BI Downbound or Upbound */ - }bi; - struct OpalIoP7IOCCiErrorData { - __be64 ciPortStatus; /* 3Dn008 */ - __be64 ciPortLdcp; /* 3Dn010 */ - - u8 ciPort; /* Index of CI port: 0/1 */ - }ci; - }; -}; - -/** - * This structure defines the overlay which will be used to store PHB error - * data upon request. - */ -enum { - OPAL_PHB_ERROR_DATA_VERSION_1 = 1, -}; - -enum { - OPAL_PHB_ERROR_DATA_TYPE_P7IOC = 1, - OPAL_PHB_ERROR_DATA_TYPE_PHB3 = 2 -}; - -enum { - OPAL_P7IOC_NUM_PEST_REGS = 128, - OPAL_PHB3_NUM_PEST_REGS = 256 -}; - -/* CAPI modes for PHB */ -enum { - OPAL_PHB_CAPI_MODE_PCIE = 0, - OPAL_PHB_CAPI_MODE_CAPI = 1, - OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, - OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, -}; - -struct OpalIoPhbErrorCommon { - __be32 version; - __be32 ioType; - __be32 len; -}; - -struct OpalIoP7IOCPhbErrorData { - struct OpalIoPhbErrorCommon common; - - __be32 brdgCtl; - - // P7IOC utl regs - __be32 portStatusReg; - __be32 rootCmplxStatus; - __be32 busAgentStatus; - - // P7IOC cfg regs - __be32 deviceStatus; - __be32 slotStatus; - __be32 linkStatus; - __be32 devCmdStatus; - __be32 devSecStatus; - - // cfg AER regs - __be32 rootErrorStatus; - __be32 uncorrErrorStatus; - __be32 corrErrorStatus; - __be32 tlpHdr1; - __be32 tlpHdr2; - __be32 tlpHdr3; - __be32 tlpHdr4; - __be32 sourceId; - - __be32 rsv3; - - // Record data about the call to allocate a buffer. - __be64 errorClass; - __be64 correlator; - - //P7IOC MMIO Error Regs - __be64 p7iocPlssr; // n120 - __be64 p7iocCsr; // n110 - __be64 lemFir; // nC00 - __be64 lemErrorMask; // nC18 - __be64 lemWOF; // nC40 - __be64 phbErrorStatus; // nC80 - __be64 phbFirstErrorStatus; // nC88 - __be64 phbErrorLog0; // nCC0 - __be64 phbErrorLog1; // nCC8 - __be64 mmioErrorStatus; // nD00 - __be64 mmioFirstErrorStatus; // nD08 - __be64 mmioErrorLog0; // nD40 - __be64 mmioErrorLog1; // nD48 - __be64 dma0ErrorStatus; // nD80 - __be64 dma0FirstErrorStatus; // nD88 - __be64 dma0ErrorLog0; // nDC0 - __be64 dma0ErrorLog1; // nDC8 - __be64 dma1ErrorStatus; // nE00 - __be64 dma1FirstErrorStatus; // nE08 - __be64 dma1ErrorLog0; // nE40 - __be64 dma1ErrorLog1; // nE48 - __be64 pestA[OPAL_P7IOC_NUM_PEST_REGS]; - __be64 pestB[OPAL_P7IOC_NUM_PEST_REGS]; -}; - -struct OpalIoPhb3ErrorData { - struct OpalIoPhbErrorCommon common; - - __be32 brdgCtl; - - /* PHB3 UTL regs */ - __be32 portStatusReg; - __be32 rootCmplxStatus; - __be32 busAgentStatus; - - /* PHB3 cfg regs */ - __be32 deviceStatus; - __be32 slotStatus; - __be32 linkStatus; - __be32 devCmdStatus; - __be32 devSecStatus; - - /* cfg AER regs */ - __be32 rootErrorStatus; - __be32 uncorrErrorStatus; - __be32 corrErrorStatus; - __be32 tlpHdr1; - __be32 tlpHdr2; - __be32 tlpHdr3; - __be32 tlpHdr4; - __be32 sourceId; - - __be32 rsv3; - - /* Record data about the call to allocate a buffer */ - __be64 errorClass; - __be64 correlator; - - __be64 nFir; /* 000 */ - __be64 nFirMask; /* 003 */ - __be64 nFirWOF; /* 008 */ - - /* PHB3 MMIO Error Regs */ - __be64 phbPlssr; /* 120 */ - __be64 phbCsr; /* 110 */ - __be64 lemFir; /* C00 */ - __be64 lemErrorMask; /* C18 */ - __be64 lemWOF; /* C40 */ - __be64 phbErrorStatus; /* C80 */ - __be64 phbFirstErrorStatus; /* C88 */ - __be64 phbErrorLog0; /* CC0 */ - __be64 phbErrorLog1; /* CC8 */ - __be64 mmioErrorStatus; /* D00 */ - __be64 mmioFirstErrorStatus; /* D08 */ - __be64 mmioErrorLog0; /* D40 */ - __be64 mmioErrorLog1; /* D48 */ - __be64 dma0ErrorStatus; /* D80 */ - __be64 dma0FirstErrorStatus; /* D88 */ - __be64 dma0ErrorLog0; /* DC0 */ - __be64 dma0ErrorLog1; /* DC8 */ - __be64 dma1ErrorStatus; /* E00 */ - __be64 dma1FirstErrorStatus; /* E08 */ - __be64 dma1ErrorLog0; /* E40 */ - __be64 dma1ErrorLog1; /* E48 */ - __be64 pestA[OPAL_PHB3_NUM_PEST_REGS]; - __be64 pestB[OPAL_PHB3_NUM_PEST_REGS]; -}; - -enum { - OPAL_REINIT_CPUS_HILE_BE = (1 << 0), - OPAL_REINIT_CPUS_HILE_LE = (1 << 1), -}; - -typedef struct oppanel_line { - const char * line; - uint64_t line_len; -} oppanel_line_t; - -/* OPAL I2C request */ -struct opal_i2c_request { - uint8_t type; -#define OPAL_I2C_RAW_READ 0 -#define OPAL_I2C_RAW_WRITE 1 -#define OPAL_I2C_SM_READ 2 -#define OPAL_I2C_SM_WRITE 3 - uint8_t flags; -#define OPAL_I2C_ADDR_10 0x01 /* Not supported yet */ - uint8_t subaddr_sz; /* Max 4 */ - uint8_t reserved; - __be16 addr; /* 7 or 10 bit address */ - __be16 reserved2; - __be32 subaddr; /* Sub-address if any */ - __be32 size; /* Data size */ - __be64 buffer_ra; /* Buffer real address */ -}; +/* We calculate number of sg entries based on PAGE_SIZE */ +#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) /* /sys/firmware/opal */ extern struct kobject *opal_kobj; @@ -983,13 +245,6 @@ struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, unsigned long vmalloc_size); void opal_free_sg_list(struct opal_sg_list *sg); -/* - * Dump region ID range usable by the OS - */ -#define OPAL_DUMP_REGION_HOST_START 0x80 -#define OPAL_DUMP_REGION_LOG_BUF 0x80 -#define OPAL_DUMP_REGION_HOST_END 0xFF - #endif /* __ASSEMBLY__ */ -#endif /* __OPAL_H */ +#endif /* _ASM_POWERPC_OPAL_H */ -- GitLab From d7cf83fcaf1b1668201eae4cdd6e6fe7a2448654 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Feb 2015 20:01:54 +1100 Subject: [PATCH 0351/1910] powerpc/powernv: Move opal-api.h closer to the Skiboot version This commit gets opal-api.h to mostly match the version in Skiboot as of commit ea7d806ab0ba. The exceptions are things which are not (currently) used in Linux. Most of this is just whitespace and a few things moving around. I think the diff is readable. Also OpalMessageType became opal_msg_type, requiring a change in the Linux code. Finally Skiboot and Linux disagree on CAPI vs CXL, because CAPI means something else in Linux. To handle that we just point the Linux wrapper, which is named "cxl" to the OPAL token OPAL_PCI_SET_PHB_CAPI_MODE. Signed-off-by: Michael Ellerman Reviewed-by: Stewart Smith --- arch/powerpc/include/asm/opal-api.h | 158 ++++++++++-------- arch/powerpc/include/asm/opal.h | 2 +- .../powerpc/platforms/powernv/opal-wrappers.S | 2 +- arch/powerpc/platforms/powernv/opal.c | 2 +- 4 files changed, 90 insertions(+), 74 deletions(-) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index a90176a428ee..2984f486f3ba 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -1,7 +1,7 @@ /* - * PowerNV OPAL definitions. + * OPAL API definitions. * - * Copyright 2011 IBM Corp. + * Copyright 2011-2015 IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,7 +15,7 @@ /****** OPAL APIs ******/ /* Return codes */ -#define OPAL_SUCCESS 0 +#define OPAL_SUCCESS 0 #define OPAL_PARAMETER -1 #define OPAL_BUSY -2 #define OPAL_PARTIAL -3 @@ -31,6 +31,7 @@ #define OPAL_HARDWARE_FROZEN -13 #define OPAL_WRONG_STATE -14 #define OPAL_ASYNC_COMPLETION -15 +#define OPAL_EMPTY -16 #define OPAL_I2C_TIMEOUT -17 #define OPAL_I2C_INVALID_CMD -18 #define OPAL_I2C_LBUS_PARITY -19 @@ -41,7 +42,8 @@ #define OPAL_I2C_STOP_ERR -24 /* API Tokens (in r0) */ -#define OPAL_INVALID_CALL -1 +#define OPAL_INVALID_CALL -1 +#define OPAL_TEST 0 #define OPAL_CONSOLE_WRITE 1 #define OPAL_CONSOLE_READ 2 #define OPAL_RTC_READ 3 @@ -84,7 +86,7 @@ #define OPAL_GET_MSI_64 40 #define OPAL_START_CPU 41 #define OPAL_QUERY_CPU_STATUS 42 -#define OPAL_WRITE_OPPANEL 43 +#define OPAL_WRITE_OPPANEL 43 /* unimplemented */ #define OPAL_PCI_MAP_PE_DMA_WINDOW 44 #define OPAL_PCI_MAP_PE_DMA_WINDOW_REAL 45 #define OPAL_PCI_RESET 49 @@ -130,8 +132,10 @@ #define OPAL_GET_PARAM 89 #define OPAL_SET_PARAM 90 #define OPAL_DUMP_RESEND 91 -#define OPAL_PCI_SET_PHB_CXL_MODE 93 +#define OPAL_ELOG_SEND 92 /* Deprecated */ +#define OPAL_PCI_SET_PHB_CAPI_MODE 93 #define OPAL_DUMP_INFO2 94 +#define OPAL_WRITE_OPPANEL_ASYNC 95 #define OPAL_PCI_ERR_INJECT 96 #define OPAL_PCI_EEH_FREEZE_SET 97 #define OPAL_HANDLE_HMI 98 @@ -141,19 +145,22 @@ #define OPAL_UNREGISTER_DUMP_REGION 102 #define OPAL_WRITE_TPO 103 #define OPAL_READ_TPO 104 +#define OPAL_GET_DPO_STATUS 105 +#define OPAL_OLD_I2C_REQUEST 106 /* Deprecated */ #define OPAL_IPMI_SEND 107 #define OPAL_IPMI_RECV 108 #define OPAL_I2C_REQUEST 109 +#define OPAL_LAST 109 /* Device tree flags */ /* Flags set in power-mgmt nodes in device tree if * respective idle states are supported in the platform. */ -#define OPAL_PM_NAP_ENABLED 0x00010000 -#define OPAL_PM_SLEEP_ENABLED 0x00020000 -#define OPAL_PM_WINKLE_ENABLED 0x00040000 -#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 +#define OPAL_PM_NAP_ENABLED 0x00010000 +#define OPAL_PM_SLEEP_ENABLED 0x00020000 +#define OPAL_PM_WINKLE_ENABLED 0x00040000 +#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 /* with workaround */ #ifndef __ASSEMBLY__ @@ -242,7 +249,7 @@ enum OpalShpcLinkState { enum OpalMmioWindowType { OPAL_M32_WINDOW_TYPE = 1, OPAL_M64_WINDOW_TYPE = 2, - OPAL_IO_WINDOW_TYPE = 3 + OPAL_IO_WINDOW_TYPE = 3 }; enum OpalShpcSlotState { @@ -251,35 +258,24 @@ enum OpalShpcSlotState { }; enum OpalExceptionHandler { - OPAL_MACHINE_CHECK_HANDLER = 1, + OPAL_MACHINE_CHECK_HANDLER = 1, OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2, - OPAL_SOFTPATCH_HANDLER = 3 + OPAL_SOFTPATCH_HANDLER = 3 }; enum OpalPendingState { - OPAL_EVENT_OPAL_INTERNAL = 0x1, - OPAL_EVENT_NVRAM = 0x2, - OPAL_EVENT_RTC = 0x4, - OPAL_EVENT_CONSOLE_OUTPUT = 0x8, - OPAL_EVENT_CONSOLE_INPUT = 0x10, - OPAL_EVENT_ERROR_LOG_AVAIL = 0x20, - OPAL_EVENT_ERROR_LOG = 0x40, - OPAL_EVENT_EPOW = 0x80, - OPAL_EVENT_LED_STATUS = 0x100, - OPAL_EVENT_PCI_ERROR = 0x200, - OPAL_EVENT_DUMP_AVAIL = 0x400, - OPAL_EVENT_MSG_PENDING = 0x800, -}; - -enum OpalMessageType { - OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc, - * additional params function-specific - */ - OPAL_MSG_MEM_ERR, - OPAL_MSG_EPOW, - OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */ - OPAL_MSG_HMI_EVT, - OPAL_MSG_TYPE_MAX, + OPAL_EVENT_OPAL_INTERNAL = 0x1, + OPAL_EVENT_NVRAM = 0x2, + OPAL_EVENT_RTC = 0x4, + OPAL_EVENT_CONSOLE_OUTPUT = 0x8, + OPAL_EVENT_CONSOLE_INPUT = 0x10, + OPAL_EVENT_ERROR_LOG_AVAIL = 0x20, + OPAL_EVENT_ERROR_LOG = 0x40, + OPAL_EVENT_EPOW = 0x80, + OPAL_EVENT_LED_STATUS = 0x100, + OPAL_EVENT_PCI_ERROR = 0x200, + OPAL_EVENT_DUMP_AVAIL = 0x400, + OPAL_EVENT_MSG_PENDING = 0x800, }; enum OpalThreadStatus { @@ -323,7 +319,7 @@ enum OpalMveEnableAction { OPAL_ENABLE_MVE = 1 }; -enum OpalM64EnableAction { +enum OpalM64Action { OPAL_DISABLE_M64 = 0, OPAL_ENABLE_M64_SPLIT = 1, OPAL_ENABLE_M64_NON_SPLIT = 2 @@ -339,12 +335,17 @@ enum OpalPciResetScope { }; enum OpalPciReinitScope { + /* + * Note: we chose values that do not overlap + * OpalPciResetScope as OPAL v2 used the same + * enum for both + */ OPAL_REINIT_PCI_DEV = 1000 }; enum OpalPciResetState { OPAL_DEASSERT_RESET = 0, - OPAL_ASSERT_RESET = 1 + OPAL_ASSERT_RESET = 1 }; enum OpalPciMaskAction { @@ -381,11 +382,16 @@ enum OpalLPCAddressType { OPAL_LPC_FW = 2, }; -/* System parameter permission */ -enum OpalSysparamPerm { - OPAL_SYSPARAM_READ = 0x1, - OPAL_SYSPARAM_WRITE = 0x2, - OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE), +enum opal_msg_type { + OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc, + * additional params function-specific + */ + OPAL_MSG_MEM_ERR, + OPAL_MSG_EPOW, + OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */ + OPAL_MSG_HMI_EVT, + OPAL_MSG_DPO, + OPAL_MSG_TYPE_MAX, }; struct opal_msg { @@ -394,15 +400,22 @@ struct opal_msg { __be64 params[8]; }; +/* System parameter permission */ +enum OpalSysparamPerm { + OPAL_SYSPARAM_READ = 0x1, + OPAL_SYSPARAM_WRITE = 0x2, + OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE), +}; + enum { OPAL_IPMI_MSG_FORMAT_VERSION_1 = 1, }; struct opal_ipmi_msg { - uint8_t version; - uint8_t netfn; - uint8_t cmd; - uint8_t data[]; + uint8_t version; + uint8_t netfn; + uint8_t cmd; + uint8_t data[]; }; /* FSP memory errors handling */ @@ -413,7 +426,6 @@ enum OpalMemErr_Version { enum OpalMemErrType { OPAL_MEM_ERR_TYPE_RESILIENCE = 0, OPAL_MEM_ERR_TYPE_DYN_DALLOC, - OPAL_MEM_ERR_TYPE_SCRUB, }; /* Memory Reilience error type */ @@ -442,17 +454,17 @@ struct OpalMemoryErrorData { union { /* Memory Resilience corrected/uncorrected error info */ struct { - enum OpalMemErr_ResilErrType resil_err_type:8; - uint8_t reserved_1[7]; - __be64 physical_address_start; - __be64 physical_address_end; + enum OpalMemErr_ResilErrType resil_err_type:8; + uint8_t reserved_1[7]; + __be64 physical_address_start; + __be64 physical_address_end; } resilience; /* Dynamic memory deallocation error info */ struct { - enum OpalMemErr_DynErrType dyn_err_type:8; - uint8_t reserved_1[7]; - __be64 physical_address_start; - __be64 physical_address_end; + enum OpalMemErr_DynErrType dyn_err_type:8; + uint8_t reserved_1[7]; + __be64 physical_address_start; + __be64 physical_address_end; } dyn_dealloc; } u; }; @@ -487,6 +499,7 @@ enum OpalHMI_ErrType { OpalHMI_ERROR_SCOM_FIR, OpalHMI_ERROR_DEBUG_TRIG_FIR, OpalHMI_ERROR_HYP_RESOURCE, + OpalHMI_ERROR_CAPP_RECOVERY, }; struct OpalHMIEvent { @@ -539,13 +552,13 @@ struct OpalIoP7IOCErrorData { __be64 biLdcp2; /* 3C0110, 3C0128 */ __be64 biFenceStatus; /* 3C0130, 3C0130 */ - u8 biDownbound; /* BI Downbound or Upbound */ + uint8_t biDownbound; /* BI Downbound or Upbound */ }bi; struct OpalIoP7IOCCiErrorData { __be64 ciPortStatus; /* 3Dn008 */ __be64 ciPortLdcp; /* 3Dn010 */ - u8 ciPort; /* Index of CI port: 0/1 */ + uint8_t ciPort; /* Index of CI port: 0/1 */ }ci; }; }; @@ -568,14 +581,6 @@ enum { OPAL_PHB3_NUM_PEST_REGS = 256 }; -/* CAPI modes for PHB */ -enum { - OPAL_PHB_CAPI_MODE_PCIE = 0, - OPAL_PHB_CAPI_MODE_CAPI = 1, - OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, - OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, -}; - struct OpalIoPhbErrorCommon { __be32 version; __be32 ioType; @@ -674,11 +679,10 @@ struct OpalIoPhb3ErrorData { __be64 errorClass; __be64 correlator; + /* PHB3 MMIO Error Regs */ __be64 nFir; /* 000 */ __be64 nFirMask; /* 003 */ __be64 nFirWOF; /* 008 */ - - /* PHB3 MMIO Error Regs */ __be64 phbPlssr; /* 120 */ __be64 phbCsr; /* 110 */ __be64 lemFir; /* C00 */ @@ -710,8 +714,8 @@ enum { }; typedef struct oppanel_line { - const char * line; - uint64_t line_len; + __be64 line; + __be64 line_len; } oppanel_line_t; /* @@ -726,7 +730,11 @@ struct opal_sg_entry { __be64 length; }; -/* SG list */ +/* + * Candiate image SG list. + * + * length = VER | length + */ struct opal_sg_list { __be64 length; __be64 next; @@ -740,6 +748,14 @@ struct opal_sg_list { #define OPAL_DUMP_REGION_LOG_BUF 0x80 #define OPAL_DUMP_REGION_HOST_END 0xFF +/* CAPI modes for PHB */ +enum { + OPAL_PHB_CAPI_MODE_PCIE = 0, + OPAL_PHB_CAPI_MODE_CAPI = 1, + OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, + OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, +}; + /* OPAL I2C request */ struct opal_i2c_request { uint8_t type; diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 65c89dd2f604..0ef0fd660ac6 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -208,7 +208,7 @@ extern void hvc_opal_init_early(void); extern int opal_notifier_register(struct notifier_block *nb); extern int opal_notifier_unregister(struct notifier_block *nb); -extern int opal_message_notifier_register(enum OpalMessageType msg_type, +extern int opal_message_notifier_register(enum opal_msg_type msg_type, struct notifier_block *nb); extern void opal_notifier_enable(void); extern void opal_notifier_disable(void); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 0509bca5e830..b23fe7c4bf12 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -286,7 +286,7 @@ OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI); OPAL_CALL(opal_slw_set_reg, OPAL_SLW_SET_REG); OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION); OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION); -OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE); +OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CAPI_MODE); OPAL_CALL(opal_tpo_write, OPAL_WRITE_TPO); OPAL_CALL(opal_tpo_read, OPAL_READ_TPO); OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 45f0d9aa3733..142a08a61bd1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -302,7 +302,7 @@ void opal_notifier_disable(void) * Opal message notifier based on message type. Allow subscribers to get * notified for specific messgae type. */ -int opal_message_notifier_register(enum OpalMessageType msg_type, +int opal_message_notifier_register(enum opal_msg_type msg_type, struct notifier_block *nb) { if (!nb) { -- GitLab From b887f9e324629125fd20ce29d6a768d280572118 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Feb 2015 20:01:55 +1100 Subject: [PATCH 0352/1910] powerpc/powernv: Remove unused definitions in opal-api.h This removes definitions in opal-api.h that are completely unused in Linux. For each of these I see three possibilities, 1) we *should* be using them in Linux and patches will arrive to do that, 2) they are not used but should stay in the header to document the API for some important reason, 3) they are not used and needn't be part of the API. Signed-off-by: Michael Ellerman Reviewed-by: Stewart Smith --- arch/powerpc/include/asm/opal-api.h | 47 ----------------------------- 1 file changed, 47 deletions(-) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index 2984f486f3ba..e8a6baf55e82 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -165,10 +165,6 @@ #ifndef __ASSEMBLY__ /* Other enums */ -enum OpalVendorApiTokens { - OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999 -}; - enum OpalFreezeState { OPAL_EEH_STOPPED_NOT_FROZEN = 0, OPAL_EEH_STOPPED_MMIO_FREEZE = 1, @@ -236,27 +232,12 @@ enum OpalErrinjectFunc { OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET = 19, }; -enum OpalShpcAction { - OPAL_SHPC_GET_LINK_STATE = 0, - OPAL_SHPC_GET_SLOT_STATE = 1 -}; - -enum OpalShpcLinkState { - OPAL_SHPC_LINK_DOWN = 0, - OPAL_SHPC_LINK_UP = 1 -}; - enum OpalMmioWindowType { OPAL_M32_WINDOW_TYPE = 1, OPAL_M64_WINDOW_TYPE = 2, OPAL_IO_WINDOW_TYPE = 3 }; -enum OpalShpcSlotState { - OPAL_SHPC_DEV_NOT_PRESENT = 0, - OPAL_SHPC_DEV_PRESENT = 1 -}; - enum OpalExceptionHandler { OPAL_MACHINE_CHECK_HANDLER = 1, OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2, @@ -348,29 +329,6 @@ enum OpalPciResetState { OPAL_ASSERT_RESET = 1 }; -enum OpalPciMaskAction { - OPAL_UNMASK_ERROR_TYPE = 0, - OPAL_MASK_ERROR_TYPE = 1 -}; - -enum OpalSlotLedType { - OPAL_SLOT_LED_ID_TYPE = 0, - OPAL_SLOT_LED_FAULT_TYPE = 1 -}; - -enum OpalLedAction { - OPAL_TURN_OFF_LED = 0, - OPAL_TURN_ON_LED = 1, - OPAL_QUERY_LED_STATE_AFTER_BUSY = 2 -}; - -enum OpalEpowStatus { - OPAL_EPOW_NONE = 0, - OPAL_EPOW_UPS = 1, - OPAL_EPOW_OVER_AMBIENT_TEMP = 2, - OPAL_EPOW_OVER_INTERNAL_TEMP = 3 -}; - /* * Address cycle types for LPC accesses. These also correspond * to the content of the first cell of the "reg" property for @@ -440,11 +398,6 @@ enum OpalMemErr_DynErrType { OPAL_MEM_DYNAMIC_DEALLOC = 0, }; -/* OpalMemoryErrorData->flags */ -#define OPAL_MEM_CORRECTED_ERROR 0x0001 -#define OPAL_MEM_THRESHOLD_EXCEEDED 0x0002 -#define OPAL_MEM_ACK_REQUIRED 0x8000 - struct OpalMemoryErrorData { enum OpalMemErr_Version version:8; /* 0x00 */ enum OpalMemErrType type:8; /* 0x01 */ -- GitLab From 170acae4c95eda2d3ed4300f494ecf70d3f1cec6 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Tue, 24 Feb 2015 16:05:03 +0700 Subject: [PATCH 0353/1910] powerpc/boot: drop planetcore_set_serial_speed Drop planetcore_set_serial_speed() which had no users since its inception in commit fec6047047fd ("[POWERPC] bootwrapper: Add PlanetCore firmware support") in 2007. Signed-off-by: Arseny Solokha Signed-off-by: Michael Ellerman --- arch/powerpc/boot/planetcore.c | 33 --------------------------------- arch/powerpc/boot/planetcore.h | 3 --- 2 files changed, 36 deletions(-) diff --git a/arch/powerpc/boot/planetcore.c b/arch/powerpc/boot/planetcore.c index 0d8558a475bb..75117e63e6db 100644 --- a/arch/powerpc/boot/planetcore.c +++ b/arch/powerpc/boot/planetcore.c @@ -131,36 +131,3 @@ void planetcore_set_stdout_path(const char *table) setprop_str(chosen, "linux,stdout-path", path); } - -void planetcore_set_serial_speed(const char *table) -{ - void *chosen, *stdout; - u64 baud; - u32 baud32; - int len; - - chosen = finddevice("/chosen"); - if (!chosen) - return; - - len = getprop(chosen, "linux,stdout-path", prop_buf, MAX_PROP_LEN); - if (len <= 0) - return; - - stdout = finddevice(prop_buf); - if (!stdout) { - printf("planetcore_set_serial_speed: " - "Bad /chosen/linux,stdout-path.\r\n"); - - return; - } - - if (!planetcore_get_decimal(table, PLANETCORE_KEY_SERIAL_BAUD, - &baud)) { - printf("planetcore_set_serial_speed: No SB tag.\r\n"); - return; - } - - baud32 = baud; - setprop(stdout, "current-speed", &baud32, 4); -} diff --git a/arch/powerpc/boot/planetcore.h b/arch/powerpc/boot/planetcore.h index 0d4094f1771c..d53c733cc463 100644 --- a/arch/powerpc/boot/planetcore.h +++ b/arch/powerpc/boot/planetcore.h @@ -43,7 +43,4 @@ void planetcore_set_mac_addrs(const char *table); */ void planetcore_set_stdout_path(const char *table); -/* Sets the current-speed property in the serial node. */ -void planetcore_set_serial_speed(const char *table); - #endif -- GitLab From f98e7f2fe9d7ac5851cf8cc9933993a2b74566c1 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Tue, 24 Feb 2015 16:05:05 +0700 Subject: [PATCH 0354/1910] powerpc/qe: drop unused ucc_slow_poll_transmitter_now Drop ucc_slow_poll_transmitter_now() which has no users since its inception in 2007 in commit 986585385131 ("[POWERPC] Add QUICC Engine (QE) infrastructure"). Signed-off-by: Arseny Solokha Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ucc_slow.h | 13 ------------- arch/powerpc/sysdev/qe_lib/ucc_slow.c | 5 ----- 2 files changed, 18 deletions(-) diff --git a/arch/powerpc/include/asm/ucc_slow.h b/arch/powerpc/include/asm/ucc_slow.h index c44131e68e11..233ef5fe5fde 100644 --- a/arch/powerpc/include/asm/ucc_slow.h +++ b/arch/powerpc/include/asm/ucc_slow.h @@ -251,19 +251,6 @@ void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode); */ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode); -/* ucc_slow_poll_transmitter_now - * Immediately forces a poll of the transmitter for data to be sent. - * Typically, the hardware performs a periodic poll for data that the - * transmit routine has set up to be transmitted. In cases where - * this polling cycle is not soon enough, this optional routine can - * be invoked to force a poll right away, instead. Proper use for - * each transmission for which this functionality is desired is to - * call the transmit routine and then this routine right after. - * - * uccs - (In) pointer to the slow UCC structure. - */ -void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs); - /* ucc_slow_graceful_stop_tx * Smoothly stops transmission on a specified slow UCC. * diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index befaf1123f7f..5f91628209eb 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -43,11 +43,6 @@ u32 ucc_slow_get_qe_cr_subblock(int uccs_num) } EXPORT_SYMBOL(ucc_slow_get_qe_cr_subblock); -void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs) -{ - out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD); -} - void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs) { struct ucc_slow_info *us_info = uccs->us_info; -- GitLab From 5e86bfde9cd93f272844c3ff6ac5f93d3666b3e7 Mon Sep 17 00:00:00 2001 From: Arseny Solokha Date: Tue, 24 Feb 2015 16:05:06 +0700 Subject: [PATCH 0355/1910] powerpc/mpic: remove unused functions Drop unused fsl_mpic_primary_get_version(), mpic_set_clk_ratio(), mpic_set_serial_int(). + fsl_mpic_primary_get_version() is just a safe wrapper around fsl_mpic_get_version() for SMP configurations. While the latter is called explicitly for handling PIC initialization and setting up error interrupt vector depending on PIC hardware version, the former isn't used for anything. + As for mpic_set_clk_ratio() and mpic_set_serial_int(), they both are almost nine years old[1] but still have no chance to be called even from out-of-tree modules because they both are __init and of course aren't exported. [1] https://lists.ozlabs.org/pipermail/linuxppc-dev/2006-June/023867.html Signed-off-by: Arseny Solokha Cc: hongtao.jia@freescale.com Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/mpic.h | 20 ------------------- arch/powerpc/sysdev/mpic.c | 35 --------------------------------- 2 files changed, 55 deletions(-) diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 754f93d208fa..6ce63a7662f8 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -34,10 +34,6 @@ #define MPIC_GREG_GCONF_BASE_MASK 0x000fffff #define MPIC_GREG_GCONF_MCK 0x08000000 #define MPIC_GREG_GLOBAL_CONF_1 0x00030 -#define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000 -#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000 -#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(r) \ - (((r) << 28) & MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK) #define MPIC_GREG_VENDOR_0 0x00040 #define MPIC_GREG_VENDOR_1 0x00050 #define MPIC_GREG_VENDOR_2 0x00060 @@ -395,16 +391,6 @@ extern struct bus_type mpic_subsys; #define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */ #define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */ -/* Get the version of primary MPIC */ -#ifdef CONFIG_MPIC -extern u32 fsl_mpic_primary_get_version(void); -#else -static inline u32 fsl_mpic_primary_get_version(void) -{ - return 0; -} -#endif - /* Allocate the controller structure and setup the linux irq descs * for the range if interrupts passed in. No HW initialization is * actually performed. @@ -496,11 +482,5 @@ extern unsigned int mpic_get_coreint_irq(void); /* Fetch Machine Check interrupt from primary mpic */ extern unsigned int mpic_get_mcirq(void); -/* Set the EPIC clock ratio */ -void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio); - -/* Enable/Disable EPIC serial interrupt mode */ -void mpic_set_serial_int(struct mpic *mpic, int enable); - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MPIC_H */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index bbfbbf2025fd..f72b592d60cc 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1219,16 +1219,6 @@ static u32 fsl_mpic_get_version(struct mpic *mpic) * Exported functions */ -u32 fsl_mpic_primary_get_version(void) -{ - struct mpic *mpic = mpic_primary; - - if (mpic) - return fsl_mpic_get_version(mpic); - - return 0; -} - struct mpic * __init mpic_alloc(struct device_node *node, phys_addr_t phys_addr, unsigned int flags, @@ -1676,31 +1666,6 @@ void __init mpic_init(struct mpic *mpic) mpic_err_int_init(mpic, MPIC_FSL_ERR_INT); } -void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) -{ - u32 v; - - v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); - v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; - v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); -} - -void __init mpic_set_serial_int(struct mpic *mpic, int enable) -{ - unsigned long flags; - u32 v; - - raw_spin_lock_irqsave(&mpic_lock, flags); - v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); - if (enable) - v |= MPIC_GREG_GLOBAL_CONF_1_SIE; - else - v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); - raw_spin_unlock_irqrestore(&mpic_lock, flags); -} - void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { struct mpic *mpic = mpic_find(irq); -- GitLab From 1680e4ba3d4f0ab12c387975584924f585fc77eb Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 11 Feb 2015 12:55:44 +0800 Subject: [PATCH 0356/1910] powerpc/boot/fdt: Use unsigned long for pointer casts Now that the wrapper supports 64-bit builds, we see warnings when attempting to cast pointers to int. Use unsigned long instead. Signed-off-by: Jeremy Kerr Signed-off-by: Michael Ellerman --- arch/powerpc/boot/libfdt-wrapper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/boot/libfdt-wrapper.c b/arch/powerpc/boot/libfdt-wrapper.c index bb8b9b3505ee..535e8fd8900d 100644 --- a/arch/powerpc/boot/libfdt-wrapper.c +++ b/arch/powerpc/boot/libfdt-wrapper.c @@ -44,12 +44,12 @@ #define offset_devp(off) \ ({ \ - int _offset = (off); \ + unsigned long _offset = (off); \ check_err(_offset) ? NULL : (void *)(_offset+1); \ }) -#define devp_offset_find(devp) (((int)(devp))-1) -#define devp_offset(devp) (devp ? ((int)(devp))-1 : 0) +#define devp_offset_find(devp) (((unsigned long)(devp))-1) +#define devp_offset(devp) (devp ? ((unsigned long)(devp))-1 : 0) static void *fdt; static void *buf; /* = NULL */ -- GitLab From 6c87b2202f5414be3acae9df2e1833e8b46c5688 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 11 Feb 2015 12:55:44 +0800 Subject: [PATCH 0357/1910] powerpc/boot/fdt: Add little-endian support to libfdt wrappers For epapr-style boot, we may be little-endian. This change implements the proper conversion for fdt*_to_cpu and cpu_to_fdt*. We also need the full cpu_to_* and *_to_cpu macros for this. Signed-off-by: Jeremy Kerr Acked-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/boot/libfdt_env.h | 14 ++++++++------ arch/powerpc/boot/of.h | 8 ++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/boot/libfdt_env.h b/arch/powerpc/boot/libfdt_env.h index c89fdb1b80e1..8dcd744e5728 100644 --- a/arch/powerpc/boot/libfdt_env.h +++ b/arch/powerpc/boot/libfdt_env.h @@ -4,15 +4,17 @@ #include #include +#include "of.h" + typedef u32 uint32_t; typedef u64 uint64_t; typedef unsigned long uintptr_t; -#define fdt16_to_cpu(x) (x) -#define cpu_to_fdt16(x) (x) -#define fdt32_to_cpu(x) (x) -#define cpu_to_fdt32(x) (x) -#define fdt64_to_cpu(x) (x) -#define cpu_to_fdt64(x) (x) +#define fdt16_to_cpu(x) be16_to_cpu(x) +#define cpu_to_fdt16(x) cpu_to_be16(x) +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) +#define fdt64_to_cpu(x) be64_to_cpu(x) +#define cpu_to_fdt64(x) cpu_to_be64(x) #endif /* _ARCH_POWERPC_BOOT_LIBFDT_ENV_H */ diff --git a/arch/powerpc/boot/of.h b/arch/powerpc/boot/of.h index c8c1750aba0c..5603320dce07 100644 --- a/arch/powerpc/boot/of.h +++ b/arch/powerpc/boot/of.h @@ -24,11 +24,19 @@ void of_console_init(void); typedef u32 __be32; #ifdef __LITTLE_ENDIAN__ +#define cpu_to_be16(x) swab16(x) +#define be16_to_cpu(x) swab16(x) #define cpu_to_be32(x) swab32(x) #define be32_to_cpu(x) swab32(x) +#define cpu_to_be64(x) swab64(x) +#define be64_to_cpu(x) swab64(x) #else +#define cpu_to_be16(x) (x) +#define be16_to_cpu(x) (x) #define cpu_to_be32(x) (x) #define be32_to_cpu(x) (x) +#define cpu_to_be64(x) (x) +#define be64_to_cpu(x) (x) #endif #define PROM_ERROR (-1u) -- GitLab From 90d1d44e0de0ec833634667bc1827303b2e1645e Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 11 Feb 2015 12:55:44 +0800 Subject: [PATCH 0358/1910] powerpc/boot/wrapper: use the pseries wrapper for zImage.epapr We'll likely be entering the zImage.epapr as BE, so include the pseries implementation of _zimage_start, which adds the endian fixup magic. Although the endian fixup won't work on Book III-E machines starting LE, the current entry point doesn't support LE anyway, so we shouldn't be breaking anything. Signed-off-by: Jeremy Kerr Signed-off-by: Michael Ellerman --- arch/powerpc/boot/wrapper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index ae0f88ec4a32..3f50c27ed8f8 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -277,7 +277,7 @@ treeboot-iss4xx-mpic) platformo="$object/treeboot-iss4xx.o" ;; epapr) - platformo="$object/epapr.o $object/epapr-wrapper.o" + platformo="$object/pseries-head.o $object/epapr.o $object/epapr-wrapper.o" link_address='0x20000000' pie=-pie ;; -- GitLab From 8c06f0d910ca628b657dc964a7347e70070dc7d6 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 11 Feb 2015 12:55:44 +0800 Subject: [PATCH 0359/1910] powerpc/boot: Fix stack corruption in epapr entry point Currently, a 64-bit little-endian zImage.epapr won't boot in epapr mode, as we never return from platform_init. Before entering C, we initialise our stack by setting r1 16 bytes below the end of the _bss_stack: stwu r0,-16(r1) /* establish a stack frame */ However, the called function will save the caller's lr in the caller's frame's lr save area, at -16(r1) to -32(r1). This means that writes to the fdt variable will corrupt the saved link register: 0000000020c06018 l O .bss 0000000000001000 _bss_stack 0000000020c07018 l O .bss 0000000000000008 fdt We'll need at least 32 bytes in the initial stack frame, to handle the LR save area. We bump this to 112 bytes, as that'll be the max required by ABIv1. Thanks to Alistair Popple for debugging help. Signed-off-by: Jeremy Kerr Signed-off-by: Michael Ellerman --- arch/powerpc/boot/crt0.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 14de4f8778a7..e0040621d00c 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -218,7 +218,7 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */ beq 6f ld r1,0(r8) li r0,0 - stdu r0,-16(r1) /* establish a stack frame */ + stdu r0,-112(r1) /* establish a stack frame */ 6: #endif /* __powerpc64__ */ /* Call platform_init() */ -- GitLab From 7f664cf9e422105644818b180349e3b10a370de7 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 11 Feb 2015 12:55:44 +0800 Subject: [PATCH 0360/1910] powerpc/boot: don't clobber r6 and r7 in epapr boot We use r6 and r7 for epapr boot, but the current pre-C init will clobber both of these. This change does a simple replacement, of r6 -> r12 and r7 -> r13, so that we hit platform init with these registers intact. Signed-off-by: Jeremy Kerr Signed-off-by: Michael Ellerman --- arch/powerpc/boot/crt0.S | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index e0040621d00c..12866ccb5694 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -155,29 +155,29 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */ ld r9,(p_rela-p_base)(r10) add r9,r9,r10 - li r7,0 + li r13,0 li r8,0 -9: ld r6,0(r11) /* get tag */ - cmpdi r6,0 +9: ld r12,0(r11) /* get tag */ + cmpdi r12,0 beq 12f /* end of list */ - cmpdi r6,RELA + cmpdi r12,RELA bne 10f - ld r7,8(r11) /* get RELA pointer in r7 */ + ld r13,8(r11) /* get RELA pointer in r13 */ b 11f -10: addis r6,r6,(-RELACOUNT)@ha - cmpdi r6,RELACOUNT@l +10: addis r12,r12,(-RELACOUNT)@ha + cmpdi r12,RELACOUNT@l bne 11f ld r8,8(r11) /* get RELACOUNT value in r8 */ 11: addi r11,r11,16 b 9b 12: - cmpdi r7,0 /* check we have both RELA and RELACOUNT */ + cmpdi r13,0 /* check we have both RELA and RELACOUNT */ cmpdi cr1,r8,0 beq 3f beq cr1,3f /* Calcuate the runtime offset. */ - subf r7,r7,r9 + subf r13,r13,r9 /* Run through the list of relocations and process the * R_PPC64_RELATIVE ones. */ @@ -185,10 +185,10 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */ 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ cmpdi r0,22 /* R_PPC64_RELATIVE */ bne 3f - ld r6,0(r9) /* reloc->r_offset */ + ld r12,0(r9) /* reloc->r_offset */ ld r0,16(r9) /* reloc->r_addend */ - add r0,r0,r7 - stdx r0,r7,r6 + add r0,r0,r13 + stdx r0,r13,r12 addi r9,r9,24 bdnz 13b -- GitLab From 4d9b519c9bcab5718053f8717dadad7b09b41f5e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:02 -0700 Subject: [PATCH 0361/1910] hwrng: add devm_* interfaces This change adds devm_hwrng_register and devm_hwrng_unregister which use can simplify error unwinding and unbinding code paths in device drivers. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 42 +++++++++++++++++++++++++++++++++++ include/linux/hw_random.h | 4 ++++ 2 files changed, 46 insertions(+) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 32a8a867f7f8..83161dde53ee 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -536,6 +536,48 @@ void hwrng_unregister(struct hwrng *rng) } EXPORT_SYMBOL_GPL(hwrng_unregister); +static void devm_hwrng_release(struct device *dev, void *res) +{ + hwrng_unregister(*(struct hwrng **)res); +} + +static int devm_hwrng_match(struct device *dev, void *res, void *data) +{ + struct hwrng **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +int devm_hwrng_register(struct device *dev, struct hwrng *rng) +{ + struct hwrng **ptr; + int error; + + ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + error = hwrng_register(rng); + if (error) { + devres_free(ptr); + return error; + } + + *ptr = rng; + devres_add(dev, ptr); + return 0; +} +EXPORT_SYMBOL_GPL(devm_hwrng_register); + +void devm_hwrng_unregister(struct device *dev, struct hwrng *rng) +{ + devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng); +} +EXPORT_SYMBOL_GPL(devm_hwrng_unregister); + static int __init hwrng_modinit(void) { return register_miscdev(); diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h index eb7b414d232b..4f7d8f4b1e9a 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h @@ -50,10 +50,14 @@ struct hwrng { struct completion cleanup_done; }; +struct device; + /** Register a new Hardware Random Number Generator driver. */ extern int hwrng_register(struct hwrng *rng); +extern int devm_hwrng_register(struct device *dev, struct hwrng *rng); /** Unregister a Hardware Random Number Generator driver. */ extern void hwrng_unregister(struct hwrng *rng); +extern void devm_hwrng_unregister(struct device *dve, struct hwrng *rng); /** Feed random bits into the pool. */ extern void add_hwgenerator_randomness(const char *buffer, size_t count, size_t entropy); -- GitLab From 6229c16060fee9a015bf476f21e40c6f08609d6e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:03 -0700 Subject: [PATCH 0362/1910] hwrng: bcm63xx - make use of devm_hwrng_register This change converts bcm63xx-rng to use devm* API for managing all resources, which allows us to dispense with the rest of error handling path and remove() function. Also we combine hwern and driver-private data into a single allocation, use clk_prepare_enable() instead of "naked" clk_enable() and move clock enabling/disabling into hwrnd inti(0 and cleanup() methods so the clock stays off until rng is used. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm63xx-rng.c | 87 ++++++++++------------------ 1 file changed, 31 insertions(+), 56 deletions(-) diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index 27da00f68c8f..d1494ecd9e11 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -24,16 +24,22 @@ #define RNG_MASK 0x10 struct bcm63xx_rng_priv { + struct hwrng rng; struct clk *clk; void __iomem *regs; }; -#define to_rng_priv(rng) ((struct bcm63xx_rng_priv *)rng->priv) +#define to_rng_priv(rng) container_of(rng, struct bcm63xx_rng_priv, rng) static int bcm63xx_rng_init(struct hwrng *rng) { struct bcm63xx_rng_priv *priv = to_rng_priv(rng); u32 val; + int error; + + error = clk_prepare_enable(priv->clk); + if (error) + return error; val = __raw_readl(priv->regs + RNG_CTRL); val |= RNG_EN; @@ -50,6 +56,8 @@ static void bcm63xx_rng_cleanup(struct hwrng *rng) val = __raw_readl(priv->regs + RNG_CTRL); val &= ~RNG_EN; __raw_writel(val, priv->regs + RNG_CTRL); + + clk_didsable_unprepare(prov->clk); } static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) @@ -79,86 +87,53 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { dev_err(&pdev->dev, "no iomem resource\n"); - ret = -ENXIO; - goto out; + return -ENXIO; } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out; - } - - rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); - if (!rng) { - ret = -ENOMEM; - goto out; + if (!priv) + return -ENOMEM; + + priv->rng.name = pdev->name; + priv->rng.init = bcm63xx_rng_init; + priv->rng.cleanup = bcm63xx_rng_cleanup; + prov->rng.data_present = bcm63xx_rng_data_present; + priv->rng.data_read = bcm63xx_rng_data_read; + + priv->clk = devm_clk_get(&pdev->dev, "ipsec"); + if (IS_ERR(priv->clk)) { + error = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "no clock for device: %d\n", error); + return error; } - platform_set_drvdata(pdev, rng); - rng->priv = (unsigned long)priv; - rng->name = pdev->name; - rng->init = bcm63xx_rng_init; - rng->cleanup = bcm63xx_rng_cleanup; - rng->data_present = bcm63xx_rng_data_present; - rng->data_read = bcm63xx_rng_data_read; - - clk = clk_get(&pdev->dev, "ipsec"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "no clock for device\n"); - ret = PTR_ERR(clk); - goto out; - } - - priv->clk = clk; - if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r), pdev->name)) { dev_err(&pdev->dev, "request mem failed"); - ret = -ENOMEM; - goto out; + return -EBUSY; } priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); if (!priv->regs) { dev_err(&pdev->dev, "ioremap failed"); - ret = -ENOMEM; - goto out; + return -ENOMEM; } - clk_enable(clk); - - ret = hwrng_register(rng); - if (ret) { - dev_err(&pdev->dev, "failed to register rng device\n"); - goto out_clk_disable; + error = devm_hwrng_register(&pdev->dev, &priv->rng); + if (error) { + dev_err(&pdev->dev, "failed to register rng device: %d\n", + error); + return error; } dev_info(&pdev->dev, "registered RNG driver\n"); - return 0; - -out_clk_disable: - clk_disable(clk); -out: - return ret; -} - -static int bcm63xx_rng_remove(struct platform_device *pdev) -{ - struct hwrng *rng = platform_get_drvdata(pdev); - struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - - hwrng_unregister(rng); - clk_disable(priv->clk); - return 0; } static struct platform_driver bcm63xx_rng_driver = { .probe = bcm63xx_rng_probe, - .remove = bcm63xx_rng_remove, .driver = { .name = "bcm63xx-rng", }, -- GitLab From 1e6e38a916e2410e80cec5f2e3c075ffd967b027 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:04 -0700 Subject: [PATCH 0363/1910] hwrng: exynos - make use of devm_hwrng_register This allows us to get rid of remove() method. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index fed0830bf724..dc4701fd814f 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -131,16 +131,7 @@ static int exynos_rng_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); - return hwrng_register(&exynos_rng->rng); -} - -static int exynos_rng_remove(struct platform_device *pdev) -{ - struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); - - hwrng_unregister(&exynos_rng->rng); - - return 0; + return devm_hwrng_register(&pdev->dev, &exynos_rng->rng); } #ifdef CONFIG_PM @@ -172,7 +163,6 @@ static struct platform_driver exynos_rng_driver = { .pm = &exynos_rng_pm_ops, }, .probe = exynos_rng_probe, - .remove = exynos_rng_remove, }; module_platform_driver(exynos_rng_driver); -- GitLab From 9052b0dd45d7e44aa43af03f48d329a2530c70c4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:05 -0700 Subject: [PATCH 0364/1910] hwrng: msm - make use of devm_hwrng_register This allows us to get rid of remove() method. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/msm-rng.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c index cea1c703d62f..96fb986402eb 100644 --- a/drivers/char/hw_random/msm-rng.c +++ b/drivers/char/hw_random/msm-rng.c @@ -157,7 +157,7 @@ static int msm_rng_probe(struct platform_device *pdev) rng->hwrng.cleanup = msm_rng_cleanup, rng->hwrng.read = msm_rng_read, - ret = hwrng_register(&rng->hwrng); + ret = devm_hwrng_register(&pdev->dev, &rng->hwrng); if (ret) { dev_err(&pdev->dev, "failed to register hwrng\n"); return ret; @@ -166,14 +166,6 @@ static int msm_rng_probe(struct platform_device *pdev) return 0; } -static int msm_rng_remove(struct platform_device *pdev) -{ - struct msm_rng *rng = platform_get_drvdata(pdev); - - hwrng_unregister(&rng->hwrng); - return 0; -} - static const struct of_device_id msm_rng_of_match[] = { { .compatible = "qcom,prng", }, {} @@ -182,7 +174,6 @@ MODULE_DEVICE_TABLE(of, msm_rng_of_match); static struct platform_driver msm_rng_driver = { .probe = msm_rng_probe, - .remove = msm_rng_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(msm_rng_of_match), -- GitLab From ef0a1b26499f61b2453dd0c454aedee687edf31c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:06 -0700 Subject: [PATCH 0365/1910] hwrng: iproc-rng200 - do not use static structure Instead of using static hwrng structure that is reused between binds/unbinds of the device let's embed it into driver's private structure that we allocate. This way we are guaranteed not to stumble onto something left from previous bind attempt. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/iproc-rng200.c | 44 +++++++++++++-------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index 276cb8a93bac..2dbaf5c52f35 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -48,9 +48,12 @@ #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF struct iproc_rng200_dev { - void __iomem *base; + struct hwrng rng; + void __iomem *base; }; +#define to_rng_priv(rng) container_of(rng, struct iproc_rng200_dev, rng) + static void iproc_rng200_restart(void __iomem *rng_base) { uint32_t val; @@ -89,11 +92,11 @@ static void iproc_rng200_restart(void __iomem *rng_base) } static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max, - bool wait) + bool wait) { - uint32_t status; + struct iproc_rng200_dev *priv = to_rng_priv(rng); uint32_t num_remaining = max; - struct iproc_rng200_dev *priv = (struct iproc_rng200_dev *)rng->priv; + uint32_t status; #define MAX_RESETS_PER_READ 1 uint32_t num_resets = 0; @@ -151,10 +154,8 @@ static int iproc_rng200_read(struct hwrng *rng, void *buf, size_t max, static int iproc_rng200_init(struct hwrng *rng) { + struct iproc_rng200_dev *priv = to_rng_priv(rng); uint32_t val; - struct iproc_rng200_dev *priv; - - priv = (struct iproc_rng200_dev *)rng->priv; /* Setup RNG. */ val = ioread32(priv->base + RNG_CTRL_OFFSET); @@ -167,10 +168,8 @@ static int iproc_rng200_init(struct hwrng *rng) static void iproc_rng200_cleanup(struct hwrng *rng) { + struct iproc_rng200_dev *priv = to_rng_priv(rng); uint32_t val; - struct iproc_rng200_dev *priv; - - priv = (struct iproc_rng200_dev *)rng->priv; /* Disable RNG hardware */ val = ioread32(priv->base + RNG_CTRL_OFFSET); @@ -179,13 +178,6 @@ static void iproc_rng200_cleanup(struct hwrng *rng) iowrite32(val, priv->base + RNG_CTRL_OFFSET); } -static struct hwrng iproc_rng200_ops = { - .name = "iproc-rng200", - .read = iproc_rng200_read, - .init = iproc_rng200_init, - .cleanup = iproc_rng200_cleanup, -}; - static int iproc_rng200_probe(struct platform_device *pdev) { struct iproc_rng200_dev *priv; @@ -193,13 +185,10 @@ static int iproc_rng200_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret; - priv = devm_kzalloc(dev, sizeof(struct iproc_rng200_dev), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - iproc_rng200_ops.priv = (unsigned long)priv; - platform_set_drvdata(pdev, priv); - /* Map peripheral */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -213,13 +202,20 @@ static int iproc_rng200_probe(struct platform_device *pdev) return PTR_ERR(priv->base); } + priv->rng.name = "iproc-rng200", + priv->rng.read = iproc_rng200_read, + priv->rng.init = iproc_rng200_init, + priv->rng.cleanup = iproc_rng200_cleanup, + /* Register driver */ - ret = hwrng_register(&iproc_rng200_ops); + ret = hwrng_register(&priv->rng); if (ret) { dev_err(dev, "hwrng registration failed\n"); return ret; } + platform_set_drvdata(pdev, priv); + dev_info(dev, "hwrng registered\n"); return 0; @@ -227,8 +223,10 @@ static int iproc_rng200_probe(struct platform_device *pdev) static int iproc_rng200_remove(struct platform_device *pdev) { + struct iproc_rng200_dev *priv = platform_get_drvdata(pdev); + /* Unregister driver */ - hwrng_unregister(&iproc_rng200_ops); + hwrng_unregister(&priv->rng); return 0; } -- GitLab From 73b3862127e71d8cc7677b07ccc5adff0c0179bd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 12 Mar 2015 14:00:07 -0700 Subject: [PATCH 0366/1910] hwrng: iproc-rng200 - make use of devm_hwrng_register This allows us to get rid of driver's remove() method. Signed-off-by: Dmitry Torokhov Signed-off-by: Herbert Xu --- drivers/char/hw_random/iproc-rng200.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index 2dbaf5c52f35..3eaf7cb96d36 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -208,29 +208,17 @@ static int iproc_rng200_probe(struct platform_device *pdev) priv->rng.cleanup = iproc_rng200_cleanup, /* Register driver */ - ret = hwrng_register(&priv->rng); + ret = devm_hwrng_register(dev, &priv->rng); if (ret) { dev_err(dev, "hwrng registration failed\n"); return ret; } - platform_set_drvdata(pdev, priv); - dev_info(dev, "hwrng registered\n"); return 0; } -static int iproc_rng200_remove(struct platform_device *pdev) -{ - struct iproc_rng200_dev *priv = platform_get_drvdata(pdev); - - /* Unregister driver */ - hwrng_unregister(&priv->rng); - - return 0; -} - static const struct of_device_id iproc_rng200_of_match[] = { { .compatible = "brcm,iproc-rng200", }, {}, @@ -243,7 +231,6 @@ static struct platform_driver iproc_rng200_driver = { .of_match_table = iproc_rng200_of_match, }, .probe = iproc_rng200_probe, - .remove = iproc_rng200_remove, }; module_platform_driver(iproc_rng200_driver); -- GitLab From d358f1abbf71ad4b10e843b589033e5d37142436 Mon Sep 17 00:00:00 2001 From: James Hartley Date: Thu, 12 Mar 2015 23:17:26 +0000 Subject: [PATCH 0367/1910] crypto: img-hash - Add Imagination Technologies hw hash accelerator This adds support for the Imagination Technologies hash accelerator which provides hardware acceleration for SHA1 SHA224 SHA256 and MD5 hashes. Signed-off-by: James Hartley Reviewed-by: Andrew Bresticker Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 14 + drivers/crypto/Makefile | 1 + drivers/crypto/img-hash.c | 1030 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1045 insertions(+) create mode 100644 drivers/crypto/img-hash.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 9dd34bc3f541..8b18b6685269 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -445,4 +445,18 @@ config CRYPTO_DEV_VMX source "drivers/crypto/vmx/Kconfig" +config CRYPTO_DEV_IMGTEC_HASH + depends on MIPS || COMPILE_TEST + tristate "Imagination Technologies hardware hash accelerator" + select CRYPTO_ALG_API + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_SHA224 + select CRYPTO_SHA256 + select CRYPTO_HASH + help + This driver interfaces with the Imagination Technologies + hardware hash accelerator. Supporting MD5/SHA1/SHA224/SHA256 + hashing algorithms. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 20a71273369a..fb84be7e6be5 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o +obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c new file mode 100644 index 000000000000..027417273649 --- /dev/null +++ b/drivers/crypto/img-hash.c @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2014 Imagination Technologies + * Authors: Will Thomas, James Hartley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Interface structure taken from omap-sham driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CR_RESET 0 +#define CR_RESET_SET 1 +#define CR_RESET_UNSET 0 + +#define CR_MESSAGE_LENGTH_H 0x4 +#define CR_MESSAGE_LENGTH_L 0x8 + +#define CR_CONTROL 0xc +#define CR_CONTROL_BYTE_ORDER_3210 0 +#define CR_CONTROL_BYTE_ORDER_0123 1 +#define CR_CONTROL_BYTE_ORDER_2310 2 +#define CR_CONTROL_BYTE_ORDER_1032 3 +#define CR_CONTROL_BYTE_ORDER_SHIFT 8 +#define CR_CONTROL_ALGO_MD5 0 +#define CR_CONTROL_ALGO_SHA1 1 +#define CR_CONTROL_ALGO_SHA224 2 +#define CR_CONTROL_ALGO_SHA256 3 + +#define CR_INTSTAT 0x10 +#define CR_INTENAB 0x14 +#define CR_INTCLEAR 0x18 +#define CR_INT_RESULTS_AVAILABLE BIT(0) +#define CR_INT_NEW_RESULTS_SET BIT(1) +#define CR_INT_RESULT_READ_ERR BIT(2) +#define CR_INT_MESSAGE_WRITE_ERROR BIT(3) +#define CR_INT_STATUS BIT(8) + +#define CR_RESULT_QUEUE 0x1c +#define CR_RSD0 0x40 +#define CR_CORE_REV 0x50 +#define CR_CORE_DES1 0x60 +#define CR_CORE_DES2 0x70 + +#define DRIVER_FLAGS_BUSY BIT(0) +#define DRIVER_FLAGS_FINAL BIT(1) +#define DRIVER_FLAGS_DMA_ACTIVE BIT(2) +#define DRIVER_FLAGS_OUTPUT_READY BIT(3) +#define DRIVER_FLAGS_INIT BIT(4) +#define DRIVER_FLAGS_CPU BIT(5) +#define DRIVER_FLAGS_DMA_READY BIT(6) +#define DRIVER_FLAGS_ERROR BIT(7) +#define DRIVER_FLAGS_SG BIT(8) +#define DRIVER_FLAGS_SHA1 BIT(18) +#define DRIVER_FLAGS_SHA224 BIT(19) +#define DRIVER_FLAGS_SHA256 BIT(20) +#define DRIVER_FLAGS_MD5 BIT(21) + +#define IMG_HASH_QUEUE_LENGTH 20 +#define IMG_HASH_DMA_THRESHOLD 64 + +#ifdef __LITTLE_ENDIAN +#define IMG_HASH_BYTE_ORDER CR_CONTROL_BYTE_ORDER_3210 +#else +#define IMG_HASH_BYTE_ORDER CR_CONTROL_BYTE_ORDER_0123 +#endif + +struct img_hash_dev; + +struct img_hash_request_ctx { + struct img_hash_dev *hdev; + u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32)); + unsigned long flags; + size_t digsize; + + dma_addr_t dma_addr; + size_t dma_ct; + + /* sg root */ + struct scatterlist *sgfirst; + /* walk state */ + struct scatterlist *sg; + size_t nents; + size_t offset; + unsigned int total; + size_t sent; + + unsigned long op; + + size_t bufcnt; + u8 buffer[0] __aligned(sizeof(u32)); + struct ahash_request fallback_req; +}; + +struct img_hash_ctx { + struct img_hash_dev *hdev; + unsigned long flags; + struct crypto_ahash *fallback; +}; + +struct img_hash_dev { + struct list_head list; + struct device *dev; + struct clk *hash_clk; + struct clk *sys_clk; + void __iomem *io_base; + + phys_addr_t bus_addr; + void __iomem *cpu_addr; + + spinlock_t lock; + int err; + struct tasklet_struct done_task; + struct tasklet_struct dma_task; + + unsigned long flags; + struct crypto_queue queue; + struct ahash_request *req; + + struct dma_chan *dma_lch; +}; + +struct img_hash_drv { + struct list_head dev_list; + spinlock_t lock; +}; + +static struct img_hash_drv img_hash = { + .dev_list = LIST_HEAD_INIT(img_hash.dev_list), + .lock = __SPIN_LOCK_UNLOCKED(img_hash.lock), +}; + +static inline u32 img_hash_read(struct img_hash_dev *hdev, u32 offset) +{ + return readl_relaxed(hdev->io_base + offset); +} + +static inline void img_hash_write(struct img_hash_dev *hdev, + u32 offset, u32 value) +{ + writel_relaxed(value, hdev->io_base + offset); +} + +static inline u32 img_hash_read_result_queue(struct img_hash_dev *hdev) +{ + return be32_to_cpu(img_hash_read(hdev, CR_RESULT_QUEUE)); +} + +static void img_hash_start(struct img_hash_dev *hdev, bool dma) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + u32 cr = IMG_HASH_BYTE_ORDER << CR_CONTROL_BYTE_ORDER_SHIFT; + + if (ctx->flags & DRIVER_FLAGS_MD5) + cr |= CR_CONTROL_ALGO_MD5; + else if (ctx->flags & DRIVER_FLAGS_SHA1) + cr |= CR_CONTROL_ALGO_SHA1; + else if (ctx->flags & DRIVER_FLAGS_SHA224) + cr |= CR_CONTROL_ALGO_SHA224; + else if (ctx->flags & DRIVER_FLAGS_SHA256) + cr |= CR_CONTROL_ALGO_SHA256; + dev_dbg(hdev->dev, "Starting hash process\n"); + img_hash_write(hdev, CR_CONTROL, cr); + + /* + * The hardware block requires two cycles between writing the control + * register and writing the first word of data in non DMA mode, to + * ensure the first data write is not grouped in burst with the control + * register write a read is issued to 'flush' the bus. + */ + if (!dma) + img_hash_read(hdev, CR_CONTROL); +} + +static int img_hash_xmit_cpu(struct img_hash_dev *hdev, const u8 *buf, + size_t length, int final) +{ + u32 count, len32; + const u32 *buffer = (const u32 *)buf; + + dev_dbg(hdev->dev, "xmit_cpu: length: %u bytes\n", length); + + if (final) + hdev->flags |= DRIVER_FLAGS_FINAL; + + len32 = DIV_ROUND_UP(length, sizeof(u32)); + + for (count = 0; count < len32; count++) + writel_relaxed(buffer[count], hdev->cpu_addr); + + return -EINPROGRESS; +} + +static void img_hash_dma_callback(void *data) +{ + struct img_hash_dev *hdev = (struct img_hash_dev *)data; + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + + if (ctx->bufcnt) { + img_hash_xmit_cpu(hdev, ctx->buffer, ctx->bufcnt, 0); + ctx->bufcnt = 0; + } + if (ctx->sg) + tasklet_schedule(&hdev->dma_task); +} + +static int img_hash_xmit_dma(struct img_hash_dev *hdev, struct scatterlist *sg) +{ + struct dma_async_tx_descriptor *desc; + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + + ctx->dma_ct = dma_map_sg(hdev->dev, sg, 1, DMA_MEM_TO_DEV); + if (ctx->dma_ct == 0) { + dev_err(hdev->dev, "Invalid DMA sg\n"); + hdev->err = -EINVAL; + return -EINVAL; + } + + desc = dmaengine_prep_slave_sg(hdev->dma_lch, + sg, + ctx->dma_ct, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(hdev->dev, "Null DMA descriptor\n"); + hdev->err = -EINVAL; + dma_unmap_sg(hdev->dev, sg, 1, DMA_MEM_TO_DEV); + return -EINVAL; + } + desc->callback = img_hash_dma_callback; + desc->callback_param = hdev; + dmaengine_submit(desc); + dma_async_issue_pending(hdev->dma_lch); + + return 0; +} + +static int img_hash_write_via_cpu(struct img_hash_dev *hdev) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + + ctx->bufcnt = sg_copy_to_buffer(hdev->req->src, sg_nents(ctx->sg), + ctx->buffer, hdev->req->nbytes); + + ctx->total = hdev->req->nbytes; + ctx->bufcnt = 0; + + hdev->flags |= (DRIVER_FLAGS_CPU | DRIVER_FLAGS_FINAL); + + img_hash_start(hdev, false); + + return img_hash_xmit_cpu(hdev, ctx->buffer, ctx->total, 1); +} + +static int img_hash_finish(struct ahash_request *req) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(req); + + if (!req->result) + return -EINVAL; + + memcpy(req->result, ctx->digest, ctx->digsize); + + return 0; +} + +static void img_hash_copy_hash(struct ahash_request *req) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(req); + u32 *hash = (u32 *)ctx->digest; + int i; + + for (i = (ctx->digsize / sizeof(u32)) - 1; i >= 0; i--) + hash[i] = img_hash_read_result_queue(ctx->hdev); +} + +static void img_hash_finish_req(struct ahash_request *req, int err) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(req); + struct img_hash_dev *hdev = ctx->hdev; + + if (!err) { + img_hash_copy_hash(req); + if (DRIVER_FLAGS_FINAL & hdev->flags) + err = img_hash_finish(req); + } else { + dev_warn(hdev->dev, "Hash failed with error %d\n", err); + ctx->flags |= DRIVER_FLAGS_ERROR; + } + + hdev->flags &= ~(DRIVER_FLAGS_DMA_READY | DRIVER_FLAGS_OUTPUT_READY | + DRIVER_FLAGS_CPU | DRIVER_FLAGS_BUSY | DRIVER_FLAGS_FINAL); + + if (req->base.complete) + req->base.complete(&req->base, err); +} + +static int img_hash_write_via_dma(struct img_hash_dev *hdev) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + + img_hash_start(hdev, true); + + dev_dbg(hdev->dev, "xmit dma size: %d\n", ctx->total); + + if (!ctx->total) + hdev->flags |= DRIVER_FLAGS_FINAL; + + hdev->flags |= DRIVER_FLAGS_DMA_ACTIVE | DRIVER_FLAGS_FINAL; + + tasklet_schedule(&hdev->dma_task); + + return -EINPROGRESS; +} + +static int img_hash_dma_init(struct img_hash_dev *hdev) +{ + struct dma_slave_config dma_conf; + int err = -EINVAL; + + hdev->dma_lch = dma_request_slave_channel(hdev->dev, "tx"); + if (!hdev->dma_lch) { + dev_err(hdev->dev, "Couldn't aquire a slave DMA channel.\n"); + return -EBUSY; + } + dma_conf.direction = DMA_MEM_TO_DEV; + dma_conf.dst_addr = hdev->bus_addr; + dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_conf.dst_maxburst = 16; + dma_conf.device_fc = false; + + err = dmaengine_slave_config(hdev->dma_lch, &dma_conf); + if (err) { + dev_err(hdev->dev, "Couldn't configure DMA slave.\n"); + dma_release_channel(hdev->dma_lch); + return err; + } + + return 0; +} + +static void img_hash_dma_task(unsigned long d) +{ + struct img_hash_dev *hdev = (struct img_hash_dev *)d; + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + u8 *addr; + size_t nbytes, bleft, wsend, len, tbc; + struct scatterlist tsg; + + if (!ctx->sg) + return; + + addr = sg_virt(ctx->sg); + nbytes = ctx->sg->length - ctx->offset; + + /* + * The hash accelerator does not support a data valid mask. This means + * that if each dma (i.e. per page) is not a multiple of 4 bytes, the + * padding bytes in the last word written by that dma would erroneously + * be included in the hash. To avoid this we round down the transfer, + * and add the excess to the start of the next dma. It does not matter + * that the final dma may not be a multiple of 4 bytes as the hashing + * block is programmed to accept the correct number of bytes. + */ + + bleft = nbytes % 4; + wsend = (nbytes / 4); + + if (wsend) { + sg_init_one(&tsg, addr + ctx->offset, wsend * 4); + if (img_hash_xmit_dma(hdev, &tsg)) { + dev_err(hdev->dev, "DMA failed, falling back to CPU"); + ctx->flags |= DRIVER_FLAGS_CPU; + hdev->err = 0; + img_hash_xmit_cpu(hdev, addr + ctx->offset, + wsend * 4, 0); + ctx->sent += wsend * 4; + wsend = 0; + } else { + ctx->sent += wsend * 4; + } + } + + if (bleft) { + ctx->bufcnt = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents, + ctx->buffer, bleft, ctx->sent); + tbc = 0; + ctx->sg = sg_next(ctx->sg); + while (ctx->sg && (ctx->bufcnt < 4)) { + len = ctx->sg->length; + if (likely(len > (4 - ctx->bufcnt))) + len = 4 - ctx->bufcnt; + tbc = sg_pcopy_to_buffer(ctx->sgfirst, ctx->nents, + ctx->buffer + ctx->bufcnt, len, + ctx->sent + ctx->bufcnt); + ctx->bufcnt += tbc; + if (tbc >= ctx->sg->length) { + ctx->sg = sg_next(ctx->sg); + tbc = 0; + } + } + + ctx->sent += ctx->bufcnt; + ctx->offset = tbc; + + if (!wsend) + img_hash_dma_callback(hdev); + } else { + ctx->offset = 0; + ctx->sg = sg_next(ctx->sg); + } +} + +static int img_hash_write_via_dma_stop(struct img_hash_dev *hdev) +{ + struct img_hash_request_ctx *ctx = ahash_request_ctx(hdev->req); + + if (ctx->flags & DRIVER_FLAGS_SG) + dma_unmap_sg(hdev->dev, ctx->sg, ctx->dma_ct, DMA_TO_DEVICE); + + return 0; +} + +static int img_hash_process_data(struct img_hash_dev *hdev) +{ + struct ahash_request *req = hdev->req; + struct img_hash_request_ctx *ctx = ahash_request_ctx(req); + int err = 0; + + ctx->bufcnt = 0; + + if (req->nbytes >= IMG_HASH_DMA_THRESHOLD) { + dev_dbg(hdev->dev, "process data request(%d bytes) using DMA\n", + req->nbytes); + err = img_hash_write_via_dma(hdev); + } else { + dev_dbg(hdev->dev, "process data request(%d bytes) using CPU\n", + req->nbytes); + err = img_hash_write_via_cpu(hdev); + } + return err; +} + +static int img_hash_hw_init(struct img_hash_dev *hdev) +{ + unsigned long long nbits; + u32 u, l; + int ret; + + img_hash_write(hdev, CR_RESET, CR_RESET_SET); + img_hash_write(hdev, CR_RESET, CR_RESET_UNSET); + img_hash_write(hdev, CR_INTENAB, CR_INT_NEW_RESULTS_SET); + + nbits = (hdev->req->nbytes << 3); + u = nbits >> 32; + l = nbits; + img_hash_write(hdev, CR_MESSAGE_LENGTH_H, u); + img_hash_write(hdev, CR_MESSAGE_LENGTH_L, l); + + if (!(DRIVER_FLAGS_INIT & hdev->flags)) { + hdev->flags |= DRIVER_FLAGS_INIT; + hdev->err = 0; + } + dev_dbg(hdev->dev, "hw initialized, nbits: %llx\n", nbits); + return 0; +} + +static int img_hash_init(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct img_hash_request_ctx *rctx = ahash_request_ctx(req); + struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback); + rctx->fallback_req.base.flags = req->base.flags + & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_ahash_init(&rctx->fallback_req); +} + +static int img_hash_handle_queue(struct img_hash_dev *hdev, + struct ahash_request *req) +{ + struct crypto_async_request *async_req, *backlog; + struct img_hash_request_ctx *ctx; + unsigned long flags; + int err = 0, res = 0; + + spin_lock_irqsave(&hdev->lock, flags); + + if (req) + res = ahash_enqueue_request(&hdev->queue, req); + + if (DRIVER_FLAGS_BUSY & hdev->flags) { + spin_unlock_irqrestore(&hdev->lock, flags); + return res; + } + + backlog = crypto_get_backlog(&hdev->queue); + async_req = crypto_dequeue_request(&hdev->queue); + if (async_req) + hdev->flags |= DRIVER_FLAGS_BUSY; + + spin_unlock_irqrestore(&hdev->lock, flags); + + if (!async_req) + return res; + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + + req = ahash_request_cast(async_req); + hdev->req = req; + + ctx = ahash_request_ctx(req); + + dev_info(hdev->dev, "processing req, op: %lu, bytes: %d\n", + ctx->op, req->nbytes); + + err = img_hash_hw_init(hdev); + + if (!err) + err = img_hash_process_data(hdev); + + if (err != -EINPROGRESS) { + /* done_task will not finish so do it here */ + img_hash_finish_req(req, err); + } + return res; +} + +static int img_hash_update(struct ahash_request *req) +{ + struct img_hash_request_ctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback); + rctx->fallback_req.base.flags = req->base.flags + & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + + return crypto_ahash_update(&rctx->fallback_req); +} + +static int img_hash_final(struct ahash_request *req) +{ + struct img_hash_request_ctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback); + rctx->fallback_req.base.flags = req->base.flags + & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.result = req->result; + + return crypto_ahash_final(&rctx->fallback_req); +} + +static int img_hash_finup(struct ahash_request *req) +{ + struct img_hash_request_ctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct img_hash_ctx *ctx = crypto_ahash_ctx(tfm); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback); + rctx->fallback_req.base.flags = req->base.flags + & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; + + return crypto_ahash_finup(&rctx->fallback_req); +} + +static int img_hash_digest(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct img_hash_ctx *tctx = crypto_ahash_ctx(tfm); + struct img_hash_request_ctx *ctx = ahash_request_ctx(req); + struct img_hash_dev *hdev = NULL; + struct img_hash_dev *tmp; + int err; + + spin_lock(&img_hash.lock); + if (!tctx->hdev) { + list_for_each_entry(tmp, &img_hash.dev_list, list) { + hdev = tmp; + break; + } + tctx->hdev = hdev; + + } else { + hdev = tctx->hdev; + } + + spin_unlock(&img_hash.lock); + ctx->hdev = hdev; + ctx->flags = 0; + ctx->digsize = crypto_ahash_digestsize(tfm); + + switch (ctx->digsize) { + case SHA1_DIGEST_SIZE: + ctx->flags |= DRIVER_FLAGS_SHA1; + break; + case SHA256_DIGEST_SIZE: + ctx->flags |= DRIVER_FLAGS_SHA256; + break; + case SHA224_DIGEST_SIZE: + ctx->flags |= DRIVER_FLAGS_SHA224; + break; + case MD5_DIGEST_SIZE: + ctx->flags |= DRIVER_FLAGS_MD5; + break; + default: + return -EINVAL; + } + + ctx->bufcnt = 0; + ctx->offset = 0; + ctx->sent = 0; + ctx->total = req->nbytes; + ctx->sg = req->src; + ctx->sgfirst = req->src; + ctx->nents = sg_nents(ctx->sg); + + err = img_hash_handle_queue(tctx->hdev, req); + + return err; +} + +static int img_hash_cra_init(struct crypto_tfm *tfm) +{ + struct img_hash_ctx *ctx = crypto_tfm_ctx(tfm); + const char *alg_name = crypto_tfm_alg_name(tfm); + int err = -ENOMEM; + + ctx->fallback = crypto_alloc_ahash(alg_name, 0, + CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(ctx->fallback)) { + pr_err("img_hash: Could not load fallback driver.\n"); + err = PTR_ERR(ctx->fallback); + goto err; + } + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct img_hash_request_ctx) + + IMG_HASH_DMA_THRESHOLD); + + return 0; + +err: + return err; +} + +static void img_hash_cra_exit(struct crypto_tfm *tfm) +{ + struct img_hash_ctx *tctx = crypto_tfm_ctx(tfm); + + crypto_free_ahash(tctx->fallback); +} + +static irqreturn_t img_irq_handler(int irq, void *dev_id) +{ + struct img_hash_dev *hdev = dev_id; + u32 reg; + + reg = img_hash_read(hdev, CR_INTSTAT); + img_hash_write(hdev, CR_INTCLEAR, reg); + + if (reg & CR_INT_NEW_RESULTS_SET) { + dev_dbg(hdev->dev, "IRQ CR_INT_NEW_RESULTS_SET\n"); + if (DRIVER_FLAGS_BUSY & hdev->flags) { + hdev->flags |= DRIVER_FLAGS_OUTPUT_READY; + if (!(DRIVER_FLAGS_CPU & hdev->flags)) + hdev->flags |= DRIVER_FLAGS_DMA_READY; + tasklet_schedule(&hdev->done_task); + } else { + dev_warn(hdev->dev, + "HASH interrupt when no active requests.\n"); + } + } else if (reg & CR_INT_RESULTS_AVAILABLE) { + dev_warn(hdev->dev, + "IRQ triggered before the hash had completed\n"); + } else if (reg & CR_INT_RESULT_READ_ERR) { + dev_warn(hdev->dev, + "Attempt to read from an empty result queue\n"); + } else if (reg & CR_INT_MESSAGE_WRITE_ERROR) { + dev_warn(hdev->dev, + "Data written before the hardware was configured\n"); + } + return IRQ_HANDLED; +} + +static struct ahash_alg img_algs[] = { + { + .init = img_hash_init, + .update = img_hash_update, + .final = img_hash_final, + .finup = img_hash_finup, + .digest = img_hash_digest, + .halg = { + .digestsize = MD5_DIGEST_SIZE, + .base = { + .cra_name = "md5", + .cra_driver_name = "img-md5", + .cra_priority = 300, + .cra_flags = + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct img_hash_ctx), + .cra_init = img_hash_cra_init, + .cra_exit = img_hash_cra_exit, + .cra_module = THIS_MODULE, + } + } + }, + { + .init = img_hash_init, + .update = img_hash_update, + .final = img_hash_final, + .finup = img_hash_finup, + .digest = img_hash_digest, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "sha1", + .cra_driver_name = "img-sha1", + .cra_priority = 300, + .cra_flags = + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct img_hash_ctx), + .cra_init = img_hash_cra_init, + .cra_exit = img_hash_cra_exit, + .cra_module = THIS_MODULE, + } + } + }, + { + .init = img_hash_init, + .update = img_hash_update, + .final = img_hash_final, + .finup = img_hash_finup, + .digest = img_hash_digest, + .halg = { + .digestsize = SHA224_DIGEST_SIZE, + .base = { + .cra_name = "sha224", + .cra_driver_name = "img-sha224", + .cra_priority = 300, + .cra_flags = + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA224_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct img_hash_ctx), + .cra_init = img_hash_cra_init, + .cra_exit = img_hash_cra_exit, + .cra_module = THIS_MODULE, + } + } + }, + { + .init = img_hash_init, + .update = img_hash_update, + .final = img_hash_final, + .finup = img_hash_finup, + .digest = img_hash_digest, + .halg = { + .digestsize = SHA256_DIGEST_SIZE, + .base = { + .cra_name = "sha256", + .cra_driver_name = "img-sha256", + .cra_priority = 300, + .cra_flags = + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct img_hash_ctx), + .cra_init = img_hash_cra_init, + .cra_exit = img_hash_cra_exit, + .cra_module = THIS_MODULE, + } + } + } +}; + +static int img_register_algs(struct img_hash_dev *hdev) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(img_algs); i++) { + err = crypto_register_ahash(&img_algs[i]); + if (err) + goto err_reg; + } + return 0; + +err_reg: + for (; i--; ) + crypto_unregister_ahash(&img_algs[i]); + + return err; +} + +static int img_unregister_algs(struct img_hash_dev *hdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(img_algs); i++) + crypto_unregister_ahash(&img_algs[i]); + return 0; +} + +static void img_hash_done_task(unsigned long data) +{ + struct img_hash_dev *hdev = (struct img_hash_dev *)data; + int err = 0; + + if (hdev->err == -EINVAL) { + err = hdev->err; + goto finish; + } + + if (!(DRIVER_FLAGS_BUSY & hdev->flags)) { + img_hash_handle_queue(hdev, NULL); + return; + } + + if (DRIVER_FLAGS_CPU & hdev->flags) { + if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) { + hdev->flags &= ~DRIVER_FLAGS_OUTPUT_READY; + goto finish; + } + } else if (DRIVER_FLAGS_DMA_READY & hdev->flags) { + if (DRIVER_FLAGS_DMA_ACTIVE & hdev->flags) { + hdev->flags &= ~DRIVER_FLAGS_DMA_ACTIVE; + img_hash_write_via_dma_stop(hdev); + if (hdev->err) { + err = hdev->err; + goto finish; + } + } + if (DRIVER_FLAGS_OUTPUT_READY & hdev->flags) { + hdev->flags &= ~(DRIVER_FLAGS_DMA_READY | + DRIVER_FLAGS_OUTPUT_READY); + goto finish; + } + } + return; + +finish: + img_hash_finish_req(hdev->req, err); +} + +static const struct of_device_id img_hash_match[] = { + { .compatible = "img,hash-accelerator" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_hash_match) + +static int img_hash_probe(struct platform_device *pdev) +{ + struct img_hash_dev *hdev; + struct device *dev = &pdev->dev; + struct resource *hash_res; + int irq; + int err; + + hdev = devm_kzalloc(dev, sizeof(*hdev), GFP_KERNEL); + if (hdev == NULL) + return -ENOMEM; + + spin_lock_init(&hdev->lock); + + hdev->dev = dev; + + platform_set_drvdata(pdev, hdev); + + INIT_LIST_HEAD(&hdev->list); + + tasklet_init(&hdev->done_task, img_hash_done_task, (unsigned long)hdev); + tasklet_init(&hdev->dma_task, img_hash_dma_task, (unsigned long)hdev); + + crypto_init_queue(&hdev->queue, IMG_HASH_QUEUE_LENGTH); + + /* Register bank */ + hash_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + hdev->io_base = devm_ioremap_resource(dev, hash_res); + if (IS_ERR(hdev->io_base)) { + err = PTR_ERR(hdev->io_base); + dev_err(dev, "can't ioremap, returned %d\n", err); + + goto res_err; + } + + /* Write port (DMA or CPU) */ + hash_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + hdev->cpu_addr = devm_ioremap_resource(dev, hash_res); + if (IS_ERR(hdev->cpu_addr)) { + dev_err(dev, "can't ioremap write port\n"); + err = PTR_ERR(hdev->cpu_addr); + goto res_err; + } + hdev->bus_addr = hash_res->start; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no IRQ resource info\n"); + err = irq; + goto res_err; + } + + err = devm_request_irq(dev, irq, img_irq_handler, 0, + dev_name(dev), hdev); + if (err) { + dev_err(dev, "unable to request irq\n"); + goto res_err; + } + dev_dbg(dev, "using IRQ channel %d\n", irq); + + hdev->hash_clk = devm_clk_get(&pdev->dev, "hash"); + if (IS_ERR(hdev->hash_clk)) { + dev_err(dev, "clock initialization failed.\n"); + err = PTR_ERR(hdev->hash_clk); + goto res_err; + } + + hdev->sys_clk = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(hdev->sys_clk)) { + dev_err(dev, "clock initialization failed.\n"); + err = PTR_ERR(hdev->sys_clk); + goto res_err; + } + + err = clk_prepare_enable(hdev->hash_clk); + if (err) + goto res_err; + + err = clk_prepare_enable(hdev->sys_clk); + if (err) + goto clk_err; + + err = img_hash_dma_init(hdev); + if (err) + goto dma_err; + + dev_dbg(dev, "using %s for DMA transfers\n", + dma_chan_name(hdev->dma_lch)); + + spin_lock(&img_hash.lock); + list_add_tail(&hdev->list, &img_hash.dev_list); + spin_unlock(&img_hash.lock); + + err = img_register_algs(hdev); + if (err) + goto err_algs; + dev_dbg(dev, "Img MD5/SHA1/SHA224/SHA256 Hardware accelerator initialized\n"); + + return 0; + +err_algs: + spin_lock(&img_hash.lock); + list_del(&hdev->list); + spin_unlock(&img_hash.lock); + dma_release_channel(hdev->dma_lch); +dma_err: + clk_disable_unprepare(hdev->sys_clk); +clk_err: + clk_disable_unprepare(hdev->hash_clk); +res_err: + tasklet_kill(&hdev->done_task); + tasklet_kill(&hdev->dma_task); + + return err; +} + +static int img_hash_remove(struct platform_device *pdev) +{ + static struct img_hash_dev *hdev; + + hdev = platform_get_drvdata(pdev); + spin_lock(&img_hash.lock); + list_del(&hdev->list); + spin_unlock(&img_hash.lock); + + img_unregister_algs(hdev); + + tasklet_kill(&hdev->done_task); + tasklet_kill(&hdev->dma_task); + + dma_release_channel(hdev->dma_lch); + + clk_disable_unprepare(hdev->hash_clk); + clk_disable_unprepare(hdev->sys_clk); + + return 0; +} + +static struct platform_driver img_hash_driver = { + .probe = img_hash_probe, + .remove = img_hash_remove, + .driver = { + .name = "img-hash-accelerator", + .of_match_table = of_match_ptr(img_hash_match), + } +}; +module_platform_driver(img_hash_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Imgtec SHA1/224/256 & MD5 hw accelerator driver"); +MODULE_AUTHOR("Will Thomas."); +MODULE_AUTHOR("James Hartley "); -- GitLab From 5986ac4fcb451160acdc8bf3a0b81ac9a72b3251 Mon Sep 17 00:00:00 2001 From: James Hartley Date: Thu, 12 Mar 2015 23:17:27 +0000 Subject: [PATCH 0368/1910] Documentation: crypto: Add DT binding info for the img hw hash accelerator This adds the binding documentation for the Imagination Technologies hash accelerator that provides hardware acceleration for SHA1/SHA224/SHA256/MD5 hashes. This hardware will be present in the upcoming pistachio SoC. Signed-off-by: James Hartley Reviewed-by: Andrew Bresticker Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/img-hash.txt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/img-hash.txt diff --git a/Documentation/devicetree/bindings/crypto/img-hash.txt b/Documentation/devicetree/bindings/crypto/img-hash.txt new file mode 100644 index 000000000000..91a3d757d641 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/img-hash.txt @@ -0,0 +1,27 @@ +Imagination Technologies hardware hash accelerator + +The hash accelerator provides hardware hashing acceleration for +SHA1, SHA224, SHA256 and MD5 hashes + +Required properties: + +- compatible : "img,hash-accelerator" +- reg : Offset and length of the register set for the module, and the DMA port +- interrupts : The designated IRQ line for the hashing module. +- dmas : DMA specifier as per Documentation/devicetree/bindings/dma/dma.txt +- dma-names : Should be "tx" +- clocks : Clock specifiers +- clock-names : "sys" Used to clock the hash block registers + "hash" Used to clock data through the accelerator + +Example: + + hash: hash@18149600 { + compatible = "img,hash-accelerator"; + reg = <0x18149600 0x100>, <0x18101100 0x4>; + interrupts = ; + dmas = <&dma 8 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_HASH>, <&clk_periph PERIPH_CLK_ROM>; + clock-names = "sys", "hash"; + }; -- GitLab From 2ef4d5c43de945b7c78454eac63e5f4fe68f82fc Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Fri, 13 Mar 2015 11:44:07 +0100 Subject: [PATCH 0369/1910] crypto: algif_rng - zeroize buffer with random data Due to the change to RNGs to always return zero in success case, the RNG interface must zeroize the buffer with the length provided by the caller. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/algif_rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index 67f612cfed97..a34617359cd9 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -87,7 +87,7 @@ static int rng_recvmsg(struct kiocb *unused, struct socket *sock, return genlen; err = memcpy_to_msg(msg, result, len); - memzero_explicit(result, genlen); + memzero_explicit(result, len); return err ? err : len; } -- GitLab From c42e9902f3f1e731a7b83397acdf402eeb3237ca Mon Sep 17 00:00:00 2001 From: Ameen Ali Date: Fri, 13 Mar 2015 23:38:21 +0200 Subject: [PATCH 0370/1910] crypto: sha1-mb - Syntax error fixing a syntax-error . Signed-off-by: Ameen Ali Signed-off-by: Herbert Xu --- arch/x86/crypto/sha-mb/sha1_mb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/crypto/sha-mb/sha1_mb.c b/arch/x86/crypto/sha-mb/sha1_mb.c index fd9f6b035b16..9414fd964ecd 100644 --- a/arch/x86/crypto/sha-mb/sha1_mb.c +++ b/arch/x86/crypto/sha-mb/sha1_mb.c @@ -828,7 +828,7 @@ static unsigned long sha1_mb_flusher(struct mcryptd_alg_cstate *cstate) while (!list_empty(&cstate->work_list)) { rctx = list_entry(cstate->work_list.next, struct mcryptd_hash_request_ctx, waiter); - if time_before(cur_time, rctx->tag.expire) + if (time_before(cur_time, rctx->tag.expire)) break; kernel_fpu_begin(); sha_ctx = (struct sha1_hash_ctx *) sha1_ctx_mgr_flush(cstate->mgr); -- GitLab From 97a33ced310ab9bdb16699c2c64b28f29de0a23d Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 00:54:16 -0700 Subject: [PATCH 0371/1910] ASoC: qcom: Change qcom,adsp in LPASS CPU bindings Change the representation of the audio DSP, in the LPASS CPU bindings description, from a required subnode to an optional phandle. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,lpass-cpu.txt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt index e7c6e9321863..e00732dac939 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt @@ -22,13 +22,9 @@ Required properties: - reg-names : A list which must include the following entries: * "lpass-lpaif" -Required subnodes: +Optional properties: -- qcom,adsp : Audio DSP sub-node - -Optional Audio DSP subnode properties: - -- status : "disabled" indicates the adsp is not available. +- qcom,adsp : Phandle for the audio DSP node Example: @@ -43,7 +39,5 @@ lpass@28100000 { pinctrl-1 = <&mi2s_idle>; reg = <0x28100000 0x10000>; reg-names = "lpass-lpaif"; - qcom,adsp { - status = "disabled"; - }; + qcom,adsp = <&adsp>; }; -- GitLab From 8ebe148be9aa12641c62a3c99c65859bf95445fe Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 00:54:17 -0700 Subject: [PATCH 0372/1910] ASoC: qcom: Modify test for DSP in LPASS driver As the representation of the DSP in the device tree has changed from a required subnode to an optional phandle, modify the test for DSP existence in the LPASS CPU DAI driver, accordingly. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index d5167131787f..6698d058de29 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -359,45 +359,26 @@ static const struct regmap_config lpass_cpu_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static int lpass_cpu_parse_of(struct device *dev) +static int lpass_cpu_platform_probe(struct platform_device *pdev) { + struct lpass_data *drvdata; struct device_node *dsp_of_node; + struct resource *res; + int ret; - dsp_of_node = of_get_child_by_name(dev->of_node, "qcom,adsp"); - if (!dsp_of_node) { - dev_err(dev, "%s() error getting qcom,adsp sub-node\n", - __func__); - return -EINVAL; - } - - if (of_device_is_available(dsp_of_node)) { - dev_err(dev, "%s() DSP exists and holds audio resources\n", + dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); + if (dsp_of_node) { + dev_err(&pdev->dev, "%s() DSP exists and holds audio resources\n", __func__); return -EBUSY; } - return 0; -} - -static int lpass_cpu_platform_probe(struct platform_device *pdev) -{ - struct lpass_data *drvdata; - struct resource *res; - int ret; - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct lpass_data), GFP_KERNEL); if (!drvdata) return -ENOMEM; platform_set_drvdata(pdev, drvdata); - ret = lpass_cpu_parse_of(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "%s() error getting DT node info: %d\n", - __func__, ret); - return ret; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif"); if (!res) { dev_err(&pdev->dev, "%s() error getting resource\n", __func__); -- GitLab From 81ddc01d56d773eed414b5c1a7f1dba1db35f538 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 01:01:04 -0700 Subject: [PATCH 0373/1910] ASoC: qcom: Document Storm bindings Add documentation to the sound directory of the device-tree bindings for the soundcard of the Storm board. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/storm.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/storm.txt diff --git a/Documentation/devicetree/bindings/sound/storm.txt b/Documentation/devicetree/bindings/sound/storm.txt new file mode 100644 index 000000000000..062a4c185fa9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/storm.txt @@ -0,0 +1,23 @@ +* Sound complex for Storm boards + +Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC +connected to a MAX98357A DAC via I2S. + +Required properties: + +- compatible : "google,storm-audio" +- cpu : Phandle of the CPU DAI +- codec : Phandle of the codec DAI + +Optional properties: + +- qcom,model : The user-visible name of this sound card. + +Example: + +sound { + compatible = "google,storm-audio"; + qcom,model = "ipq806x-storm"; + cpu = <&lpass_cpu>; + codec = <&max98357a>; +}; -- GitLab From 79119c798649630b3191784a708b45cea4e31daf Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 01:01:05 -0700 Subject: [PATCH 0374/1910] ASoC: qcom: Add Storm machine driver Add machine driver for the Storm board with the IPQ806X SOC connected to the MAX98357A DAC. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/qcom/storm.c | 162 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 sound/soc/qcom/storm.c diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c new file mode 100644 index 000000000000..b8bd296190ad --- /dev/null +++ b/sound/soc/qcom/storm.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define STORM_SYSCLK_MULT 4 + +static int storm_ops_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct snd_soc_card *card = soc_runtime->card; + snd_pcm_format_t format = params_format(params); + unsigned int rate = params_rate(params); + unsigned int sysclk_freq; + int bitwidth, ret; + + bitwidth = snd_pcm_format_width(format); + if (bitwidth < 0) { + dev_err(card->dev, "%s() invalid bit width given: %d\n", + __func__, bitwidth); + return bitwidth; + } + + /* + * as the CPU DAI is the I2S bus master and no system clock is needed by + * the MAX98357a DAC, simply set the system clock to be a constant + * multiple of the bit clock for the clock divider + */ + sysclk_freq = rate * bitwidth * 2 * STORM_SYSCLK_MULT; + + ret = snd_soc_dai_set_sysclk(soc_runtime->cpu_dai, 0, sysclk_freq, 0); + if (ret) { + dev_err(card->dev, "%s() error setting sysclk to %u: %d\n", + __func__, sysclk_freq, ret); + return ret; + } + + return 0; +} + +static struct snd_soc_ops storm_soc_ops = { + .hw_params = storm_ops_hw_params, +}; + +static struct snd_soc_dai_link storm_dai_link = { + .name = "Primary", + .stream_name = "Primary", + .codec_dai_name = "HiFi", + .ops = &storm_soc_ops, +}; + +static struct snd_soc_card storm_soc_card = { + .name = "ipq806x-storm", + .dev = NULL, +}; + +static int storm_parse_of(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np = card->dev->of_node; + + dai_link->cpu_of_node = of_parse_phandle(np, "cpu", 0); + if (!dai_link->cpu_of_node) { + dev_err(card->dev, "%s() error getting cpu phandle\n", + __func__); + return -EINVAL; + } + dai_link->platform_of_node = dai_link->cpu_of_node; + + dai_link->codec_of_node = of_parse_phandle(np, "codec", 0); + if (!dai_link->codec_of_node) { + dev_err(card->dev, "%s() error getting codec phandle\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int storm_platform_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &storm_soc_card; + int ret; + + if (card->dev) { + dev_err(&pdev->dev, "%s() error, existing soundcard\n", + __func__); + return -ENODEV; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "%s() error parsing card name: %d\n", + __func__, ret); + return ret; + } + + card->dai_link = &storm_dai_link; + card->num_links = 1; + + ret = storm_parse_of(card); + if (ret) { + dev_err(&pdev->dev, "%s() error resolving dai links: %d\n", + __func__, ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) { + card->dev = NULL; + return ret; + } else if (ret) { + dev_err(&pdev->dev, "%s() error registering soundcard: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id storm_device_id[] = { + { .compatible = "google,storm-audio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, storm_device_id); +#endif + +static struct platform_driver storm_platform_driver = { + .driver = { + .name = "storm-audio", + .of_match_table = + of_match_ptr(storm_device_id), + }, + .probe = storm_platform_probe, +}; +module_platform_driver(storm_platform_driver); + +MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From f380dd3f3cd77df3c5d297a635b635f72fb5a2b1 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 01:01:06 -0700 Subject: [PATCH 0375/1910] ASoC: qcom: Add ability to build QCOM drivers Define the LPASS platform driver, the LPASS CPU DAI driver and the Storm machine driver configurations, and how to build them. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 25 +++++++++++++++++++++++++ sound/soc/qcom/Makefile | 11 +++++++++++ 2 files changed, 36 insertions(+) create mode 100644 sound/soc/qcom/Kconfig create mode 100644 sound/soc/qcom/Makefile diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig new file mode 100644 index 000000000000..5f58e4f1bca9 --- /dev/null +++ b/sound/soc/qcom/Kconfig @@ -0,0 +1,25 @@ +config SND_SOC_QCOM + tristate "ASoC support for QCOM platforms" + help + Say Y or M if you want to add support to use audio devices + in Qualcomm Technologies SOC-based platforms. + +config SND_SOC_LPASS_CPU + tristate + depends on SND_SOC_QCOM + select REGMAP_MMIO + +config SND_SOC_LPASS_PLATFORM + tristate + depends on SND_SOC_QCOM + select REGMAP_MMIO + +config SND_SOC_STORM + tristate "ASoC I2S support for Storm boards" + depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST + select SND_SOC_LPASS_CPU + select SND_SOC_LPASS_PLATFORM + select SND_SOC_MAX98357A + help + Say Y or M if you want add support for SoC audio on the + Qualcomm Technologies IPQ806X-based Storm board. diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile new file mode 100644 index 000000000000..c5ce96c761c4 --- /dev/null +++ b/sound/soc/qcom/Makefile @@ -0,0 +1,11 @@ +# Platform +snd-soc-lpass-cpu-objs := lpass-cpu.o +snd-soc-lpass-platform-objs := lpass-platform.o + +obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o +obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o + +# Machine +snd-soc-storm-objs := storm.o + +obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o -- GitLab From 6a328885896ef087a28173792ea93f4dde9782ef Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Fri, 13 Mar 2015 01:01:07 -0700 Subject: [PATCH 0376/1910] ASoC: Allow for building QCOM drivers Allow for the Qualcomm Technologies ASoC drivers to build. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index dcc79aa0236b..3ba52da18bc6 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -47,6 +47,7 @@ source "sound/soc/kirkwood/Kconfig" source "sound/soc/intel/Kconfig" source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" +source "sound/soc/qcom/Kconfig" source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 5b3c8f67c8db..974ba708b482 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ +obj-$(CONFIG_SND_SOC) += qcom/ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ -- GitLab From 6b5b042d4c675cb9d3446a1cdcaca98e715ba812 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 15 Mar 2015 10:27:20 +0100 Subject: [PATCH 0377/1910] ASoC: Make snd_soc_dapm_kcontrol_codec() inline snd_soc_dapm_kcontrol_codec() is a extremely simple function and inlining it typically results in less code than necessary for calling the non-inlined version of the function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 - include/sound/soc.h | 13 +++++++++++++ sound/soc/soc-dapm.c | 10 ---------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8d7416e46861..78633efd40ee 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -440,7 +440,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card); int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget_list **list); -struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol); struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( struct snd_kcontrol *kcontrol); diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..85a6853a40bb 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1258,6 +1258,19 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( return component->dapm_ptr; } +/** + * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol + * @kcontrol: The kcontrol + * + * This function must only be used on DAPM contexts that are known to be part of + * a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined. + */ +static inline struct snd_soc_codec *snd_soc_dapm_kcontrol_codec( + struct snd_kcontrol *kcontrol) +{ + return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol)); +} + /* codec IO */ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b6f88202b8c9..95337c832258 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -473,16 +473,6 @@ struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( } EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm); -/** - * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol - * @kcontrol: The kcontrol - */ -struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) -{ - return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol)); -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); - static void dapm_reset(struct snd_soc_card *card) { struct snd_soc_dapm_widget *w; -- GitLab From fa41181fe37530d78acb25b4e2c9c019241cbbf6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 15 Mar 2015 12:15:24 +0100 Subject: [PATCH 0378/1910] ASoC: nuc900: No need to track the dma buffer in the driver state struct The DMA buffer and address can be accessed through the snd_pcm_runtime. There is no need to manually track them in the driver's state struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-audio.h | 3 --- sound/soc/nuc900/nuc900-pcm.c | 31 +++++-------------------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h index 59f7e8ed1a68..d0b725705914 100644 --- a/sound/soc/nuc900/nuc900-audio.h +++ b/sound/soc/nuc900/nuc900-audio.h @@ -100,10 +100,7 @@ struct nuc900_audio { void __iomem *mmio; spinlock_t lock; - dma_addr_t dma_addr[2]; - unsigned long buffersize[2]; unsigned long irq_num; - struct snd_pcm_substream *substream; struct resource *res; struct clk *clk; struct device *dev; diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index b809fa909e4d..5ae5ca15b6d6 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -42,29 +42,10 @@ static const struct snd_pcm_hardware nuc900_pcm_hardware = { static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long flags; - int ret = 0; - - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); - if (ret < 0) - return ret; - - spin_lock_irqsave(&nuc900_audio->lock, flags); - - nuc900_audio->substream = substream; - nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr; - nuc900_audio->buffersize[substream->stream] = - params_buffer_bytes(params); - - spin_unlock_irqrestore(&nuc900_audio->lock, flags); - - return ret; + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } -static void nuc900_update_dma_register(struct snd_pcm_substream *substream, - dma_addr_t dma_addr, size_t count) +static void nuc900_update_dma_register(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct nuc900_audio *nuc900_audio = runtime->private_data; @@ -78,8 +59,8 @@ static void nuc900_update_dma_register(struct snd_pcm_substream *substream, mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; } - AUDIO_WRITE(mmio_addr, dma_addr); - AUDIO_WRITE(mmio_len, count); + AUDIO_WRITE(mmio_addr, runtime->dma_addr); + AUDIO_WRITE(mmio_len, runtime->dma_bytes); } static void nuc900_dma_start(struct snd_pcm_substream *substream) @@ -170,9 +151,7 @@ static int nuc900_dma_prepare(struct snd_pcm_substream *substream) spin_lock_irqsave(&nuc900_audio->lock, flags); - nuc900_update_dma_register(substream, - nuc900_audio->dma_addr[substream->stream], - nuc900_audio->buffersize[substream->stream]); + nuc900_update_dma_register(substream); val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); -- GitLab From c36aa0a1929a1f0f0b8c374276e49cc663e8f957 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 16 Mar 2015 14:39:57 +0800 Subject: [PATCH 0379/1910] ASoC: rt5677: add API to select ASRC clock source This patch defines an API to select the clock source for specified filters. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 163 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5677.h | 79 ++++++++++++++++++ 2 files changed, 242 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index c2a6e4091357..af182586712d 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1034,6 +1034,169 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, return 0; } +/** + * rt5677_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5677 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + unsigned int asrc3_mask = 0, asrc3_value = 0; + unsigned int asrc4_mask = 0, asrc4_value = 0; + unsigned int asrc5_mask = 0, asrc5_value = 0; + unsigned int asrc6_mask = 0, asrc6_value = 0; + unsigned int asrc7_mask = 0, asrc7_value = 0; + + switch (clk_src) { + case RT5677_CLK_SEL_SYS: + case RT5677_CLK_SEL_I2S1_ASRC: + case RT5677_CLK_SEL_I2S2_ASRC: + case RT5677_CLK_SEL_I2S3_ASRC: + case RT5677_CLK_SEL_I2S4_ASRC: + case RT5677_CLK_SEL_I2S5_ASRC: + case RT5677_CLK_SEL_I2S6_ASRC: + case RT5677_CLK_SEL_SYS2: + case RT5677_CLK_SEL_SYS3: + case RT5677_CLK_SEL_SYS4: + case RT5677_CLK_SEL_SYS5: + case RT5677_CLK_SEL_SYS6: + case RT5677_CLK_SEL_SYS7: + break; + + default: + return -EINVAL; + } + + /* ASRC 3 */ + if (filter_mask & RT5677_DA_STEREO_FILTER) { + asrc3_mask |= RT5677_DA_STO_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5677_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5677_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DA_MONO2_L_FILTER) { + asrc3_mask |= RT5677_DA_MONO2L_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5677_DA_MONO2L_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO2L_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DA_MONO2_R_FILTER) { + asrc3_mask |= RT5677_DA_MONO2R_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5677_DA_MONO2R_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO2R_CLK_SEL_SFT); + } + + if (asrc3_mask) + regmap_update_bits(rt5677->regmap, RT5677_ASRC_3, asrc3_mask, + asrc3_value); + + /* ASRC 4 */ + if (filter_mask & RT5677_DA_MONO3_L_FILTER) { + asrc4_mask |= RT5677_DA_MONO3L_CLK_SEL_MASK; + asrc4_value = (asrc4_value & ~RT5677_DA_MONO3L_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO3L_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DA_MONO3_R_FILTER) { + asrc4_mask |= RT5677_DA_MONO3R_CLK_SEL_MASK; + asrc4_value = (asrc4_value & ~RT5677_DA_MONO3R_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO3R_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DA_MONO4_L_FILTER) { + asrc4_mask |= RT5677_DA_MONO4L_CLK_SEL_MASK; + asrc4_value = (asrc4_value & ~RT5677_DA_MONO4L_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO4L_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DA_MONO4_R_FILTER) { + asrc4_mask |= RT5677_DA_MONO4R_CLK_SEL_MASK; + asrc4_value = (asrc4_value & ~RT5677_DA_MONO4R_CLK_SEL_MASK) + | (clk_src << RT5677_DA_MONO4R_CLK_SEL_SFT); + } + + if (asrc4_mask) + regmap_update_bits(rt5677->regmap, RT5677_ASRC_4, asrc4_mask, + asrc4_value); + + /* ASRC 5 */ + if (filter_mask & RT5677_AD_STEREO1_FILTER) { + asrc5_mask |= RT5677_AD_STO1_CLK_SEL_MASK; + asrc5_value = (asrc5_value & ~RT5677_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5677_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_AD_STEREO2_FILTER) { + asrc5_mask |= RT5677_AD_STO2_CLK_SEL_MASK; + asrc5_value = (asrc5_value & ~RT5677_AD_STO2_CLK_SEL_MASK) + | (clk_src << RT5677_AD_STO2_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_AD_STEREO3_FILTER) { + asrc5_mask |= RT5677_AD_STO3_CLK_SEL_MASK; + asrc5_value = (asrc5_value & ~RT5677_AD_STO3_CLK_SEL_MASK) + | (clk_src << RT5677_AD_STO3_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_AD_STEREO4_FILTER) { + asrc5_mask |= RT5677_AD_STO4_CLK_SEL_MASK; + asrc5_value = (asrc5_value & ~RT5677_AD_STO4_CLK_SEL_MASK) + | (clk_src << RT5677_AD_STO4_CLK_SEL_SFT); + } + + if (asrc5_mask) + regmap_update_bits(rt5677->regmap, RT5677_ASRC_5, asrc5_mask, + asrc5_value); + + /* ASRC 6 */ + if (filter_mask & RT5677_AD_MONO_L_FILTER) { + asrc6_mask |= RT5677_AD_MONOL_CLK_SEL_MASK; + asrc6_value = (asrc6_value & ~RT5677_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5677_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_AD_MONO_R_FILTER) { + asrc6_mask |= RT5677_AD_MONOR_CLK_SEL_MASK; + asrc6_value = (asrc6_value & ~RT5677_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5677_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc6_mask) + regmap_update_bits(rt5677->regmap, RT5677_ASRC_6, asrc6_mask, + asrc6_value); + + /* ASRC 7 */ + if (filter_mask & RT5677_DSP_OB_0_3_FILTER) { + asrc7_mask |= RT5677_DSP_OB_0_3_CLK_SEL_MASK; + asrc7_value = (asrc7_value & ~RT5677_DSP_OB_0_3_CLK_SEL_MASK) + | (clk_src << RT5677_DSP_OB_0_3_CLK_SEL_SFT); + } + + if (filter_mask & RT5677_DSP_OB_4_7_FILTER) { + asrc7_mask |= RT5677_DSP_OB_4_7_CLK_SEL_MASK; + asrc7_value = (asrc7_value & ~RT5677_DSP_OB_4_7_CLK_SEL_MASK) + | (clk_src << RT5677_DSP_OB_4_7_CLK_SEL_SFT); + } + + if (asrc7_mask) + regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask, + asrc7_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 07df96b43f59..9dceb41d18ea 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1406,6 +1406,46 @@ #define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7) #define RT5677_DSP_CLK_SRC_BYPASS (0x1 << 7) +/* ASRC Control 3 (0x85) */ +#define RT5677_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5677_DA_STO_CLK_SEL_SFT 12 +#define RT5677_DA_MONO2L_CLK_SEL_MASK (0xf << 4) +#define RT5677_DA_MONO2L_CLK_SEL_SFT 4 +#define RT5677_DA_MONO2R_CLK_SEL_MASK (0xf << 0) +#define RT5677_DA_MONO2R_CLK_SEL_SFT 0 + +/* ASRC Control 4 (0x86) */ +#define RT5677_DA_MONO3L_CLK_SEL_MASK (0xf << 12) +#define RT5677_DA_MONO3L_CLK_SEL_SFT 12 +#define RT5677_DA_MONO3R_CLK_SEL_MASK (0xf << 8) +#define RT5677_DA_MONO3R_CLK_SEL_SFT 8 +#define RT5677_DA_MONO4L_CLK_SEL_MASK (0xf << 4) +#define RT5677_DA_MONO4L_CLK_SEL_SFT 4 +#define RT5677_DA_MONO4R_CLK_SEL_MASK (0xf << 0) +#define RT5677_DA_MONO4R_CLK_SEL_SFT 0 + +/* ASRC Control 5 (0x87) */ +#define RT5677_AD_STO1_CLK_SEL_MASK (0xf << 12) +#define RT5677_AD_STO1_CLK_SEL_SFT 12 +#define RT5677_AD_STO2_CLK_SEL_MASK (0xf << 8) +#define RT5677_AD_STO2_CLK_SEL_SFT 8 +#define RT5677_AD_STO3_CLK_SEL_MASK (0xf << 4) +#define RT5677_AD_STO3_CLK_SEL_SFT 4 +#define RT5677_AD_STO4_CLK_SEL_MASK (0xf << 0) +#define RT5677_AD_STO4_CLK_SEL_SFT 0 + +/* ASRC Control 6 (0x88) */ +#define RT5677_AD_MONOL_CLK_SEL_MASK (0xf << 12) +#define RT5677_AD_MONOL_CLK_SEL_SFT 12 +#define RT5677_AD_MONOR_CLK_SEL_MASK (0xf << 8) +#define RT5677_AD_MONOR_CLK_SEL_SFT 8 + +/* ASRC Control 7 (0x89) */ +#define RT5677_DSP_OB_0_3_CLK_SEL_MASK (0xf << 12) +#define RT5677_DSP_OB_0_3_CLK_SEL_SFT 12 +#define RT5677_DSP_OB_4_7_CLK_SEL_MASK (0xf << 8) +#define RT5677_DSP_OB_4_7_CLK_SEL_SFT 8 + /* VAD Function Control 4 (0x9f) */ #define RT5677_VAD_SRC_MASK (0x7 << 8) #define RT5677_VAD_SRC_SFT 8 @@ -1670,6 +1710,42 @@ enum rt5677_type { RT5676, }; +/* ASRC clock source selection */ +enum { + RT5677_CLK_SEL_SYS, + RT5677_CLK_SEL_I2S1_ASRC, + RT5677_CLK_SEL_I2S2_ASRC, + RT5677_CLK_SEL_I2S3_ASRC, + RT5677_CLK_SEL_I2S4_ASRC, + RT5677_CLK_SEL_I2S5_ASRC, + RT5677_CLK_SEL_I2S6_ASRC, + RT5677_CLK_SEL_SYS2, + RT5677_CLK_SEL_SYS3, + RT5677_CLK_SEL_SYS4, + RT5677_CLK_SEL_SYS5, + RT5677_CLK_SEL_SYS6, + RT5677_CLK_SEL_SYS7, +}; + +/* filter mask */ +enum { + RT5677_DA_STEREO_FILTER = 0x1, + RT5677_DA_MONO2_L_FILTER = (0x1 << 1), + RT5677_DA_MONO2_R_FILTER = (0x1 << 2), + RT5677_DA_MONO3_L_FILTER = (0x1 << 3), + RT5677_DA_MONO3_R_FILTER = (0x1 << 4), + RT5677_DA_MONO4_L_FILTER = (0x1 << 5), + RT5677_DA_MONO4_R_FILTER = (0x1 << 6), + RT5677_AD_STEREO1_FILTER = (0x1 << 7), + RT5677_AD_STEREO2_FILTER = (0x1 << 8), + RT5677_AD_STEREO3_FILTER = (0x1 << 9), + RT5677_AD_STEREO4_FILTER = (0x1 << 10), + RT5677_AD_MONO_L_FILTER = (0x1 << 11), + RT5677_AD_MONO_R_FILTER = (0x1 << 12), + RT5677_DSP_OB_0_3_FILTER = (0x1 << 13), + RT5677_DSP_OB_4_7_FILTER = (0x1 << 14), +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1696,4 +1772,7 @@ struct rt5677_priv { bool is_vref_slow; }; +int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + #endif /* __RT5677_H__ */ -- GitLab From 4644e5ab06dda96f7080569992202e1aec8d3b07 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Feb 2015 21:38:58 +0100 Subject: [PATCH 0380/1910] xen: pcpu: Use static attribute groups for sysfs entry Instead of manual calls of device_create_file() and device_remove_file(), assign the static attribute groups to the device to register. The conditional build of sysfs is done in is_visible callback instead. Signed-off-by: Takashi Iwai Signed-off-by: David Vrabel --- drivers/xen/pcpu.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 0aac403d53fd..49e88f2ce7a1 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c @@ -132,6 +132,33 @@ static ssize_t __ref store_online(struct device *dev, } static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); +static struct attribute *pcpu_dev_attrs[] = { + &dev_attr_online.attr, + NULL +}; + +static umode_t pcpu_dev_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + /* + * Xen never offline cpu0 due to several restrictions + * and assumptions. This basically doesn't add a sys control + * to user, one cannot attempt to offline BSP. + */ + return dev->id ? attr->mode : 0; +} + +static const struct attribute_group pcpu_dev_group = { + .attrs = pcpu_dev_attrs, + .is_visible = pcpu_dev_is_visible, +}; + +static const struct attribute_group *pcpu_dev_groups[] = { + &pcpu_dev_group, + NULL +}; + static bool xen_pcpu_online(uint32_t flags) { return !!(flags & XEN_PCPU_FLAGS_ONLINE); @@ -181,9 +208,6 @@ static void unregister_and_remove_pcpu(struct pcpu *pcpu) return; dev = &pcpu->dev; - if (dev->id) - device_remove_file(dev, &dev_attr_online); - /* pcpu remove would be implicitly done */ device_unregister(dev); } @@ -200,6 +224,7 @@ static int register_pcpu(struct pcpu *pcpu) dev->bus = &xen_pcpu_subsys; dev->id = pcpu->cpu_id; dev->release = pcpu_release; + dev->groups = pcpu_dev_groups; err = device_register(dev); if (err) { @@ -207,19 +232,6 @@ static int register_pcpu(struct pcpu *pcpu) return err; } - /* - * Xen never offline cpu0 due to several restrictions - * and assumptions. This basically doesn't add a sys control - * to user, one cannot attempt to offline BSP. - */ - if (dev->id) { - err = device_create_file(dev, &dev_attr_online); - if (err) { - device_unregister(dev); - return err; - } - } - return 0; } -- GitLab From b6a473a7e1d4f81fc3e355c95982820bb8eae97d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Feb 2015 21:38:59 +0100 Subject: [PATCH 0381/1910] xen: balloon: Use static attribute groups for sysfs entries Instead of manual calls of device_create_file(), device_remove_file() and sysfs_create_group(), assign static attribute groups to the device to register. This simplifies the code and avoids possible races. Signed-off-by: Takashi Iwai Signed-off-by: David Vrabel --- drivers/xen/xen-balloon.c | 45 +++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index e555845d61fa..39e7ef8d3957 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -193,13 +193,18 @@ static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, show_target, store_target); -static struct device_attribute *balloon_attrs[] = { - &dev_attr_target_kb, - &dev_attr_target, - &dev_attr_schedule_delay.attr, - &dev_attr_max_schedule_delay.attr, - &dev_attr_retry_count.attr, - &dev_attr_max_retry_count.attr +static struct attribute *balloon_attrs[] = { + &dev_attr_target_kb.attr, + &dev_attr_target.attr, + &dev_attr_schedule_delay.attr.attr, + &dev_attr_max_schedule_delay.attr.attr, + &dev_attr_retry_count.attr.attr, + &dev_attr_max_retry_count.attr.attr, + NULL +}; + +static const struct attribute_group balloon_group = { + .attrs = balloon_attrs }; static struct attribute *balloon_info_attrs[] = { @@ -214,6 +219,12 @@ static const struct attribute_group balloon_info_group = { .attrs = balloon_info_attrs }; +static const struct attribute_group *balloon_groups[] = { + &balloon_group, + &balloon_info_group, + NULL +}; + static struct bus_type balloon_subsys = { .name = BALLOON_CLASS_NAME, .dev_name = BALLOON_CLASS_NAME, @@ -221,7 +232,7 @@ static struct bus_type balloon_subsys = { static int register_balloon(struct device *dev) { - int i, error; + int error; error = subsys_system_register(&balloon_subsys, NULL); if (error) @@ -229,6 +240,7 @@ static int register_balloon(struct device *dev) dev->id = 0; dev->bus = &balloon_subsys; + dev->groups = balloon_groups; error = device_register(dev); if (error) { @@ -236,24 +248,7 @@ static int register_balloon(struct device *dev) return error; } - for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { - error = device_create_file(dev, balloon_attrs[i]); - if (error) - goto fail; - } - - error = sysfs_create_group(&dev->kobj, &balloon_info_group); - if (error) - goto fail; - return 0; - - fail: - while (--i >= 0) - device_remove_file(dev, balloon_attrs[i]); - device_unregister(dev); - bus_unregister(&balloon_subsys); - return error; } MODULE_LICENSE("GPL"); -- GitLab From 9b4ade226f7468bb26f98b6cd01cb5b8a05fc96d Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 21 Jan 2015 08:49:22 +0100 Subject: [PATCH 0382/1910] xen: build infrastructure for generating hypercall depending symbols Today there are several places in the kernel which build tables containing one entry for each possible Xen hypercall. Create an infrastructure to be able to generate these tables at build time. Based-on-patch-by: Jan Beulich Signed-off-by: Juergen Gross Reviewed-by: David Vrabel Acked-by: Ingo Molnar Signed-off-by: David Vrabel --- arch/x86/syscalls/Makefile | 9 +++++++++ scripts/xen-hypercalls.sh | 12 ++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 scripts/xen-hypercalls.sh diff --git a/arch/x86/syscalls/Makefile b/arch/x86/syscalls/Makefile index 3323c2745248..a55abb9f6c5e 100644 --- a/arch/x86/syscalls/Makefile +++ b/arch/x86/syscalls/Makefile @@ -19,6 +19,9 @@ quiet_cmd_syshdr = SYSHDR $@ quiet_cmd_systbl = SYSTBL $@ cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@ +quiet_cmd_hypercalls = HYPERCALLS $@ + cmd_hypercalls = $(CONFIG_SHELL) '$<' $@ $(filter-out $<,$^) + syshdr_abi_unistd_32 := i386 $(uapi)/unistd_32.h: $(syscall32) $(syshdr) $(call if_changed,syshdr) @@ -47,10 +50,16 @@ $(out)/syscalls_32.h: $(syscall32) $(systbl) $(out)/syscalls_64.h: $(syscall64) $(systbl) $(call if_changed,systbl) +$(out)/xen-hypercalls.h: $(srctree)/scripts/xen-hypercalls.sh + $(call if_changed,hypercalls) + +$(out)/xen-hypercalls.h: $(srctree)/include/xen/interface/xen*.h + uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h syshdr-y += syscalls_32.h syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h syshdr-$(CONFIG_X86_64) += syscalls_64.h +syshdr-$(CONFIG_XEN) += xen-hypercalls.h targets += $(uapisyshdr-y) $(syshdr-y) diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh new file mode 100644 index 000000000000..676d9226814f --- /dev/null +++ b/scripts/xen-hypercalls.sh @@ -0,0 +1,12 @@ +#!/bin/sh +out="$1" +shift +in="$@" + +for i in $in; do + eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null +done | \ +awk '$1 == "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 } + END { print "/* auto-generated by scripts/xen-hypercall.sh */" + for (i in v) if (!(v[i] in v)) + print "HYPERCALL("substr(v[i], 14)")"}' | sort -u >$out -- GitLab From 16b12d605795e775cd80b5901c85dd2e320a6ec2 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 21 Jan 2015 08:49:23 +0100 Subject: [PATCH 0383/1910] xen: synchronize include/xen/interface/xen.h with xen The header include/xen/interface/xen.h doesn't contain all definitions from Xen's version of that header. Update it accordingly. Signed-off-by: Juergen Gross Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- arch/x86/xen/trace.c | 2 +- include/xen/interface/xen.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/xen/trace.c b/arch/x86/xen/trace.c index 520022d1a181..8296cdf4e581 100644 --- a/arch/x86/xen/trace.c +++ b/arch/x86/xen/trace.c @@ -29,7 +29,7 @@ static const char *xen_hypercall_names[] = { N(vcpu_op), N(set_segment_base), N(mmuext_op), - N(acm_op), + N(xsm_op), N(nmi_op), N(sched_op), N(callback_op), diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index f68719f405af..a48378958062 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h @@ -67,7 +67,7 @@ #define __HYPERVISOR_vcpu_op 24 #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ #define __HYPERVISOR_mmuext_op 26 -#define __HYPERVISOR_acm_op 27 +#define __HYPERVISOR_xsm_op 27 #define __HYPERVISOR_nmi_op 28 #define __HYPERVISOR_sched_op 29 #define __HYPERVISOR_callback_op 30 @@ -75,7 +75,11 @@ #define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_physdev_op 33 #define __HYPERVISOR_hvm_op 34 +#define __HYPERVISOR_sysctl 35 +#define __HYPERVISOR_domctl 36 +#define __HYPERVISOR_kexec_op 37 #define __HYPERVISOR_tmem_op 38 +#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 -- GitLab From fc903f87364d1b00890fa991a6f116e2bb38ec1e Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 21 Jan 2015 08:49:24 +0100 Subject: [PATCH 0384/1910] xen: use generated hypervisor symbols in arch/x86/xen/trace.c Instead of manually list all hypervisor calls in arch/x86/xen/trace.c use the auto generated list. Signed-off-by: Juergen Gross Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- arch/x86/xen/trace.c | 50 ++++---------------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/arch/x86/xen/trace.c b/arch/x86/xen/trace.c index 8296cdf4e581..a702ec2f5931 100644 --- a/arch/x86/xen/trace.c +++ b/arch/x86/xen/trace.c @@ -1,54 +1,12 @@ #include #include +#include -#define N(x) [__HYPERVISOR_##x] = "("#x")" +#define HYPERCALL(x) [__HYPERVISOR_##x] = "("#x")", static const char *xen_hypercall_names[] = { - N(set_trap_table), - N(mmu_update), - N(set_gdt), - N(stack_switch), - N(set_callbacks), - N(fpu_taskswitch), - N(sched_op_compat), - N(dom0_op), - N(set_debugreg), - N(get_debugreg), - N(update_descriptor), - N(memory_op), - N(multicall), - N(update_va_mapping), - N(set_timer_op), - N(event_channel_op_compat), - N(xen_version), - N(console_io), - N(physdev_op_compat), - N(grant_table_op), - N(vm_assist), - N(update_va_mapping_otherdomain), - N(iret), - N(vcpu_op), - N(set_segment_base), - N(mmuext_op), - N(xsm_op), - N(nmi_op), - N(sched_op), - N(callback_op), - N(xenoprof_op), - N(event_channel_op), - N(physdev_op), - N(hvm_op), - -/* Architecture-specific hypercall definitions. */ - N(arch_0), - N(arch_1), - N(arch_2), - N(arch_3), - N(arch_4), - N(arch_5), - N(arch_6), - N(arch_7), +#include }; -#undef N +#undef HYPERCALL static const char *xen_hypercall_name(unsigned op) { -- GitLab From 526abeaed4971def462f209632b88fd7b8c4a09c Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 21 Jan 2015 08:49:25 +0100 Subject: [PATCH 0385/1910] xen: use generated hypercall symbols in arch/x86/xen/xen-head.S Instead of manually list each hypercall in arch/x86/xen/xen-head.S use the auto generated symbol list. This also corrects the wrong address of xen_hypercall_mca which was located 32 bytes higher than it should. Symbol addresses have been verified to match the correct ones via objdump output. Based-on-patch-by: Jan Beulich Signed-off-by: Juergen Gross Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- arch/x86/xen/xen-head.S | 63 +++++++---------------------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index 674b222544b7..8afdfccf6086 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -12,6 +12,8 @@ #include #include +#include +#include #include #ifdef CONFIG_XEN_PVH @@ -85,59 +87,14 @@ ENTRY(xen_pvh_early_cpu_init) .pushsection .text .balign PAGE_SIZE ENTRY(hypercall_page) -#define NEXT_HYPERCALL(x) \ - ENTRY(xen_hypercall_##x) \ - .skip 32 - -NEXT_HYPERCALL(set_trap_table) -NEXT_HYPERCALL(mmu_update) -NEXT_HYPERCALL(set_gdt) -NEXT_HYPERCALL(stack_switch) -NEXT_HYPERCALL(set_callbacks) -NEXT_HYPERCALL(fpu_taskswitch) -NEXT_HYPERCALL(sched_op_compat) -NEXT_HYPERCALL(platform_op) -NEXT_HYPERCALL(set_debugreg) -NEXT_HYPERCALL(get_debugreg) -NEXT_HYPERCALL(update_descriptor) -NEXT_HYPERCALL(ni) -NEXT_HYPERCALL(memory_op) -NEXT_HYPERCALL(multicall) -NEXT_HYPERCALL(update_va_mapping) -NEXT_HYPERCALL(set_timer_op) -NEXT_HYPERCALL(event_channel_op_compat) -NEXT_HYPERCALL(xen_version) -NEXT_HYPERCALL(console_io) -NEXT_HYPERCALL(physdev_op_compat) -NEXT_HYPERCALL(grant_table_op) -NEXT_HYPERCALL(vm_assist) -NEXT_HYPERCALL(update_va_mapping_otherdomain) -NEXT_HYPERCALL(iret) -NEXT_HYPERCALL(vcpu_op) -NEXT_HYPERCALL(set_segment_base) -NEXT_HYPERCALL(mmuext_op) -NEXT_HYPERCALL(xsm_op) -NEXT_HYPERCALL(nmi_op) -NEXT_HYPERCALL(sched_op) -NEXT_HYPERCALL(callback_op) -NEXT_HYPERCALL(xenoprof_op) -NEXT_HYPERCALL(event_channel_op) -NEXT_HYPERCALL(physdev_op) -NEXT_HYPERCALL(hvm_op) -NEXT_HYPERCALL(sysctl) -NEXT_HYPERCALL(domctl) -NEXT_HYPERCALL(kexec_op) -NEXT_HYPERCALL(tmem_op) /* 38 */ -ENTRY(xen_hypercall_rsvr) - .skip 320 -NEXT_HYPERCALL(mca) /* 48 */ -NEXT_HYPERCALL(arch_1) -NEXT_HYPERCALL(arch_2) -NEXT_HYPERCALL(arch_3) -NEXT_HYPERCALL(arch_4) -NEXT_HYPERCALL(arch_5) -NEXT_HYPERCALL(arch_6) - .balign PAGE_SIZE + .skip PAGE_SIZE + +#define HYPERCALL(n) \ + .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \ + .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32 +#include +#undef HYPERCALL + .popsection ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") -- GitLab From 74beaf6270f5b08159f1df8208322a24bb2905e6 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 27 Feb 2015 16:11:06 -0500 Subject: [PATCH 0386/1910] xen/pciback: Don't print scary messages when unsupported by hypervisor. We print at the warninig level messages such as: pciback 0000:90:00.5: MSI-X preparation failed (-38) which is due to the hypervisor not supporting this sub-hypercall (which was added in Xen 4.3). Instead of having scary messages all the time - only have it when the hypercall is actually supported. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- drivers/xen/xen-pciback/pci_stub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index cc3cbb4435f8..258b7c325649 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -118,7 +118,7 @@ static void pcistub_device_release(struct kref *kref) int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, &ppdev); - if (err) + if (err && err != -ENOSYS) dev_warn(&dev->dev, "MSI-X release failed (%d)\n", err); } @@ -402,7 +402,7 @@ static int pcistub_init_device(struct pci_dev *dev) }; err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); - if (err) + if (err && err != -ENOSYS) dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", err); } -- GitLab From feb44f1f7a4ac299d1ab1c3606860e70b9b89d69 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 2 Mar 2015 12:06:23 -0500 Subject: [PATCH 0387/1910] x86/xen: Provide a "Xen PV" APIC driver to support >255 VCPUs Instead of mangling the default APIC driver, provide a Xen PV guest specific one that explicitly provides appropriate methods. This allows use to report that all APIC IDs are valid, allowing dom0 to boot with more than 255 VCPUs. Since the probe order of APIC drivers is link dependent, we add in an late probe function to change to the Xen PV if it hadn't been done during bootup. Suggested-by: David Vrabel Reported-by: Cathy Avery Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- arch/x86/xen/apic.c | 180 +++++++++++++++++++++++++++++++++++++++ arch/x86/xen/enlighten.c | 90 +------------------- 2 files changed, 181 insertions(+), 89 deletions(-) diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c index 7005ced5d1ad..5e0ecaf4c336 100644 --- a/arch/x86/xen/apic.c +++ b/arch/x86/xen/apic.c @@ -7,6 +7,7 @@ #include #include #include "xen-ops.h" +#include "smp.h" static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) { @@ -28,7 +29,186 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) return 0xfd; } +static unsigned long xen_set_apic_id(unsigned int x) +{ + WARN_ON(1); + return x; +} + +static unsigned int xen_get_apic_id(unsigned long x) +{ + return ((x)>>24) & 0xFFu; +} + +static u32 xen_apic_read(u32 reg) +{ + struct xen_platform_op op = { + .cmd = XENPF_get_cpuinfo, + .interface_version = XENPF_INTERFACE_VERSION, + .u.pcpu_info.xen_cpuid = 0, + }; + int ret = 0; + + /* Shouldn't need this as APIC is turned off for PV, and we only + * get called on the bootup processor. But just in case. */ + if (!xen_initial_domain() || smp_processor_id()) + return 0; + + if (reg == APIC_LVR) + return 0x10; +#ifdef CONFIG_X86_32 + if (reg == APIC_LDR) + return SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); +#endif + if (reg != APIC_ID) + return 0; + + ret = HYPERVISOR_dom0_op(&op); + if (ret) + return 0; + + return op.u.pcpu_info.apic_id << 24; +} + +static void xen_apic_write(u32 reg, u32 val) +{ + /* Warn to see if there's any stray references */ + WARN_ON(1); +} + +static u64 xen_apic_icr_read(void) +{ + return 0; +} + +static void xen_apic_icr_write(u32 low, u32 id) +{ + /* Warn to see if there's any stray references */ + WARN_ON(1); +} + +static u32 xen_safe_apic_wait_icr_idle(void) +{ + return 0; +} + +static int xen_apic_probe_pv(void) +{ + if (xen_pv_domain()) + return 1; + + return 0; +} + +static int xen_madt_oem_check(char *oem_id, char *oem_table_id) +{ + return xen_pv_domain(); +} + +static int xen_id_always_valid(int apicid) +{ + return 1; +} + +static int xen_id_always_registered(void) +{ + return 1; +} + +static int xen_phys_pkg_id(int initial_apic_id, int index_msb) +{ + return initial_apic_id >> index_msb; +} + +#ifdef CONFIG_X86_32 +static int xen_x86_32_early_logical_apicid(int cpu) +{ + /* Match with APIC_LDR read. Otherwise setup_local_APIC complains. */ + return 1 << cpu; +} +#endif + +static void xen_noop(void) +{ +} + +static void xen_silent_inquire(int apicid) +{ +} + +static struct apic xen_pv_apic = { + .name = "Xen PV", + .probe = xen_apic_probe_pv, + .acpi_madt_oem_check = xen_madt_oem_check, + .apic_id_valid = xen_id_always_valid, + .apic_id_registered = xen_id_always_registered, + + /* .irq_delivery_mode - used in native_compose_msi_msg only */ + /* .irq_dest_mode - used in native_compose_msi_msg only */ + + .target_cpus = default_target_cpus, + .disable_esr = 0, + /* .dest_logical - default_send_IPI_ use it but we use our own. */ + .check_apicid_used = default_check_apicid_used, /* Used on 32-bit */ + + .vector_allocation_domain = flat_vector_allocation_domain, + .init_apic_ldr = xen_noop, /* setup_local_APIC calls it */ + + .ioapic_phys_id_map = default_ioapic_phys_id_map, /* Used on 32-bit */ + .setup_apic_routing = NULL, + .cpu_present_to_apicid = default_cpu_present_to_apicid, + .apicid_to_cpu_present = physid_set_mask_of_physid, /* Used on 32-bit */ + .check_phys_apicid_present = default_check_phys_apicid_present, /* smp_sanity_check needs it */ + .phys_pkg_id = xen_phys_pkg_id, /* detect_ht */ + + .get_apic_id = xen_get_apic_id, + .set_apic_id = xen_set_apic_id, /* Can be NULL on 32-bit. */ + .apic_id_mask = 0xFF << 24, /* Used by verify_local_APIC. Match with what xen_get_apic_id does. */ + + .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, + +#ifdef CONFIG_SMP + .send_IPI_mask = xen_send_IPI_mask, + .send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself, + .send_IPI_allbutself = xen_send_IPI_allbutself, + .send_IPI_all = xen_send_IPI_all, + .send_IPI_self = xen_send_IPI_self, +#endif + /* .wait_for_init_deassert- used by AP bootup - smp_callin which we don't use */ + .inquire_remote_apic = xen_silent_inquire, + + .read = xen_apic_read, + .write = xen_apic_write, + .eoi_write = xen_apic_write, + + .icr_read = xen_apic_icr_read, + .icr_write = xen_apic_icr_write, + .wait_icr_idle = xen_noop, + .safe_wait_icr_idle = xen_safe_apic_wait_icr_idle, + +#ifdef CONFIG_X86_32 + /* generic_processor_info and setup_local_APIC. */ + .x86_32_early_logical_apicid = xen_x86_32_early_logical_apicid, +#endif +}; + +static void __init xen_apic_check(void) +{ + if (apic == &xen_pv_apic) + return; + + pr_info("Switched APIC routing from %s to %s.\n", apic->name, + xen_pv_apic.name); + apic = &xen_pv_apic; +} void __init xen_init_apic(void) { x86_io_apic_ops.read = xen_io_apic_read; + /* On PV guests the APIC CPUID bit is disabled so none of the + * routines end up executing. */ + if (!xen_initial_domain()) + apic = &xen_pv_apic; + + x86_platform.apic_post_init = xen_apic_check; } +apic_driver(xen_pv_apic); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 5240f563076d..b9a227284149 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -927,92 +927,6 @@ static void xen_io_delay(void) { } -#ifdef CONFIG_X86_LOCAL_APIC -static unsigned long xen_set_apic_id(unsigned int x) -{ - WARN_ON(1); - return x; -} -static unsigned int xen_get_apic_id(unsigned long x) -{ - return ((x)>>24) & 0xFFu; -} -static u32 xen_apic_read(u32 reg) -{ - struct xen_platform_op op = { - .cmd = XENPF_get_cpuinfo, - .interface_version = XENPF_INTERFACE_VERSION, - .u.pcpu_info.xen_cpuid = 0, - }; - int ret = 0; - - /* Shouldn't need this as APIC is turned off for PV, and we only - * get called on the bootup processor. But just in case. */ - if (!xen_initial_domain() || smp_processor_id()) - return 0; - - if (reg == APIC_LVR) - return 0x10; - - if (reg != APIC_ID) - return 0; - - ret = HYPERVISOR_dom0_op(&op); - if (ret) - return 0; - - return op.u.pcpu_info.apic_id << 24; -} - -static void xen_apic_write(u32 reg, u32 val) -{ - /* Warn to see if there's any stray references */ - WARN_ON(1); -} - -static u64 xen_apic_icr_read(void) -{ - return 0; -} - -static void xen_apic_icr_write(u32 low, u32 id) -{ - /* Warn to see if there's any stray references */ - WARN_ON(1); -} - -static void xen_apic_wait_icr_idle(void) -{ - return; -} - -static u32 xen_safe_apic_wait_icr_idle(void) -{ - return 0; -} - -static void set_xen_basic_apic_ops(void) -{ - apic->read = xen_apic_read; - apic->write = xen_apic_write; - apic->icr_read = xen_apic_icr_read; - apic->icr_write = xen_apic_icr_write; - apic->wait_icr_idle = xen_apic_wait_icr_idle; - apic->safe_wait_icr_idle = xen_safe_apic_wait_icr_idle; - apic->set_apic_id = xen_set_apic_id; - apic->get_apic_id = xen_get_apic_id; - -#ifdef CONFIG_SMP - apic->send_IPI_allbutself = xen_send_IPI_allbutself; - apic->send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself; - apic->send_IPI_mask = xen_send_IPI_mask; - apic->send_IPI_all = xen_send_IPI_all; - apic->send_IPI_self = xen_send_IPI_self; -#endif -} - -#endif - static void xen_clts(void) { struct multicall_space mcs; @@ -1618,7 +1532,7 @@ asmlinkage __visible void __init xen_start_kernel(void) /* * set up the basic apic ops. */ - set_xen_basic_apic_ops(); + xen_init_apic(); #endif if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { @@ -1731,8 +1645,6 @@ asmlinkage __visible void __init xen_start_kernel(void) if (HYPERVISOR_dom0_op(&op) == 0) boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags; - xen_init_apic(); - /* Make sure ACS will be enabled */ pci_request_acs(); -- GitLab From b3b06c7eb7820cea5c15f9faa4964044284c5399 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 3 Mar 2015 16:12:12 -0500 Subject: [PATCH 0388/1910] x86/xen/apic: WARN with details. We should not be writting to the APIC registers under Xen PV. But if we do instead of just giving an blanket warning - include some details to help troubleshoot. Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/xen/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c index 5e0ecaf4c336..70e060ad879a 100644 --- a/arch/x86/xen/apic.c +++ b/arch/x86/xen/apic.c @@ -73,7 +73,7 @@ static u32 xen_apic_read(u32 reg) static void xen_apic_write(u32 reg, u32 val) { /* Warn to see if there's any stray references */ - WARN_ON(1); + WARN(1,"register: %x, value: %x\n", reg, val); } static u64 xen_apic_icr_read(void) -- GitLab From 628c28eefd6f2cef03b212081b466ae43fd093a3 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 11 Mar 2015 14:49:56 +0000 Subject: [PATCH 0389/1910] xen: unify foreign GFN map/unmap for auto-xlated physmap guests Auto-translated physmap guests (arm, arm64 and x86 PVHVM/PVH) map and unmap foreign GFNs using the same method (updating the physmap). Unify the two arm and x86 implementations into one commont one. Note that on arm and arm64, the correct error code will be returned (instead of always -EFAULT) and map/unmap failure warnings are no longer printed. These changes are required if the foreign domain is paging (-ENOENT failures are expected and must be propagated up to the caller). Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini --- arch/arm/xen/enlighten.c | 90 +------------------------- arch/x86/xen/mmu.c | 110 +------------------------------- drivers/xen/Kconfig | 6 ++ drivers/xen/Makefile | 1 + drivers/xen/xlate_mmu.c | 133 +++++++++++++++++++++++++++++++++++++++ include/xen/xen-ops.h | 8 +++ 6 files changed, 154 insertions(+), 194 deletions(-) create mode 100644 drivers/xen/xlate_mmu.c diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 263a2044c65b..5c04389fc9ef 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -53,105 +53,21 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); static __read_mostly int xen_events_irq = -1; -/* map fgmfn of domid to lpfn in the current domain */ -static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, - unsigned int domid) -{ - int rc; - struct xen_add_to_physmap_range xatp = { - .domid = DOMID_SELF, - .foreign_domid = domid, - .size = 1, - .space = XENMAPSPACE_gmfn_foreign, - }; - xen_ulong_t idx = fgmfn; - xen_pfn_t gpfn = lpfn; - int err = 0; - - set_xen_guest_handle(xatp.idxs, &idx); - set_xen_guest_handle(xatp.gpfns, &gpfn); - set_xen_guest_handle(xatp.errs, &err); - - rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); - if (rc || err) { - pr_warn("Failed to map pfn to mfn rc:%d:%d pfn:%lx mfn:%lx\n", - rc, err, lpfn, fgmfn); - return 1; - } - return 0; -} - -struct remap_data { - xen_pfn_t fgmfn; /* foreign domain's gmfn */ - pgprot_t prot; - domid_t domid; - struct vm_area_struct *vma; - int index; - struct page **pages; - struct xen_remap_mfn_info *info; -}; - -static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, - void *data) -{ - struct remap_data *info = data; - struct page *page = info->pages[info->index++]; - unsigned long pfn = page_to_pfn(page); - pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); - - if (map_foreign_page(pfn, info->fgmfn, info->domid)) - return -EFAULT; - set_pte_at(info->vma->vm_mm, addr, ptep, pte); - - return 0; -} - int xen_remap_domain_mfn_range(struct vm_area_struct *vma, unsigned long addr, xen_pfn_t mfn, int nr, pgprot_t prot, unsigned domid, struct page **pages) { - int err; - struct remap_data data; - - /* TBD: Batching, current sole caller only does page at a time */ - if (nr > 1) - return -EINVAL; - - data.fgmfn = mfn; - data.prot = prot; - data.domid = domid; - data.vma = vma; - data.index = 0; - data.pages = pages; - err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, - remap_pte_fn, &data); - return err; + return xen_xlate_remap_gfn_range(vma, addr, mfn, nr, + prot, domid, pages); } EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int nr, struct page **pages) { - int i; - - for (i = 0; i < nr; i++) { - struct xen_remove_from_physmap xrp; - unsigned long rc, pfn; - - pfn = page_to_pfn(pages[i]); - - xrp.domid = DOMID_SELF; - xrp.gpfn = pfn; - rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); - if (rc) { - pr_warn("Failed to unmap pfn:%lx rc:%ld\n", - pfn, rc); - return rc; - } - } - return 0; + return xen_xlate_unmap_gfn_range(vma, nr, pages); } EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index adca9e2b6553..3d536a56ddf1 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2436,95 +2436,6 @@ void __init xen_hvm_init_mmu_ops(void) } #endif -#ifdef CONFIG_XEN_PVH -/* - * Map foreign gfn (fgfn), to local pfn (lpfn). This for the user - * space creating new guest on pvh dom0 and needing to map domU pages. - */ -static int xlate_add_to_p2m(unsigned long lpfn, unsigned long fgfn, - unsigned int domid) -{ - int rc, err = 0; - xen_pfn_t gpfn = lpfn; - xen_ulong_t idx = fgfn; - - struct xen_add_to_physmap_range xatp = { - .domid = DOMID_SELF, - .foreign_domid = domid, - .size = 1, - .space = XENMAPSPACE_gmfn_foreign, - }; - set_xen_guest_handle(xatp.idxs, &idx); - set_xen_guest_handle(xatp.gpfns, &gpfn); - set_xen_guest_handle(xatp.errs, &err); - - rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); - if (rc < 0) - return rc; - return err; -} - -static int xlate_remove_from_p2m(unsigned long spfn, int count) -{ - struct xen_remove_from_physmap xrp; - int i, rc; - - for (i = 0; i < count; i++) { - xrp.domid = DOMID_SELF; - xrp.gpfn = spfn+i; - rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); - if (rc) - break; - } - return rc; -} - -struct xlate_remap_data { - unsigned long fgfn; /* foreign domain's gfn */ - pgprot_t prot; - domid_t domid; - int index; - struct page **pages; -}; - -static int xlate_map_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, - void *data) -{ - int rc; - struct xlate_remap_data *remap = data; - unsigned long pfn = page_to_pfn(remap->pages[remap->index++]); - pte_t pteval = pte_mkspecial(pfn_pte(pfn, remap->prot)); - - rc = xlate_add_to_p2m(pfn, remap->fgfn, remap->domid); - if (rc) - return rc; - native_set_pte(ptep, pteval); - - return 0; -} - -static int xlate_remap_gfn_range(struct vm_area_struct *vma, - unsigned long addr, unsigned long mfn, - int nr, pgprot_t prot, unsigned domid, - struct page **pages) -{ - int err; - struct xlate_remap_data pvhdata; - - BUG_ON(!pages); - - pvhdata.fgfn = mfn; - pvhdata.prot = prot; - pvhdata.domid = domid; - pvhdata.index = 0; - pvhdata.pages = pages; - err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, - xlate_map_pte_fn, &pvhdata); - flush_tlb_all(); - return err; -} -#endif - #define REMAP_BATCH_SIZE 16 struct remap_data { @@ -2564,8 +2475,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, if (xen_feature(XENFEAT_auto_translated_physmap)) { #ifdef CONFIG_XEN_PVH /* We need to update the local page tables and the xen HAP */ - return xlate_remap_gfn_range(vma, addr, mfn, nr, prot, - domid, pages); + return xen_xlate_remap_gfn_range(vma, addr, mfn, nr, prot, + domid, pages); #else return -EINVAL; #endif @@ -2609,22 +2520,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, return 0; #ifdef CONFIG_XEN_PVH - while (numpgs--) { - /* - * The mmu has already cleaned up the process mmu - * resources at this point (lookup_address will return - * NULL). - */ - unsigned long pfn = page_to_pfn(pages[numpgs]); - - xlate_remove_from_p2m(pfn, 1); - } - /* - * We don't need to flush tlbs because as part of - * xlate_remove_from_p2m, the hypervisor will do tlb flushes - * after removing the p2m entries from the EPT/NPT - */ - return 0; + return xen_xlate_unmap_gfn_range(vma, numpgs, pages); #else return -EINVAL; #endif diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index b812462083fc..afc39ca5cc4f 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -253,4 +253,10 @@ config XEN_EFI def_bool y depends on X86_64 && EFI +config XEN_AUTO_XLATE + def_bool y + depends on ARM || ARM64 || XEN_PVHVM + help + Support for auto-translated physmap guests. + endmenu diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 2ccd3592d41f..40edd1cbb60d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o obj-$(CONFIG_XEN_EFI) += efi.o obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o +obj-$(CONFIG_XEN_AUTO_XLATE) += xlate_mmu.o xen-evtchn-y := evtchn.o xen-gntdev-y := gntdev.o xen-gntalloc-y := gntalloc.o diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c new file mode 100644 index 000000000000..7724d90fc697 --- /dev/null +++ b/drivers/xen/xlate_mmu.c @@ -0,0 +1,133 @@ +/* + * MMU operations common to all auto-translated physmap guests. + * + * Copyright (C) 2015 Citrix Systems R&D Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* map fgmfn of domid to lpfn in the current domain */ +static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, + unsigned int domid) +{ + int rc; + struct xen_add_to_physmap_range xatp = { + .domid = DOMID_SELF, + .foreign_domid = domid, + .size = 1, + .space = XENMAPSPACE_gmfn_foreign, + }; + xen_ulong_t idx = fgmfn; + xen_pfn_t gpfn = lpfn; + int err = 0; + + set_xen_guest_handle(xatp.idxs, &idx); + set_xen_guest_handle(xatp.gpfns, &gpfn); + set_xen_guest_handle(xatp.errs, &err); + + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); + return rc < 0 ? rc : err; +} + +struct remap_data { + xen_pfn_t fgmfn; /* foreign domain's gmfn */ + pgprot_t prot; + domid_t domid; + struct vm_area_struct *vma; + int index; + struct page **pages; + struct xen_remap_mfn_info *info; +}; + +static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, + void *data) +{ + struct remap_data *info = data; + struct page *page = info->pages[info->index++]; + unsigned long pfn = page_to_pfn(page); + pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); + int rc; + + rc = map_foreign_page(pfn, info->fgmfn, info->domid); + if (rc < 0) + return rc; + set_pte_at(info->vma->vm_mm, addr, ptep, pte); + + return 0; +} + +int xen_xlate_remap_gfn_range(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t gfn, int nr, + pgprot_t prot, unsigned domid, + struct page **pages) +{ + int err; + struct remap_data data; + + /* TBD: Batching, current sole caller only does page at a time */ + if (nr > 1) + return -EINVAL; + + data.fgmfn = gfn; + data.prot = prot; + data.domid = domid; + data.vma = vma; + data.index = 0; + data.pages = pages; + err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, + remap_pte_fn, &data); + return err; +} +EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_range); + +int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, + int nr, struct page **pages) +{ + int i; + + for (i = 0; i < nr; i++) { + struct xen_remove_from_physmap xrp; + unsigned long pfn; + + pfn = page_to_pfn(pages[i]); + + xrp.domid = DOMID_SELF; + xrp.gpfn = pfn; + (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); + } + return 0; +} +EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range); diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 83338210ee04..9eb88a4512bd 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -34,6 +34,14 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, struct page **pages); int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages); +int xen_xlate_remap_gfn_range(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t gfn, int nr, + pgprot_t prot, + unsigned domid, + struct page **pages); +int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, + int nr, struct page **pages); bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); -- GitLab From 4e8c0c8c4bf3a5b5c98046e146ab3884bf7a7d0e Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 11 Mar 2015 14:49:57 +0000 Subject: [PATCH 0390/1910] xen/privcmd: improve performance of MMAPBATCH_V2 Make the IOCTL_PRIVCMD_MMAPBATCH_V2 (and older V1 version) map multiple frames at a time rather than one at a time, despite the pages being non-consecutive GFNs. xen_remap_foreign_mfn_array() is added which maps an array of GFNs (instead of a consecutive range of GFNs). Since per-frame errors are returned in an array, privcmd must set the MMAPBATCH_V1 error bits as part of the "report errors" phase, after all the frames are mapped. Migrate times are significantly improved (when using a PV toolstack domain). For example, for an idle 12 GiB PV guest: Before After real 0m38.179s 0m26.868s user 0m15.096s 0m13.652s sys 0m28.988s 0m18.732s Signed-off-by: David Vrabel Reviewed-by: Stefano Stabellini --- arch/arm/xen/enlighten.c | 20 +++++-- arch/x86/xen/mmu.c | 101 ++++++++++++++++++++++++++------- drivers/xen/privcmd.c | 117 +++++++++++++++++++++++++++------------ drivers/xen/xlate_mmu.c | 46 +++++++++------ include/xen/xen-ops.h | 45 +++++++++++++-- 5 files changed, 249 insertions(+), 80 deletions(-) diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 5c04389fc9ef..224081ccc92f 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -53,15 +53,27 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); static __read_mostly int xen_events_irq = -1; -int xen_remap_domain_mfn_range(struct vm_area_struct *vma, +int xen_remap_domain_mfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t mfn, int nr, - pgprot_t prot, unsigned domid, + xen_pfn_t *mfn, int nr, + int *err_ptr, pgprot_t prot, + unsigned domid, struct page **pages) { - return xen_xlate_remap_gfn_range(vma, addr, mfn, nr, + return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, prot, domid, pages); } +EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); + +/* Not used by XENFEAT_auto_translated guests. */ +int xen_remap_domain_mfn_range(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t mfn, int nr, + pgprot_t prot, unsigned domid, + struct page **pages) +{ + return -ENOSYS; +} EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 3d536a56ddf1..29b3be230ede 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2439,7 +2439,8 @@ void __init xen_hvm_init_mmu_ops(void) #define REMAP_BATCH_SIZE 16 struct remap_data { - unsigned long mfn; + xen_pfn_t *mfn; + bool contiguous; pgprot_t prot; struct mmu_update *mmu_update; }; @@ -2448,7 +2449,14 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, void *data) { struct remap_data *rmd = data; - pte_t pte = pte_mkspecial(mfn_pte(rmd->mfn++, rmd->prot)); + pte_t pte = pte_mkspecial(mfn_pte(*rmd->mfn, rmd->prot)); + + /* If we have a contigious range, just update the mfn itself, + else update pointer to be "next mfn". */ + if (rmd->contiguous) + (*rmd->mfn)++; + else + rmd->mfn++; rmd->mmu_update->ptr = virt_to_machine(ptep).maddr; rmd->mmu_update->val = pte_val_ma(pte); @@ -2457,26 +2465,26 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, return 0; } -int xen_remap_domain_mfn_range(struct vm_area_struct *vma, - unsigned long addr, - xen_pfn_t mfn, int nr, - pgprot_t prot, unsigned domid, - struct page **pages) - +static int do_remap_mfn(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t *mfn, int nr, + int *err_ptr, pgprot_t prot, + unsigned domid, + struct page **pages) { + int err = 0; struct remap_data rmd; struct mmu_update mmu_update[REMAP_BATCH_SIZE]; - int batch; unsigned long range; - int err = 0; + int mapped = 0; BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); if (xen_feature(XENFEAT_auto_translated_physmap)) { #ifdef CONFIG_XEN_PVH /* We need to update the local page tables and the xen HAP */ - return xen_xlate_remap_gfn_range(vma, addr, mfn, nr, prot, - domid, pages); + return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, + prot, domid, pages); #else return -EINVAL; #endif @@ -2484,9 +2492,15 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, rmd.mfn = mfn; rmd.prot = prot; + /* We use the err_ptr to indicate if there we are doing a contigious + * mapping or a discontigious mapping. */ + rmd.contiguous = !err_ptr; while (nr) { - batch = min(REMAP_BATCH_SIZE, nr); + int index = 0; + int done = 0; + int batch = min(REMAP_BATCH_SIZE, nr); + int batch_left = batch; range = (unsigned long)batch << PAGE_SHIFT; rmd.mmu_update = mmu_update; @@ -2495,23 +2509,72 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, if (err) goto out; - err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid); - if (err < 0) - goto out; + /* We record the error for each page that gives an error, but + * continue mapping until the whole set is done */ + do { + int i; + + err = HYPERVISOR_mmu_update(&mmu_update[index], + batch_left, &done, domid); + + /* + * @err_ptr may be the same buffer as @mfn, so + * only clear it after each chunk of @mfn is + * used. + */ + if (err_ptr) { + for (i = index; i < index + done; i++) + err_ptr[i] = 0; + } + if (err < 0) { + if (!err_ptr) + goto out; + err_ptr[i] = err; + done++; /* Skip failed frame. */ + } else + mapped += done; + batch_left -= done; + index += done; + } while (batch_left); nr -= batch; addr += range; + if (err_ptr) + err_ptr += batch; } - - err = 0; out: xen_flush_tlb_all(); - return err; + return err < 0 ? err : mapped; +} + +int xen_remap_domain_mfn_range(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t mfn, int nr, + pgprot_t prot, unsigned domid, + struct page **pages) +{ + return do_remap_mfn(vma, addr, &mfn, nr, NULL, prot, domid, pages); } EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); +int xen_remap_domain_mfn_array(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t *mfn, int nr, + int *err_ptr, pgprot_t prot, + unsigned domid, struct page **pages) +{ + /* We BUG_ON because it's a programmer error to pass a NULL err_ptr, + * and the consequences later is quite hard to detect what the actual + * cause of "wrong memory was mapped in". + */ + BUG_ON(err_ptr == NULL); + return do_remap_mfn(vma, addr, mfn, nr, err_ptr, prot, domid, pages); +} +EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); + + /* Returns: 0 success */ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 59ac71c4a043..5a296161d843 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -159,6 +159,40 @@ static int traverse_pages(unsigned nelem, size_t size, return ret; } +/* + * Similar to traverse_pages, but use each page as a "block" of + * data to be processed as one unit. + */ +static int traverse_pages_block(unsigned nelem, size_t size, + struct list_head *pos, + int (*fn)(void *data, int nr, void *state), + void *state) +{ + void *pagedata; + unsigned pageidx; + int ret = 0; + + BUG_ON(size > PAGE_SIZE); + + pageidx = PAGE_SIZE; + + while (nelem) { + int nr = (PAGE_SIZE/size); + struct page *page; + if (nr > nelem) + nr = nelem; + pos = pos->next; + page = list_entry(pos, struct page, lru); + pagedata = page_address(page); + ret = (*fn)(pagedata, nr, state); + if (ret) + break; + nelem -= nr; + } + + return ret; +} + struct mmap_mfn_state { unsigned long va; struct vm_area_struct *vma; @@ -274,39 +308,25 @@ struct mmap_batch_state { /* auto translated dom0 note: if domU being created is PV, then mfn is * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). */ -static int mmap_batch_fn(void *data, void *state) +static int mmap_batch_fn(void *data, int nr, void *state) { xen_pfn_t *mfnp = data; struct mmap_batch_state *st = state; struct vm_area_struct *vma = st->vma; struct page **pages = vma->vm_private_data; - struct page *cur_page = NULL; + struct page **cur_pages = NULL; int ret; if (xen_feature(XENFEAT_auto_translated_physmap)) - cur_page = pages[st->index++]; + cur_pages = &pages[st->index]; - ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, - st->vma->vm_page_prot, st->domain, - &cur_page); + BUG_ON(nr < 0); + ret = xen_remap_domain_mfn_array(st->vma, st->va & PAGE_MASK, mfnp, nr, + (int *)mfnp, st->vma->vm_page_prot, + st->domain, cur_pages); - /* Store error code for second pass. */ - if (st->version == 1) { - if (ret < 0) { - /* - * V1 encodes the error codes in the 32bit top nibble of the - * mfn (with its known limitations vis-a-vis 64 bit callers). - */ - *mfnp |= (ret == -ENOENT) ? - PRIVCMD_MMAPBATCH_PAGED_ERROR : - PRIVCMD_MMAPBATCH_MFN_ERROR; - } - } else { /* st->version == 2 */ - *((int *) mfnp) = ret; - } - - /* And see if it affects the global_error. */ - if (ret < 0) { + /* Adjust the global_error? */ + if (ret != nr) { if (ret == -ENOENT) st->global_error = -ENOENT; else { @@ -315,23 +335,35 @@ static int mmap_batch_fn(void *data, void *state) st->global_error = 1; } } - st->va += PAGE_SIZE; + st->va += PAGE_SIZE * nr; + st->index += nr; return 0; } -static int mmap_return_errors(void *data, void *state) +static int mmap_return_error(int err, struct mmap_batch_state *st) { - struct mmap_batch_state *st = state; + int ret; if (st->version == 1) { - xen_pfn_t mfnp = *((xen_pfn_t *) data); - if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR) - return __put_user(mfnp, st->user_mfn++); - else + if (err) { + xen_pfn_t mfn; + + ret = get_user(mfn, st->user_mfn); + if (ret < 0) + return ret; + /* + * V1 encodes the error codes in the 32bit top + * nibble of the mfn (with its known + * limitations vis-a-vis 64 bit callers). + */ + mfn |= (err == -ENOENT) ? + PRIVCMD_MMAPBATCH_PAGED_ERROR : + PRIVCMD_MMAPBATCH_MFN_ERROR; + return __put_user(mfn, st->user_mfn++); + } else st->user_mfn++; } else { /* st->version == 2 */ - int err = *((int *) data); if (err) return __put_user(err, st->user_err++); else @@ -341,6 +373,21 @@ static int mmap_return_errors(void *data, void *state) return 0; } +static int mmap_return_errors(void *data, int nr, void *state) +{ + struct mmap_batch_state *st = state; + int *errs = data; + int i; + int ret; + + for (i = 0; i < nr; i++) { + ret = mmap_return_error(errs[i], st); + if (ret < 0) + return ret; + } + return 0; +} + /* Allocate pfns that are then mapped with gmfns from foreign domid. Update * the vma with the page info to use later. * Returns: 0 if success, otherwise -errno @@ -472,8 +519,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) state.version = version; /* mmap_batch_fn guarantees ret == 0 */ - BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), - &pagelist, mmap_batch_fn, &state)); + BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t), + &pagelist, mmap_batch_fn, &state)); up_write(&mm->mmap_sem); @@ -481,8 +528,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) /* Write back errors in second pass. */ state.user_mfn = (xen_pfn_t *)m.arr; state.user_err = m.err; - ret = traverse_pages(m.num, sizeof(xen_pfn_t), - &pagelist, mmap_return_errors, &state); + ret = traverse_pages_block(m.num, sizeof(xen_pfn_t), + &pagelist, mmap_return_errors, &state); } else ret = 0; diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c index 7724d90fc697..58a5389aec89 100644 --- a/drivers/xen/xlate_mmu.c +++ b/drivers/xen/xlate_mmu.c @@ -62,13 +62,15 @@ static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, } struct remap_data { - xen_pfn_t fgmfn; /* foreign domain's gmfn */ + xen_pfn_t *fgmfn; /* foreign domain's gmfn */ pgprot_t prot; domid_t domid; struct vm_area_struct *vma; int index; struct page **pages; struct xen_remap_mfn_info *info; + int *err_ptr; + int mapped; }; static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, @@ -80,38 +82,46 @@ static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); int rc; - rc = map_foreign_page(pfn, info->fgmfn, info->domid); - if (rc < 0) - return rc; - set_pte_at(info->vma->vm_mm, addr, ptep, pte); + rc = map_foreign_page(pfn, *info->fgmfn, info->domid); + *info->err_ptr++ = rc; + if (!rc) { + set_pte_at(info->vma->vm_mm, addr, ptep, pte); + info->mapped++; + } + info->fgmfn++; return 0; } -int xen_xlate_remap_gfn_range(struct vm_area_struct *vma, +int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t gfn, int nr, - pgprot_t prot, unsigned domid, + xen_pfn_t *mfn, int nr, + int *err_ptr, pgprot_t prot, + unsigned domid, struct page **pages) { int err; struct remap_data data; + unsigned long range = nr << PAGE_SHIFT; - /* TBD: Batching, current sole caller only does page at a time */ - if (nr > 1) - return -EINVAL; + /* Kept here for the purpose of making sure code doesn't break + x86 PVOPS */ + BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); - data.fgmfn = gfn; - data.prot = prot; + data.fgmfn = mfn; + data.prot = prot; data.domid = domid; - data.vma = vma; - data.index = 0; + data.vma = vma; data.pages = pages; - err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, + data.index = 0; + data.err_ptr = err_ptr; + data.mapped = 0; + + err = apply_to_page_range(vma->vm_mm, addr, range, remap_pte_fn, &data); - return err; + return err < 0 ? err : data.mapped; } -EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_range); +EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array); int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, int nr, struct page **pages) diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 9eb88a4512bd..c643e6a94c9a 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -27,17 +27,54 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order); struct vm_area_struct; + +/* + * xen_remap_domain_mfn_array() - map an array of foreign frames + * @vma: VMA to map the pages into + * @addr: Address at which to map the pages + * @gfn: Array of GFNs to map + * @nr: Number entries in the GFN array + * @err_ptr: Returns per-GFN error status. + * @prot: page protection mask + * @domid: Domain owning the pages + * @pages: Array of pages if this domain has an auto-translated physmap + * + * @gfn and @err_ptr may point to the same buffer, the GFNs will be + * overwritten by the error codes after they are mapped. + * + * Returns the number of successfully mapped frames, or a -ve error + * code. + */ +int xen_remap_domain_mfn_array(struct vm_area_struct *vma, + unsigned long addr, + xen_pfn_t *gfn, int nr, + int *err_ptr, pgprot_t prot, + unsigned domid, + struct page **pages); + +/* xen_remap_domain_mfn_range() - map a range of foreign frames + * @vma: VMA to map the pages into + * @addr: Address at which to map the pages + * @gfn: First GFN to map. + * @nr: Number frames to map + * @prot: page protection mask + * @domid: Domain owning the pages + * @pages: Array of pages if this domain has an auto-translated physmap + * + * Returns the number of successfully mapped frames, or a -ve error + * code. + */ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t mfn, int nr, + xen_pfn_t gfn, int nr, pgprot_t prot, unsigned domid, struct page **pages); int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages); -int xen_xlate_remap_gfn_range(struct vm_area_struct *vma, +int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t gfn, int nr, - pgprot_t prot, + xen_pfn_t *gfn, int nr, + int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages); int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, -- GitLab From ebfe79a7c85c171def09ff86f6fdea254a51d6c9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Mar 2015 14:24:17 +0300 Subject: [PATCH 0391/1910] xen/mce: fix up xen_late_init_mcelog() error handling Static checkers complain about the missing call to misc_deregister() if bind_virq_for_mce() fails. Also I reversed the tests so that we do error handling instead of success handling. That way we just have a series of function calls instead of the more complicated nested if statements in the original code. Let's preserve the error codes as well. Signed-off-by: Dan Carpenter Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- drivers/xen/mcelog.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 6ab6a79c38a5..a493c7315e94 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c @@ -393,14 +393,25 @@ static int bind_virq_for_mce(void) static int __init xen_late_init_mcelog(void) { + int ret; + /* Only DOM0 is responsible for MCE logging */ - if (xen_initial_domain()) { - /* register character device /dev/mcelog for xen mcelog */ - if (misc_register(&xen_mce_chrdev_device)) - return -ENODEV; - return bind_virq_for_mce(); - } + if (!xen_initial_domain()) + return -ENODEV; + + /* register character device /dev/mcelog for xen mcelog */ + ret = misc_register(&xen_mce_chrdev_device); + if (ret) + return ret; + + ret = bind_virq_for_mce(); + if (ret) + goto deregister; - return -ENODEV; + return 0; + +deregister: + misc_deregister(&xen_mce_chrdev_device); + return ret; } device_initcall(xen_late_init_mcelog); -- GitLab From 785748788bafb1f286a73195c2c43ad3cda5234d Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Tue, 10 Mar 2015 20:49:18 +0000 Subject: [PATCH 0392/1910] xen-scsiback: define a pr_fmt macro with xen-pvscsi Add the {xen-pvscsi: } prefix in pr_fmt and remove DPRINTK, then replace all DPRINTK with pr_debug. Also fixed up some comments just as eliminate redundant whitespace and format the code. These will make the code easier to read. Signed-off-by: Tao Chen Reviewed-by: Juergen Gross Signed-off-by: David Vrabel --- drivers/xen/xen-scsiback.c | 75 ++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 9faca6a60bb0..d0b0bc549355 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -31,6 +31,8 @@ * IN THE SOFTWARE. */ +#define pr_fmt(fmt) "xen-pvscsi: " fmt + #include #include @@ -69,9 +71,6 @@ #include #include -#define DPRINTK(_f, _a...) \ - pr_debug("(file=%s, line=%d) " _f, __FILE__ , __LINE__ , ## _a) - #define VSCSI_VERSION "v0.1" #define VSCSI_NAMELEN 32 @@ -271,7 +270,7 @@ static void scsiback_print_status(char *sense_buffer, int errors, { struct scsiback_tpg *tpg = pending_req->v2p->tpg; - pr_err("xen-pvscsi[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", + pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", tpg->tport->tport_name, pending_req->v2p->lun, pending_req->cmnd[0], status_byte(errors), msg_byte(errors), host_byte(errors), driver_byte(errors)); @@ -427,7 +426,7 @@ static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, BUG_ON(err); for (i = 0; i < cnt; i++) { if (unlikely(map[i].status != GNTST_okay)) { - pr_err("xen-pvscsi: invalid buffer -- could not remap it\n"); + pr_err("invalid buffer -- could not remap it\n"); map[i].handle = SCSIBACK_INVALID_HANDLE; err = -ENOMEM; } else { @@ -449,7 +448,7 @@ static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, for (i = 0; i < cnt; i++) { if (get_free_page(pg + mapcount)) { put_free_pages(pg, mapcount); - pr_err("xen-pvscsi: no grant page\n"); + pr_err("no grant page\n"); return -ENOMEM; } gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), @@ -492,7 +491,7 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, return 0; if (nr_segments > VSCSIIF_SG_TABLESIZE) { - DPRINTK("xen-pvscsi: invalid parameter nr_seg = %d\n", + pr_debug("invalid parameter nr_seg = %d\n", ring_req->nr_segments); return -EINVAL; } @@ -516,13 +515,12 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, nr_segments += n_segs; } if (nr_segments > SG_ALL) { - DPRINTK("xen-pvscsi: invalid nr_seg = %d\n", - nr_segments); + pr_debug("invalid nr_seg = %d\n", nr_segments); return -EINVAL; } } - /* free of (sgl) in fast_flush_area()*/ + /* free of (sgl) in fast_flush_area() */ pending_req->sgl = kmalloc_array(nr_segments, sizeof(struct scatterlist), GFP_KERNEL); if (!pending_req->sgl) @@ -679,7 +677,8 @@ static int prepare_pending_reqs(struct vscsibk_info *info, v2p = scsiback_do_translation(info, &vir); if (!v2p) { pending_req->v2p = NULL; - DPRINTK("xen-pvscsi: doesn't exist.\n"); + pr_debug("the v2p of (chn:%d, tgt:%d, lun:%d) doesn't exist.\n", + vir.chn, vir.tgt, vir.lun); return -ENODEV; } pending_req->v2p = v2p; @@ -690,14 +689,14 @@ static int prepare_pending_reqs(struct vscsibk_info *info, (pending_req->sc_data_direction != DMA_TO_DEVICE) && (pending_req->sc_data_direction != DMA_FROM_DEVICE) && (pending_req->sc_data_direction != DMA_NONE)) { - DPRINTK("xen-pvscsi: invalid parameter data_dir = %d\n", + pr_debug("invalid parameter data_dir = %d\n", pending_req->sc_data_direction); return -EINVAL; } pending_req->cmd_len = ring_req->cmd_len; if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { - DPRINTK("xen-pvscsi: invalid parameter cmd_len = %d\n", + pr_debug("invalid parameter cmd_len = %d\n", pending_req->cmd_len); return -EINVAL; } @@ -721,7 +720,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { rc = ring->rsp_prod_pvt; - pr_warn("xen-pvscsi: Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", + pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", info->domid, rp, rc, rp - rc); info->ring_error = 1; return 0; @@ -772,7 +771,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) scsiback_device_action(pending_req, TMR_LUN_RESET, 0); break; default: - pr_err_ratelimited("xen-pvscsi: invalid request\n"); + pr_err_ratelimited("invalid request\n"); scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, 0, pending_req); kmem_cache_free(scsiback_cachep, pending_req); @@ -874,14 +873,13 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, lunp = strrchr(phy, ':'); if (!lunp) { - pr_err("xen-pvscsi: illegal format of physical device %s\n", - phy); + pr_err("illegal format of physical device %s\n", phy); return -EINVAL; } *lunp = 0; lunp++; if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { - pr_err("xen-pvscsi: lun number not valid: %s\n", lunp); + pr_err("lun number not valid: %s\n", lunp); return -EINVAL; } @@ -909,7 +907,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, mutex_unlock(&scsiback_mutex); if (!tpg) { - pr_err("xen-pvscsi: %s:%d %s\n", phy, lun, error); + pr_err("%s:%d %s\n", phy, lun, error); return -ENODEV; } @@ -926,7 +924,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, if ((entry->v.chn == v->chn) && (entry->v.tgt == v->tgt) && (entry->v.lun == v->lun)) { - pr_warn("xen-pvscsi: Virtual ID is already used. Assignment was not performed.\n"); + pr_warn("Virtual ID is already used. Assignment was not performed.\n"); err = -EEXIST; goto out; } @@ -997,7 +995,7 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, if (!scsiback_add_translation_entry(info, phy, vir)) { if (xenbus_printf(XBT_NIL, info->dev->nodename, state, "%d", XenbusStateInitialised)) { - pr_err("xen-pvscsi: xenbus_printf error %s\n", state); + pr_err("xenbus_printf error %s\n", state); scsiback_del_translation_entry(info, vir); } } else { @@ -1012,7 +1010,7 @@ static void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, if (!scsiback_del_translation_entry(info, vir)) { if (xenbus_printf(XBT_NIL, info->dev->nodename, state, "%d", XenbusStateClosed)) - pr_err("xen-pvscsi: xenbus_printf error %s\n", state); + pr_err("xenbus_printf error %s\n", state); } } @@ -1071,15 +1069,14 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, /* modify vscsi-devs/dev-x/state */ if (xenbus_printf(XBT_NIL, dev->nodename, state, "%d", XenbusStateConnected)) { - pr_err("xen-pvscsi: xenbus_printf error %s\n", - str); + pr_err("xenbus_printf error %s\n", str); scsiback_del_translation_entry(info, &vir); xenbus_printf(XBT_NIL, dev->nodename, state, "%d", XenbusStateClosed); } } break; - /*When it is necessary, processing is added here.*/ + /* When it is necessary, processing is added here. */ default: break; } @@ -1196,7 +1193,7 @@ static int scsiback_probe(struct xenbus_device *dev, struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), GFP_KERNEL); - DPRINTK("%p %d\n", dev, dev->otherend_id); + pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); if (!info) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); @@ -1227,7 +1224,7 @@ static int scsiback_probe(struct xenbus_device *dev, return 0; fail: - pr_warn("xen-pvscsi: %s failed\n", __func__); + pr_warn("%s failed\n", __func__); scsiback_remove(dev); return err; @@ -1432,7 +1429,7 @@ scsiback_make_tport(struct target_fabric_configfs *tf, } snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); - pr_debug("xen-pvscsi: Allocated emulated Target %s Address: %s\n", + pr_debug("Allocated emulated Target %s Address: %s\n", scsiback_dump_proto_id(tport), name); return &tport->tport_wwn; @@ -1443,7 +1440,7 @@ static void scsiback_drop_tport(struct se_wwn *wwn) struct scsiback_tport *tport = container_of(wwn, struct scsiback_tport, tport_wwn); - pr_debug("xen-pvscsi: Deallocating emulated Target %s Address: %s\n", + pr_debug("Deallocating emulated Target %s Address: %s\n", scsiback_dump_proto_id(tport), tport->tport_name); kfree(tport); @@ -1470,8 +1467,8 @@ static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) static int scsiback_check_stop_free(struct se_cmd *se_cmd) { /* - * Do not release struct se_cmd's containing a valid TMR - * pointer. These will be released directly in scsiback_device_action() + * Do not release struct se_cmd's containing a valid TMR pointer. + * These will be released directly in scsiback_device_action() * with transport_generic_free_cmd(). */ if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) @@ -1637,7 +1634,7 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, return -ENOMEM; } /* - * Initialize the struct se_session pointer + * Initialize the struct se_session pointer */ tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(tv_nexus->tvn_se_sess)) { @@ -1708,7 +1705,7 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg) return -EBUSY; } - pr_debug("xen-pvscsi: Removing I_T Nexus to emulated %s Initiator Port: %s\n", + pr_debug("Removing I_T Nexus to emulated %s Initiator Port: %s\n", scsiback_dump_proto_id(tpg->tport), tv_nexus->tvn_se_sess->se_node_acl->initiatorname); @@ -1754,7 +1751,7 @@ static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg, unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; int ret; /* - * Shutdown the active I_T nexus if 'NULL' is passed.. + * Shutdown the active I_T nexus if 'NULL' is passed. */ if (!strncmp(page, "NULL", 4)) { ret = scsiback_drop_nexus(tpg); @@ -1925,7 +1922,7 @@ static void scsiback_drop_tpg(struct se_portal_group *se_tpg) */ scsiback_drop_nexus(tpg); /* - * Deregister the se_tpg from TCM.. + * Deregister the se_tpg from TCM. */ core_tpg_deregister(se_tpg); kfree(tpg); @@ -1995,7 +1992,7 @@ static int scsiback_register_configfs(void) struct target_fabric_configfs *fabric; int ret; - pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", + pr_debug("fabric module %s on %s/%s on "UTS_RELEASE"\n", VSCSI_VERSION, utsname()->sysname, utsname()->machine); /* * Register the top level struct config_item_type with TCM core @@ -2032,7 +2029,7 @@ static int scsiback_register_configfs(void) * Setup our local pointer to *fabric */ scsiback_fabric_configfs = fabric; - pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); + pr_debug("Set fabric -> scsiback_fabric_configfs\n"); return 0; }; @@ -2043,7 +2040,7 @@ static void scsiback_deregister_configfs(void) target_fabric_configfs_deregister(scsiback_fabric_configfs); scsiback_fabric_configfs = NULL; - pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); + pr_debug("Cleared scsiback_fabric_configfs\n"); }; static const struct xenbus_device_id scsiback_ids[] = { @@ -2094,7 +2091,7 @@ static int __init scsiback_init(void) xenbus_unregister_driver(&scsiback_driver); out_cache_destroy: kmem_cache_destroy(scsiback_cachep); - pr_err("xen-pvscsi: %s: error %d\n", __func__, ret); + pr_err("%s: error %d\n", __func__, ret); return ret; } -- GitLab From 169e6cf0666fdbc67ea39220143fd6e38875b96e Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 17 Feb 2015 08:02:48 +0100 Subject: [PATCH 0393/1910] xen: scsiback: add LUN of restored domain When a xen domain is being restored the LUN state of a pvscsi device is "Connected" and not "Initialising" as in case of attaching a new pvscsi LUN. This must be taken into account when adding a new pvscsi device for a domain as otherwise the pvscsi LUN won't be connected to the SCSI target associated with it. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: David Vrabel --- drivers/xen/xen-scsiback.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index d0b0bc549355..2eab75892c23 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -990,7 +990,7 @@ static int scsiback_del_translation_entry(struct vscsibk_info *info, } static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, - char *phy, struct ids_tuple *vir) + char *phy, struct ids_tuple *vir, int try) { if (!scsiback_add_translation_entry(info, phy, vir)) { if (xenbus_printf(XBT_NIL, info->dev->nodename, state, @@ -998,7 +998,7 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, pr_err("xenbus_printf error %s\n", state); scsiback_del_translation_entry(info, vir); } - } else { + } else if (!try) { xenbus_printf(XBT_NIL, info->dev->nodename, state, "%d", XenbusStateClosed); } @@ -1058,10 +1058,19 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, switch (op) { case VSCSIBACK_OP_ADD_OR_DEL_LUN: - if (device_state == XenbusStateInitialising) - scsiback_do_add_lun(info, state, phy, &vir); - if (device_state == XenbusStateClosing) + switch (device_state) { + case XenbusStateInitialising: + scsiback_do_add_lun(info, state, phy, &vir, 0); + break; + case XenbusStateConnected: + scsiback_do_add_lun(info, state, phy, &vir, 1); + break; + case XenbusStateClosing: scsiback_do_del_lun(info, state, &vir); + break; + default: + break; + } break; case VSCSIBACK_OP_UPDATEDEV_STATE: -- GitLab From 85617dc7ee1caa68a8d078b5dd4328d0ef373282 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 17 Feb 2015 08:02:49 +0100 Subject: [PATCH 0394/1910] xen: support suspend/resume in pvscsi frontend Up to now the pvscsi frontend hasn't supported domain suspend and resume. When a domain with an assigned pvscsi device was suspended and resumed again, it was not able to use the device any more: trying to do so resulted in hanging processes. Support suspend and resume of pvscsi devices. Signed-off-by: Juergen Gross Signed-off-by: David Vrabel --- drivers/scsi/xen-scsifront.c | 214 +++++++++++++++++++++++++++++------ 1 file changed, 179 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 34199d206ba6..78d95069ac6a 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -63,6 +63,7 @@ #define VSCSIFRONT_OP_ADD_LUN 1 #define VSCSIFRONT_OP_DEL_LUN 2 +#define VSCSIFRONT_OP_READD_LUN 3 /* Tuning point. */ #define VSCSIIF_DEFAULT_CMD_PER_LUN 10 @@ -113,8 +114,13 @@ struct vscsifrnt_info { DECLARE_BITMAP(shadow_free_bitmap, VSCSIIF_MAX_REQS); struct vscsifrnt_shadow *shadow[VSCSIIF_MAX_REQS]; + /* Following items are protected by the host lock. */ wait_queue_head_t wq_sync; + wait_queue_head_t wq_pause; unsigned int wait_ring_available:1; + unsigned int waiting_pause:1; + unsigned int pause:1; + unsigned callers; char dev_state_path[64]; struct task_struct *curr; @@ -274,31 +280,31 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info, wake_up(&shadow->wq_reset); } -static int scsifront_cmd_done(struct vscsifrnt_info *info) +static void scsifront_do_response(struct vscsifrnt_info *info, + struct vscsiif_response *ring_rsp) +{ + if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || + test_bit(ring_rsp->rqid, info->shadow_free_bitmap), + "illegal rqid %u returned by backend!\n", ring_rsp->rqid)) + return; + + if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) + scsifront_cdb_cmd_done(info, ring_rsp); + else + scsifront_sync_cmd_done(info, ring_rsp); +} + +static int scsifront_ring_drain(struct vscsifrnt_info *info) { struct vscsiif_response *ring_rsp; RING_IDX i, rp; int more_to_do = 0; - unsigned long flags; - - spin_lock_irqsave(info->host->host_lock, flags); rp = info->ring.sring->rsp_prod; rmb(); /* ordering required respective to dom0 */ for (i = info->ring.rsp_cons; i != rp; i++) { - ring_rsp = RING_GET_RESPONSE(&info->ring, i); - - if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || - test_bit(ring_rsp->rqid, info->shadow_free_bitmap), - "illegal rqid %u returned by backend!\n", - ring_rsp->rqid)) - continue; - - if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) - scsifront_cdb_cmd_done(info, ring_rsp); - else - scsifront_sync_cmd_done(info, ring_rsp); + scsifront_do_response(info, ring_rsp); } info->ring.rsp_cons = i; @@ -308,6 +314,18 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info) else info->ring.sring->rsp_event = i + 1; + return more_to_do; +} + +static int scsifront_cmd_done(struct vscsifrnt_info *info) +{ + int more_to_do; + unsigned long flags; + + spin_lock_irqsave(info->host->host_lock, flags); + + more_to_do = scsifront_ring_drain(info); + info->wait_ring_available = 0; spin_unlock_irqrestore(info->host->host_lock, flags); @@ -328,6 +346,24 @@ static irqreturn_t scsifront_irq_fn(int irq, void *dev_id) return IRQ_HANDLED; } +static void scsifront_finish_all(struct vscsifrnt_info *info) +{ + unsigned i; + struct vscsiif_response resp; + + scsifront_ring_drain(info); + + for (i = 0; i < VSCSIIF_MAX_REQS; i++) { + if (test_bit(i, info->shadow_free_bitmap)) + continue; + resp.rqid = i; + resp.sense_len = 0; + resp.rslt = DID_RESET << 16; + resp.residual_len = 0; + scsifront_do_response(info, &resp); + } +} + static int map_data_for_request(struct vscsifrnt_info *info, struct scsi_cmnd *sc, struct vscsiif_request *ring_req, @@ -475,6 +511,27 @@ static struct vscsiif_request *scsifront_command2ring( return ring_req; } +static int scsifront_enter(struct vscsifrnt_info *info) +{ + if (info->pause) + return 1; + info->callers++; + return 0; +} + +static void scsifront_return(struct vscsifrnt_info *info) +{ + info->callers--; + if (info->callers) + return; + + if (!info->waiting_pause) + return; + + info->waiting_pause = 0; + wake_up(&info->wq_pause); +} + static int scsifront_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) { @@ -486,6 +543,10 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, uint16_t rqid; spin_lock_irqsave(shost->host_lock, flags); + if (scsifront_enter(info)) { + spin_unlock_irqrestore(shost->host_lock, flags); + return SCSI_MLQUEUE_HOST_BUSY; + } if (RING_FULL(&info->ring)) goto busy; @@ -505,6 +566,7 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, if (err < 0) { pr_debug("%s: err %d\n", __func__, err); scsifront_put_rqid(info, rqid); + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); if (err == -ENOMEM) return SCSI_MLQUEUE_HOST_BUSY; @@ -514,11 +576,13 @@ static int scsifront_queuecommand(struct Scsi_Host *shost, } scsifront_do_request(info); + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); return 0; busy: + scsifront_return(info); spin_unlock_irqrestore(shost->host_lock, flags); pr_debug("%s: busy\n", __func__); return SCSI_MLQUEUE_HOST_BUSY; @@ -549,7 +613,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) if (ring_req) break; } - if (err) { + if (err || info->pause) { spin_unlock_irq(host->host_lock); kfree(shadow); return FAILED; @@ -561,6 +625,11 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) spin_lock_irq(host->host_lock); } + if (scsifront_enter(info)) { + spin_unlock_irq(host->host_lock); + return FAILED; + } + ring_req->act = act; ring_req->ref_rqid = s->rqid; @@ -587,6 +656,7 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act) err = FAILED; } + scsifront_return(info); spin_unlock_irq(host->host_lock); return err; } @@ -698,6 +768,13 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info) return err; } +static void scsifront_free_ring(struct vscsifrnt_info *info) +{ + unbind_from_irqhandler(info->irq, info); + gnttab_end_foreign_access(info->ring_ref, 0, + (unsigned long)info->ring.sring); +} + static int scsifront_init_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; @@ -744,9 +821,7 @@ static int scsifront_init_ring(struct vscsifrnt_info *info) fail: xenbus_transaction_end(xbt, 1); free_sring: - unbind_from_irqhandler(info->irq, info); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); + scsifront_free_ring(info); return err; } @@ -779,6 +854,7 @@ static int scsifront_probe(struct xenbus_device *dev, } init_waitqueue_head(&info->wq_sync); + init_waitqueue_head(&info->wq_pause); spin_lock_init(&info->shadow_lock); snprintf(name, TASK_COMM_LEN, "vscsiif.%d", host->host_no); @@ -802,13 +878,60 @@ static int scsifront_probe(struct xenbus_device *dev, return 0; free_sring: - unbind_from_irqhandler(info->irq, info); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); + scsifront_free_ring(info); scsi_host_put(host); return err; } +static int scsifront_resume(struct xenbus_device *dev) +{ + struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); + struct Scsi_Host *host = info->host; + int err; + + spin_lock_irq(host->host_lock); + + /* Finish all still pending commands. */ + scsifront_finish_all(info); + + spin_unlock_irq(host->host_lock); + + /* Reconnect to dom0. */ + scsifront_free_ring(info); + err = scsifront_init_ring(info); + if (err) { + dev_err(&dev->dev, "fail to resume %d\n", err); + scsi_host_put(host); + return err; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + + return 0; +} + +static int scsifront_suspend(struct xenbus_device *dev) +{ + struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); + struct Scsi_Host *host = info->host; + int err = 0; + + /* No new commands for the backend. */ + spin_lock_irq(host->host_lock); + info->pause = 1; + while (info->callers && !err) { + info->waiting_pause = 1; + info->wait_ring_available = 0; + spin_unlock_irq(host->host_lock); + wake_up(&info->wq_sync); + err = wait_event_interruptible(info->wq_pause, + !info->waiting_pause); + spin_lock_irq(host->host_lock); + } + spin_unlock_irq(host->host_lock); + return err; +} + static int scsifront_remove(struct xenbus_device *dev) { struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev); @@ -823,10 +946,7 @@ static int scsifront_remove(struct xenbus_device *dev) } mutex_unlock(&scsifront_mutex); - gnttab_end_foreign_access(info->ring_ref, 0, - (unsigned long)info->ring.sring); - unbind_from_irqhandler(info->irq, info); - + scsifront_free_ring(info); scsi_host_put(info->host); return 0; @@ -919,6 +1039,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) scsi_device_put(sdev); } break; + case VSCSIFRONT_OP_READD_LUN: + if (device_state == XenbusStateConnected) + xenbus_printf(XBT_NIL, dev->nodename, + info->dev_state_path, + "%d", XenbusStateConnected); + break; default: break; } @@ -932,21 +1058,29 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) static void scsifront_read_backend_params(struct xenbus_device *dev, struct vscsifrnt_info *info) { - unsigned int sg_grant; + unsigned int sg_grant, nr_segs; int ret; struct Scsi_Host *host = info->host; ret = xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg-grant", "%u", &sg_grant); - if (ret == 1 && sg_grant) { - sg_grant = min_t(unsigned int, sg_grant, SG_ALL); - sg_grant = max_t(unsigned int, sg_grant, VSCSIIF_SG_TABLESIZE); - host->sg_tablesize = min_t(unsigned int, sg_grant, + if (ret != 1) + sg_grant = 0; + nr_segs = min_t(unsigned int, sg_grant, SG_ALL); + nr_segs = max_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE); + nr_segs = min_t(unsigned int, nr_segs, VSCSIIF_SG_TABLESIZE * PAGE_SIZE / sizeof(struct scsiif_request_segment)); - host->max_sectors = (host->sg_tablesize - 1) * PAGE_SIZE / 512; - } - dev_info(&dev->dev, "using up to %d SG entries\n", host->sg_tablesize); + + if (!info->pause && sg_grant) + dev_info(&dev->dev, "using up to %d SG entries\n", nr_segs); + else if (info->pause && nr_segs < host->sg_tablesize) + dev_warn(&dev->dev, + "SG entries decreased from %d to %u - device may not work properly anymore\n", + host->sg_tablesize, nr_segs); + + host->sg_tablesize = nr_segs; + host->max_sectors = (nr_segs - 1) * PAGE_SIZE / 512; } static void scsifront_backend_changed(struct xenbus_device *dev, @@ -965,6 +1099,14 @@ static void scsifront_backend_changed(struct xenbus_device *dev, case XenbusStateConnected: scsifront_read_backend_params(dev, info); + + if (info->pause) { + scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_READD_LUN); + xenbus_switch_state(dev, XenbusStateConnected); + info->pause = 0; + return; + } + if (xenbus_read_driver_state(dev->nodename) == XenbusStateInitialised) scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); @@ -1002,6 +1144,8 @@ static struct xenbus_driver scsifront_driver = { .ids = scsifront_ids, .probe = scsifront_probe, .remove = scsifront_remove, + .resume = scsifront_resume, + .suspend = scsifront_suspend, .otherend_changed = scsifront_backend_changed, }; -- GitLab From 278edfc07875779a69277f6c5773ec9318a994ee Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 11 Mar 2015 13:52:00 +0000 Subject: [PATCH 0395/1910] xen-pciback: also support disabling of bus-mastering and memory-write-invalidate It's not clear to me why only the enabling operation got handled so far. Signed-off-by: Jan Beulich Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- drivers/xen/xen-pciback/conf_space_header.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index 2d7369391472..c2260a0456c9 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c @@ -88,9 +88,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", pci_name(dev)); pci_set_master(dev); + } else if (dev->is_busmaster && !is_master_cmd(value)) { + if (unlikely(verbose_request)) + printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n", + pci_name(dev)); + pci_clear_master(dev); } - if (value & PCI_COMMAND_INVALIDATE) { + if (!(cmd->val & PCI_COMMAND_INVALIDATE) && + (value & PCI_COMMAND_INVALIDATE)) { if (unlikely(verbose_request)) printk(KERN_DEBUG DRV_NAME ": %s: enable memory-write-invalidate\n", @@ -101,6 +107,13 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) pci_name(dev), err); value &= ~PCI_COMMAND_INVALIDATE; } + } else if ((cmd->val & PCI_COMMAND_INVALIDATE) && + !(value & PCI_COMMAND_INVALIDATE)) { + if (unlikely(verbose_request)) + printk(KERN_DEBUG + DRV_NAME ": %s: disable memory-write-invalidate\n", + pci_name(dev)); + pci_clear_mwi(dev); } cmd->val = value; -- GitLab From 99d422341376443a98ef22d0f0003b3381f32186 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Thu, 12 Mar 2015 10:17:11 +0800 Subject: [PATCH 0396/1910] ASoC: wm8731: let codec to manage clock by itself Enable WM8731 to support common clock framework. Signed-off-by: Songjun Wu Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 098c143f44d6..8df1550f74b5 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { /* codec private data */ struct wm8731_priv { struct regmap *regmap; + struct clk *mclk; struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; const struct snd_pcm_hw_constraint_list *constraints; unsigned int sysclk; @@ -390,6 +392,8 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, switch (clk_id) { case WM8731_SYSCLK_XTAL: case WM8731_SYSCLK_MCLK: + if (wm8731->mclk && clk_set_rate(wm8731->mclk, freq)) + return -EINVAL; wm8731->sysclk_type = clk_id; break; default: @@ -491,6 +495,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: + if (wm8731->mclk) + clk_prepare_enable(wm8731->mclk); break; case SND_SOC_BIAS_PREPARE: break; @@ -509,6 +515,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8731_PWR, reg | 0x0040); break; case SND_SOC_BIAS_OFF: + if (wm8731->mclk) + clk_disable_unprepare(wm8731->mclk); snd_soc_write(codec, WM8731_PWR, 0xffff); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); @@ -667,6 +675,19 @@ static int wm8731_spi_probe(struct spi_device *spi) if (wm8731 == NULL) return -ENOMEM; + wm8731->mclk = devm_clk_get(&spi->dev, "mclk"); + if (IS_ERR(wm8731->mclk)) { + ret = PTR_ERR(wm8731->mclk); + if (ret == -ENOENT) { + wm8731->mclk = NULL; + dev_warn(&spi->dev, "Assuming static MCLK\n"); + } else { + dev_err(&spi->dev, "Failed to get MCLK: %d\n", + ret); + return ret; + } + } + mutex_init(&wm8731->lock); wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); @@ -718,6 +739,19 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, if (wm8731 == NULL) return -ENOMEM; + wm8731->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(wm8731->mclk)) { + ret = PTR_ERR(wm8731->mclk); + if (ret == -ENOENT) { + wm8731->mclk = NULL; + dev_warn(&i2c->dev, "Assuming static MCLK\n"); + } else { + dev_err(&i2c->dev, "Failed to get MCLK: %d\n", + ret); + return ret; + } + } + mutex_init(&wm8731->lock); wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); -- GitLab From 45706bb53d118b5340a12926e26444d73b6491f9 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Fri, 19 Dec 2014 08:41:05 +0530 Subject: [PATCH 0397/1910] powerpc/book3s: Fix flush_tlb cpu_spec hook to take a generic argument. The flush_tlb hook in cpu_spec was introduced as a generic function hook to invalidate TLBs. But the current implementation of flush_tlb hook takes IS (invalidation selector) as an argument which is architecture dependent. Hence, It is not right to have a generic routine where caller has to pass non-generic argument. This patch fixes this and makes flush_tlb hook as high level API. Reported-by: Benjamin Herrenschmidt Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cputable.h | 8 +++- arch/powerpc/include/asm/mmu-hash64.h | 1 + arch/powerpc/kernel/cpu_setup_power.S | 10 +---- arch/powerpc/kernel/cputable.c | 4 +- arch/powerpc/kernel/mce_power.c | 53 ++++++++++++++++++++++++++- arch/powerpc/kvm/book3s_hv_ras.c | 4 +- 6 files changed, 65 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 5cf5a6d10685..6367b8347dad 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -100,7 +100,7 @@ struct cpu_spec { /* * Processor specific routine to flush tlbs. */ - void (*flush_tlb)(unsigned long inval_selector); + void (*flush_tlb)(unsigned int action); }; @@ -114,6 +114,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, extern const char *powerpc_base_platform; +/* TLB flush actions. Used as argument to cpu_spec.flush_tlb() hook */ +enum { + TLB_INVAL_SCOPE_GLOBAL = 0, /* invalidate all TLBs */ + TLB_INVAL_SCOPE_LPID = 1, /* invalidate TLBs for current LPID */ +}; + #endif /* __ASSEMBLY__ */ /* CPU kernel features */ diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 4f13c3ed7acf..1da6a81ce541 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -112,6 +112,7 @@ #define TLBIEL_INVAL_SET_SHIFT 12 #define POWER7_TLB_SETS 128 /* # sets in POWER7 TLB */ +#define POWER8_TLB_SETS 512 /* # sets in POWER8 TLB */ #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 46733535cc0b..9c9b7411b28b 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -137,15 +137,11 @@ __init_HFSCR: /* * Clear the TLB using the specified IS form of tlbiel instruction * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. - * - * r3 = IS field */ __init_tlb_power7: - li r3,0xc00 /* IS field = 0b11 */ -_GLOBAL(__flush_tlb_power7) li r6,128 mtctr r6 - mr r7,r3 /* IS field */ + li r7,0xc00 /* IS field = 0b11 */ ptesync 2: tlbiel r7 addi r7,r7,0x1000 @@ -154,11 +150,9 @@ _GLOBAL(__flush_tlb_power7) 1: blr __init_tlb_power8: - li r3,0xc00 /* IS field = 0b11 */ -_GLOBAL(__flush_tlb_power8) li r6,512 mtctr r6 - mr r7,r3 /* IS field */ + li r7,0xc00 /* IS field = 0b11 */ ptesync 2: tlbiel r7 addi r7,r7,0x1000 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index f337666768a7..7ed126bc9b18 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -71,8 +71,8 @@ extern void __restore_cpu_power7(void); extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power8(void); extern void __restore_cpu_a2(void); -extern void __flush_tlb_power7(unsigned long inval_selector); -extern void __flush_tlb_power8(unsigned long inval_selector); +extern void __flush_tlb_power7(unsigned int action); +extern void __flush_tlb_power8(unsigned int action); extern long __machine_check_early_realmode_p7(struct pt_regs *regs); extern long __machine_check_early_realmode_p8(struct pt_regs *regs); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index b6f123ab90ed..2c647b1e62e4 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c @@ -28,6 +28,55 @@ #include #include +static void flush_tlb_206(unsigned int num_sets, unsigned int action) +{ + unsigned long rb; + unsigned int i; + + switch (action) { + case TLB_INVAL_SCOPE_GLOBAL: + rb = TLBIEL_INVAL_SET; + break; + case TLB_INVAL_SCOPE_LPID: + rb = TLBIEL_INVAL_SET_LPID; + break; + default: + BUG(); + break; + } + + asm volatile("ptesync" : : : "memory"); + for (i = 0; i < num_sets; i++) { + asm volatile("tlbiel %0" : : "r" (rb)); + rb += 1 << TLBIEL_INVAL_SET_SHIFT; + } + asm volatile("ptesync" : : : "memory"); +} + +/* + * Generic routine to flush TLB on power7. This routine is used as + * flush_tlb hook in cpu_spec for Power7 processor. + * + * action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs. + * TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID. + */ +void __flush_tlb_power7(unsigned int action) +{ + flush_tlb_206(POWER7_TLB_SETS, action); +} + +/* + * Generic routine to flush TLB on power8. This routine is used as + * flush_tlb hook in cpu_spec for power8 processor. + * + * action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs. + * TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID. + */ +void __flush_tlb_power8(unsigned int action) +{ + flush_tlb_206(POWER8_TLB_SETS, action); +} + /* flush SLBs and reload */ static void flush_and_reload_slb(void) { @@ -79,7 +128,7 @@ static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) } if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { if (cur_cpu_spec && cur_cpu_spec->flush_tlb) - cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); + cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL); /* reset error bits */ dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; } @@ -110,7 +159,7 @@ static long mce_handle_common_ierror(uint64_t srr1) break; case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { - cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); + cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL); handled = 1; } break; diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index 60081bd75847..93b5f5c9b445 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -84,7 +84,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) } if (dsisr & DSISR_MC_TLB_MULTI) { if (cur_cpu_spec && cur_cpu_spec->flush_tlb) - cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); + cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID); dsisr &= ~DSISR_MC_TLB_MULTI; } /* Any other errors we don't understand? */ @@ -102,7 +102,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) break; case SRR1_MC_IFETCH_TLBMULTI: if (cur_cpu_spec && cur_cpu_spec->flush_tlb) - cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); + cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID); break; default: handled = 0; -- GitLab From 28158cd1b75180343efa7c4d7d2f8e74ccc63b8f Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 11 Feb 2015 10:20:49 +1100 Subject: [PATCH 0398/1910] powerpc/eeh: Enhance pcibios_set_pcie_reset_state() Function pcibios_set_pcie_reset_state() is possibly called by pci_reset_function(), on which VFIO infrastructure depends to issue reset. pcibios_set_pcie_reset_state() is issuing reset on the parent PE of the indicated PCI device. The reset causes state lost on all PCI devices except the indicated one as the argument to pcibios_set_pcie_reset_state(). Also, sideband MMIO access from guest when issuing reset would cause unexpected EEH error. For above two issues, the patch applies following enhancements to pcibios_set_pcie_reset_state(): * For all PCI devices except the indicated one, save their state prior to reset and restore state after that. * Explicitly freeze PE prior to reset and unfreeze it after that, in order to avoid unexpected EEH error. Tested-by: Priya M. A Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/eeh.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 3b2252e7731b..19a897c810be 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -667,6 +667,55 @@ int eeh_pci_enable(struct eeh_pe *pe, int function) return rc; } +static void *eeh_disable_and_save_dev_state(void *data, void *userdata) +{ + struct eeh_dev *edev = data; + struct pci_dev *pdev = eeh_dev_to_pci_dev(edev); + struct pci_dev *dev = userdata; + + /* + * The caller should have disabled and saved the + * state for the specified device + */ + if (!pdev || pdev == dev) + return NULL; + + /* Ensure we have D0 power state */ + pci_set_power_state(pdev, PCI_D0); + + /* Save device state */ + pci_save_state(pdev); + + /* + * Disable device to avoid any DMA traffic and + * interrupt from the device + */ + pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); + + return NULL; +} + +static void *eeh_restore_dev_state(void *data, void *userdata) +{ + struct eeh_dev *edev = data; + struct device_node *dn = eeh_dev_to_of_node(edev); + struct pci_dev *pdev = eeh_dev_to_pci_dev(edev); + struct pci_dev *dev = userdata; + + if (!pdev) + return NULL; + + /* Apply customization from firmware */ + if (dn && eeh_ops->restore_config) + eeh_ops->restore_config(dn); + + /* The caller should restore state for the specified device */ + if (pdev != dev) + pci_save_state(pdev); + + return NULL; +} + /** * pcibios_set_pcie_slot_reset - Set PCI-E reset state * @dev: pci device struct @@ -689,13 +738,19 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat switch (state) { case pcie_deassert_reset: eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); + eeh_unfreeze_pe(pe, false); eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); + eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev); break; case pcie_hot_reset: + eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); + eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); eeh_ops->reset(pe, EEH_RESET_HOT); break; case pcie_warm_reset: + eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); + eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); break; -- GitLab From 6ec7334304f2882b7fc13ab70a0bf58948cf6244 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 13 Feb 2015 15:16:32 +1100 Subject: [PATCH 0399/1910] powerpc/pci: Fix comments about ppc_md.pcibios_fixup The patch fixes the comments about ppc_md.pcibios_fixup(), which should be called after allocating resources. Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/machdep.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index c8175a3fe560..098d51e924ea 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -125,7 +125,7 @@ struct machdep_calls { unsigned int (*get_irq)(void); /* PCI stuff */ - /* Called after scanning the bus, before allocating resources */ + /* Called after allocating resources */ void (*pcibios_fixup)(void); int (*pci_probe_mode)(struct pci_bus *); void (*pci_irq_fixup)(struct pci_dev *dev); -- GitLab From 01f3bfb7804ae20aaf66884cf537f7dc2cdc1671 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:39 +1100 Subject: [PATCH 0400/1910] powerpc/powernv: Shorten EEH function names The patch shortens names of EEH functions in powernv-eeh.c and no logic change introduced by this patch. Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-powernv.c | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index e261869adc86..f562dd1a99cc 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -39,11 +39,11 @@ #include "pci.h" /** - * powernv_eeh_init - EEH platform dependent initialization + * pnv_eeh_init - EEH platform dependent initialization * * EEH platform dependent initialization on powernv */ -static int powernv_eeh_init(void) +static int pnv_eeh_init(void) { struct pci_controller *hose; struct pnv_phb *phb; @@ -86,14 +86,14 @@ static int powernv_eeh_init(void) } /** - * powernv_eeh_post_init - EEH platform dependent post initialization + * pnv_eeh_post_init - EEH platform dependent post initialization * * EEH platform dependent post initialization on powernv. When * the function is called, the EEH PEs and devices should have * been built. If the I/O cache staff has been built, EEH is * ready to supply service. */ -static int powernv_eeh_post_init(void) +static int pnv_eeh_post_init(void) { struct pci_controller *hose; struct pnv_phb *phb; @@ -113,7 +113,7 @@ static int powernv_eeh_post_init(void) } /** - * powernv_eeh_dev_probe - Do probe on PCI device + * pnv_eeh_dev_probe - Do probe on PCI device * @dev: PCI device * @flag: unused * @@ -129,7 +129,7 @@ static int powernv_eeh_post_init(void) * was possiblly triggered by EEH core, the binding between EEH device * and the PCI device isn't built yet. */ -static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) +static int pnv_eeh_dev_probe(struct pci_dev *dev, void *flag) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; @@ -221,7 +221,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) } /** - * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable + * pnv_eeh_set_option - Initialize EEH or MMIO/DMA reenable * @pe: EEH PE * @option: operation to be issued * @@ -229,7 +229,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) * Currently, following options are support according to PAPR: * Enable EEH, Disable EEH, Enable MMIO and Enable DMA */ -static int powernv_eeh_set_option(struct eeh_pe *pe, int option) +static int pnv_eeh_set_option(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -246,19 +246,19 @@ static int powernv_eeh_set_option(struct eeh_pe *pe, int option) } /** - * powernv_eeh_get_pe_addr - Retrieve PE address + * pnv_eeh_get_pe_addr - Retrieve PE address * @pe: EEH PE * * Retrieve the PE address according to the given tranditional * PCI BDF (Bus/Device/Function) address. */ -static int powernv_eeh_get_pe_addr(struct eeh_pe *pe) +static int pnv_eeh_get_pe_addr(struct eeh_pe *pe) { return pe->addr; } /** - * powernv_eeh_get_state - Retrieve PE state + * pnv_eeh_get_state - Retrieve PE state * @pe: EEH PE * @delay: delay while PE state is temporarily unavailable * @@ -267,7 +267,7 @@ static int powernv_eeh_get_pe_addr(struct eeh_pe *pe) * we prefer passing down to hardware implementation to handle * it. */ -static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay) +static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -292,13 +292,13 @@ static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay) } /** - * powernv_eeh_reset - Reset the specified PE + * pnv_eeh_reset - Reset the specified PE * @pe: EEH PE * @option: reset option * * Reset the specified PE */ -static int powernv_eeh_reset(struct eeh_pe *pe, int option) +static int pnv_eeh_reset(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -311,20 +311,20 @@ static int powernv_eeh_reset(struct eeh_pe *pe, int option) } /** - * powernv_eeh_wait_state - Wait for PE state + * pnv_eeh_wait_state - Wait for PE state * @pe: EEH PE * @max_wait: maximal period in microsecond * * Wait for the state of associated PE. It might take some time * to retrieve the PE's state. */ -static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) +static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait) { int ret; int mwait; while (1) { - ret = powernv_eeh_get_state(pe, &mwait); + ret = pnv_eeh_get_state(pe, &mwait); /* * If the PE's state is temporarily unavailable, @@ -348,7 +348,7 @@ static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) } /** - * powernv_eeh_get_log - Retrieve error log + * pnv_eeh_get_log - Retrieve error log * @pe: EEH PE * @severity: temporary or permanent error log * @drv_log: driver log to be combined with retrieved error log @@ -356,8 +356,8 @@ static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) * * Retrieve the temporary or permanent error from the PE. */ -static int powernv_eeh_get_log(struct eeh_pe *pe, int severity, - char *drv_log, unsigned long len) +static int pnv_eeh_get_log(struct eeh_pe *pe, int severity, + char *drv_log, unsigned long len) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -370,14 +370,14 @@ static int powernv_eeh_get_log(struct eeh_pe *pe, int severity, } /** - * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE + * pnv_eeh_configure_bridge - Configure PCI bridges in the indicated PE * @pe: EEH PE * * The function will be called to reconfigure the bridges included * in the specified PE so that the mulfunctional PE would be recovered * again. */ -static int powernv_eeh_configure_bridge(struct eeh_pe *pe) +static int pnv_eeh_configure_bridge(struct eeh_pe *pe) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -390,7 +390,7 @@ static int powernv_eeh_configure_bridge(struct eeh_pe *pe) } /** - * powernv_pe_err_inject - Inject specified error to the indicated PE + * pnv_pe_err_inject - Inject specified error to the indicated PE * @pe: the indicated PE * @type: error type * @func: specific error type @@ -401,8 +401,8 @@ static int powernv_eeh_configure_bridge(struct eeh_pe *pe) * determined by @type and @func, to the indicated PE for * testing purpose. */ -static int powernv_eeh_err_inject(struct eeh_pe *pe, int type, int func, - unsigned long addr, unsigned long mask) +static int pnv_eeh_err_inject(struct eeh_pe *pe, int type, int func, + unsigned long addr, unsigned long mask) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; @@ -414,7 +414,7 @@ static int powernv_eeh_err_inject(struct eeh_pe *pe, int type, int func, return ret; } -static inline bool powernv_eeh_cfg_blocked(struct device_node *dn) +static inline bool pnv_eeh_cfg_blocked(struct device_node *dn) { struct eeh_dev *edev = of_node_to_eeh_dev(dn); @@ -427,10 +427,10 @@ static inline bool powernv_eeh_cfg_blocked(struct device_node *dn) return false; } -static int powernv_eeh_read_config(struct device_node *dn, - int where, int size, u32 *val) +static int pnv_eeh_read_config(struct device_node *dn, + int where, int size, u32 *val) { - if (powernv_eeh_cfg_blocked(dn)) { + if (pnv_eeh_cfg_blocked(dn)) { *val = 0xFFFFFFFF; return PCIBIOS_SET_FAILED; } @@ -438,22 +438,22 @@ static int powernv_eeh_read_config(struct device_node *dn, return pnv_pci_cfg_read(dn, where, size, val); } -static int powernv_eeh_write_config(struct device_node *dn, - int where, int size, u32 val) +static int pnv_eeh_write_config(struct device_node *dn, + int where, int size, u32 val) { - if (powernv_eeh_cfg_blocked(dn)) + if (pnv_eeh_cfg_blocked(dn)) return PCIBIOS_SET_FAILED; return pnv_pci_cfg_write(dn, where, size, val); } /** - * powernv_eeh_next_error - Retrieve next EEH error to handle + * pnv_eeh_next_error - Retrieve next EEH error to handle * @pe: Affected PE * * Using OPAL API, to retrieve next EEH error for EEH core to handle */ -static int powernv_eeh_next_error(struct eeh_pe **pe) +static int pnv_eeh_next_error(struct eeh_pe **pe) { struct pci_controller *hose; struct pnv_phb *phb = NULL; @@ -469,7 +469,7 @@ static int powernv_eeh_next_error(struct eeh_pe **pe) return -EEXIST; } -static int powernv_eeh_restore_config(struct device_node *dn) +static int pnv_eeh_restore_config(struct device_node *dn) { struct eeh_dev *edev = of_node_to_eeh_dev(dn); struct pnv_phb *phb; @@ -490,24 +490,24 @@ static int powernv_eeh_restore_config(struct device_node *dn) return 0; } -static struct eeh_ops powernv_eeh_ops = { +static struct eeh_ops pnv_eeh_ops = { .name = "powernv", - .init = powernv_eeh_init, - .post_init = powernv_eeh_post_init, + .init = pnv_eeh_init, + .post_init = pnv_eeh_post_init, .of_probe = NULL, - .dev_probe = powernv_eeh_dev_probe, - .set_option = powernv_eeh_set_option, - .get_pe_addr = powernv_eeh_get_pe_addr, - .get_state = powernv_eeh_get_state, - .reset = powernv_eeh_reset, - .wait_state = powernv_eeh_wait_state, - .get_log = powernv_eeh_get_log, - .configure_bridge = powernv_eeh_configure_bridge, - .err_inject = powernv_eeh_err_inject, - .read_config = powernv_eeh_read_config, - .write_config = powernv_eeh_write_config, - .next_error = powernv_eeh_next_error, - .restore_config = powernv_eeh_restore_config + .dev_probe = pnv_eeh_dev_probe, + .set_option = pnv_eeh_set_option, + .get_pe_addr = pnv_eeh_get_pe_addr, + .get_state = pnv_eeh_get_state, + .reset = pnv_eeh_reset, + .wait_state = pnv_eeh_wait_state, + .get_log = pnv_eeh_get_log, + .configure_bridge = pnv_eeh_configure_bridge, + .err_inject = pnv_eeh_err_inject, + .read_config = pnv_eeh_read_config, + .write_config = pnv_eeh_write_config, + .next_error = pnv_eeh_next_error, + .restore_config = pnv_eeh_restore_config }; /** @@ -521,7 +521,7 @@ static int __init eeh_powernv_init(void) int ret = -EINVAL; eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE); - ret = eeh_ops_register(&powernv_eeh_ops); + ret = eeh_ops_register(&pnv_eeh_ops); if (!ret) pr_info("EEH: PowerNV platform initialized\n"); else -- GitLab From fa646c3cab032caf94184aef728d7275164c437e Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:40 +1100 Subject: [PATCH 0401/1910] powerpc/powernv: Drop PHB operation err_inject() The patch drops PHB EEH operation err_inject() and merge its logic to eeh_ops::err_inject(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 49 +------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 38 +++++++++++++-- arch/powerpc/platforms/powernv/pci.h | 2 - 3 files changed, 36 insertions(+), 53 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 2809c9895288..dd154cf98085 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -70,7 +70,6 @@ static ssize_t ioda_eeh_ei_write(struct file *filp, size_t count, loff_t *ppos) { struct pci_controller *hose = filp->private_data; - struct pnv_phb *phb = hose->private_data; struct eeh_dev *edev; struct eeh_pe *pe; int pe_no, type, func; @@ -78,7 +77,7 @@ static ssize_t ioda_eeh_ei_write(struct file *filp, char buf[50]; int ret; - if (!phb->eeh_ops || !phb->eeh_ops->err_inject) + if (!eeh_ops || !eeh_ops->err_inject) return -ENXIO; ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); @@ -103,7 +102,7 @@ static ssize_t ioda_eeh_ei_write(struct file *filp, return -ENODEV; /* Do error injection */ - ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask); + ret = eeh_ops->err_inject(pe, type, func, addr, mask); return ret < 0 ? ret : count; } @@ -756,49 +755,6 @@ static int ioda_eeh_configure_bridge(struct eeh_pe *pe) return 0; } -static int ioda_eeh_err_inject(struct eeh_pe *pe, int type, int func, - unsigned long addr, unsigned long mask) -{ - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - s64 ret; - - /* Sanity check on error type */ - if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR && - type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) { - pr_warn("%s: Invalid error type %d\n", - __func__, type); - return -ERANGE; - } - - if (func < OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR || - func > OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET) { - pr_warn("%s: Invalid error function %d\n", - __func__, func); - return -ERANGE; - } - - /* Firmware supports error injection ? */ - if (!opal_check_token(OPAL_PCI_ERR_INJECT)) { - pr_warn("%s: Firmware doesn't support error injection\n", - __func__); - return -ENXIO; - } - - /* Do error injection */ - ret = opal_pci_err_inject(phb->opal_id, pe->addr, - type, func, addr, mask); - if (ret != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld injecting error " - "%d-%d to PHB#%x-PE#%x\n", - __func__, ret, type, func, - hose->global_number, pe->addr); - return -EIO; - } - - return 0; -} - static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data) { /* GEM */ @@ -1144,6 +1100,5 @@ struct pnv_eeh_ops ioda_eeh_ops = { .reset = ioda_eeh_reset, .get_log = ioda_eeh_get_log, .configure_bridge = ioda_eeh_configure_bridge, - .err_inject = ioda_eeh_err_inject, .next_error = ioda_eeh_next_error }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index f562dd1a99cc..df33daab381c 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -406,12 +406,42 @@ static int pnv_eeh_err_inject(struct eeh_pe *pe, int type, int func, { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; - int ret = -EEXIST; + s64 rc; + + /* Sanity check on error type */ + if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR && + type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) { + pr_warn("%s: Invalid error type %d\n", + __func__, type); + return -ERANGE; + } - if (phb->eeh_ops && phb->eeh_ops->err_inject) - ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask); + if (func < OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR || + func > OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET) { + pr_warn("%s: Invalid error function %d\n", + __func__, func); + return -ERANGE; + } - return ret; + /* Firmware supports error injection ? */ + if (!opal_check_token(OPAL_PCI_ERR_INJECT)) { + pr_warn("%s: Firmware doesn't support error injection\n", + __func__); + return -ENXIO; + } + + /* Do error injection */ + rc = opal_pci_err_inject(phb->opal_id, pe->addr, + type, func, addr, mask); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld injecting error " + "%d-%d to PHB#%x-PE#%x\n", + __func__, rc, type, func, + hose->global_number, pe->addr); + return -EIO; + } + + return 0; } static inline bool pnv_eeh_cfg_blocked(struct device_node *dn) diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 6c02ff8dd69f..a9f236229fe0 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -85,8 +85,6 @@ struct pnv_eeh_ops { int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len); int (*configure_bridge)(struct eeh_pe *pe); - int (*err_inject)(struct eeh_pe *pe, int type, int func, - unsigned long addr, unsigned long mask); int (*next_error)(struct eeh_pe **pe); }; #endif /* CONFIG_EEH */ -- GitLab From 4cf17445589932155797444687dca1ef2dd47f10 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:41 +1100 Subject: [PATCH 0402/1910] powerpc/powernv: Drop PHB operation post_init() The patch drops PHB EEH operation post_init() and merge its logic to eeh_ops::post_init(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 193 ------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 184 +++++++++++++++++- arch/powerpc/platforms/powernv/pci.h | 1 - 3 files changed, 179 insertions(+), 199 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index dd154cf98085..bd509ad08211 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -34,198 +34,6 @@ #include "powernv.h" #include "pci.h" -static int ioda_eeh_nb_init = 0; - -static int ioda_eeh_event(struct notifier_block *nb, - unsigned long events, void *change) -{ - uint64_t changed_evts = (uint64_t)change; - - /* - * We simply send special EEH event if EEH has - * been enabled, or clear pending events in - * case that we enable EEH soon - */ - if (!(changed_evts & OPAL_EVENT_PCI_ERROR) || - !(events & OPAL_EVENT_PCI_ERROR)) - return 0; - - if (eeh_enabled()) - eeh_send_failure_event(NULL); - else - opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); - - return 0; -} - -static struct notifier_block ioda_eeh_nb = { - .notifier_call = ioda_eeh_event, - .next = NULL, - .priority = 0 -}; - -#ifdef CONFIG_DEBUG_FS -static ssize_t ioda_eeh_ei_write(struct file *filp, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct pci_controller *hose = filp->private_data; - struct eeh_dev *edev; - struct eeh_pe *pe; - int pe_no, type, func; - unsigned long addr, mask; - char buf[50]; - int ret; - - if (!eeh_ops || !eeh_ops->err_inject) - return -ENXIO; - - ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); - if (!ret) - return -EFAULT; - - /* Retrieve parameters */ - ret = sscanf(buf, "%x:%x:%x:%lx:%lx", - &pe_no, &type, &func, &addr, &mask); - if (ret != 5) - return -EINVAL; - - /* Retrieve PE */ - edev = kzalloc(sizeof(*edev), GFP_KERNEL); - if (!edev) - return -ENOMEM; - edev->phb = hose; - edev->pe_config_addr = pe_no; - pe = eeh_pe_get(edev); - kfree(edev); - if (!pe) - return -ENODEV; - - /* Do error injection */ - ret = eeh_ops->err_inject(pe, type, func, addr, mask); - return ret < 0 ? ret : count; -} - -static const struct file_operations ioda_eeh_ei_fops = { - .open = simple_open, - .llseek = no_llseek, - .write = ioda_eeh_ei_write, -}; - -static int ioda_eeh_dbgfs_set(void *data, int offset, u64 val) -{ - struct pci_controller *hose = data; - struct pnv_phb *phb = hose->private_data; - - out_be64(phb->regs + offset, val); - return 0; -} - -static int ioda_eeh_dbgfs_get(void *data, int offset, u64 *val) -{ - struct pci_controller *hose = data; - struct pnv_phb *phb = hose->private_data; - - *val = in_be64(phb->regs + offset); - return 0; -} - -static int ioda_eeh_outb_dbgfs_set(void *data, u64 val) -{ - return ioda_eeh_dbgfs_set(data, 0xD10, val); -} - -static int ioda_eeh_outb_dbgfs_get(void *data, u64 *val) -{ - return ioda_eeh_dbgfs_get(data, 0xD10, val); -} - -static int ioda_eeh_inbA_dbgfs_set(void *data, u64 val) -{ - return ioda_eeh_dbgfs_set(data, 0xD90, val); -} - -static int ioda_eeh_inbA_dbgfs_get(void *data, u64 *val) -{ - return ioda_eeh_dbgfs_get(data, 0xD90, val); -} - -static int ioda_eeh_inbB_dbgfs_set(void *data, u64 val) -{ - return ioda_eeh_dbgfs_set(data, 0xE10, val); -} - -static int ioda_eeh_inbB_dbgfs_get(void *data, u64 *val) -{ - return ioda_eeh_dbgfs_get(data, 0xE10, val); -} - -DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_outb_dbgfs_ops, ioda_eeh_outb_dbgfs_get, - ioda_eeh_outb_dbgfs_set, "0x%llx\n"); -DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbA_dbgfs_ops, ioda_eeh_inbA_dbgfs_get, - ioda_eeh_inbA_dbgfs_set, "0x%llx\n"); -DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get, - ioda_eeh_inbB_dbgfs_set, "0x%llx\n"); -#endif /* CONFIG_DEBUG_FS */ - - -/** - * ioda_eeh_post_init - Chip dependent post initialization - * @hose: PCI controller - * - * The function will be called after eeh PEs and devices - * have been built. That means the EEH is ready to supply - * service with I/O cache. - */ -static int ioda_eeh_post_init(struct pci_controller *hose) -{ - struct pnv_phb *phb = hose->private_data; - int ret; - - /* Register OPAL event notifier */ - if (!ioda_eeh_nb_init) { - ret = opal_notifier_register(&ioda_eeh_nb); - if (ret) { - pr_err("%s: Can't register OPAL event notifier (%d)\n", - __func__, ret); - return ret; - } - - ioda_eeh_nb_init = 1; - } - -#ifdef CONFIG_DEBUG_FS - if (!phb->has_dbgfs && phb->dbgfs) { - phb->has_dbgfs = 1; - - debugfs_create_file("err_injct", 0200, - phb->dbgfs, hose, - &ioda_eeh_ei_fops); - - debugfs_create_file("err_injct_outbound", 0600, - phb->dbgfs, hose, - &ioda_eeh_outb_dbgfs_ops); - debugfs_create_file("err_injct_inboundA", 0600, - phb->dbgfs, hose, - &ioda_eeh_inbA_dbgfs_ops); - debugfs_create_file("err_injct_inboundB", 0600, - phb->dbgfs, hose, - &ioda_eeh_inbB_dbgfs_ops); - } -#endif - - /* If EEH is enabled, we're going to rely on that. - * Otherwise, we restore to conventional mechanism - * to clear frozen PE during PCI config access. - */ - if (eeh_enabled()) - phb->flags |= PNV_PHB_FLAG_EEH; - else - phb->flags &= ~PNV_PHB_FLAG_EEH; - - return 0; -} - /** * ioda_eeh_set_option - Set EEH operation or I/O setting * @pe: EEH PE @@ -1094,7 +902,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) } struct pnv_eeh_ops ioda_eeh_ops = { - .post_init = ioda_eeh_post_init, .set_option = ioda_eeh_set_option, .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index df33daab381c..641ba3378ccf 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -38,6 +39,8 @@ #include "powernv.h" #include "pci.h" +static bool pnv_eeh_nb_init = false; + /** * pnv_eeh_init - EEH platform dependent initialization * @@ -85,6 +88,139 @@ static int pnv_eeh_init(void) return 0; } +static int pnv_eeh_event(struct notifier_block *nb, + unsigned long events, void *change) +{ + uint64_t changed_evts = (uint64_t)change; + + /* + * We simply send special EEH event if EEH has + * been enabled, or clear pending events in + * case that we enable EEH soon + */ + if (!(changed_evts & OPAL_EVENT_PCI_ERROR) || + !(events & OPAL_EVENT_PCI_ERROR)) + return 0; + + if (eeh_enabled()) + eeh_send_failure_event(NULL); + else + opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); + + return 0; +} + +static struct notifier_block pnv_eeh_nb = { + .notifier_call = pnv_eeh_event, + .next = NULL, + .priority = 0 +}; + +#ifdef CONFIG_DEBUG_FS +static ssize_t pnv_eeh_ei_write(struct file *filp, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct pci_controller *hose = filp->private_data; + struct eeh_dev *edev; + struct eeh_pe *pe; + int pe_no, type, func; + unsigned long addr, mask; + char buf[50]; + int ret; + + if (!eeh_ops || !eeh_ops->err_inject) + return -ENXIO; + + /* Copy over argument buffer */ + ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); + if (!ret) + return -EFAULT; + + /* Retrieve parameters */ + ret = sscanf(buf, "%x:%x:%x:%lx:%lx", + &pe_no, &type, &func, &addr, &mask); + if (ret != 5) + return -EINVAL; + + /* Retrieve PE */ + edev = kzalloc(sizeof(*edev), GFP_KERNEL); + if (!edev) + return -ENOMEM; + edev->phb = hose; + edev->pe_config_addr = pe_no; + pe = eeh_pe_get(edev); + kfree(edev); + if (!pe) + return -ENODEV; + + /* Do error injection */ + ret = eeh_ops->err_inject(pe, type, func, addr, mask); + return ret < 0 ? ret : count; +} + +static const struct file_operations pnv_eeh_ei_fops = { + .open = simple_open, + .llseek = no_llseek, + .write = pnv_eeh_ei_write, +}; + +static int pnv_eeh_dbgfs_set(void *data, int offset, u64 val) +{ + struct pci_controller *hose = data; + struct pnv_phb *phb = hose->private_data; + + out_be64(phb->regs + offset, val); + return 0; +} + +static int pnv_eeh_dbgfs_get(void *data, int offset, u64 *val) +{ + struct pci_controller *hose = data; + struct pnv_phb *phb = hose->private_data; + + *val = in_be64(phb->regs + offset); + return 0; +} + +static int pnv_eeh_outb_dbgfs_set(void *data, u64 val) +{ + return pnv_eeh_dbgfs_set(data, 0xD10, val); +} + +static int pnv_eeh_outb_dbgfs_get(void *data, u64 *val) +{ + return pnv_eeh_dbgfs_get(data, 0xD10, val); +} + +static int pnv_eeh_inbA_dbgfs_set(void *data, u64 val) +{ + return pnv_eeh_dbgfs_set(data, 0xD90, val); +} + +static int pnv_eeh_inbA_dbgfs_get(void *data, u64 *val) +{ + return pnv_eeh_dbgfs_get(data, 0xD90, val); +} + +static int pnv_eeh_inbB_dbgfs_set(void *data, u64 val) +{ + return pnv_eeh_dbgfs_set(data, 0xE10, val); +} + +static int pnv_eeh_inbB_dbgfs_get(void *data, u64 *val) +{ + return pnv_eeh_dbgfs_get(data, 0xE10, val); +} + +DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_outb_dbgfs_ops, pnv_eeh_outb_dbgfs_get, + pnv_eeh_outb_dbgfs_set, "0x%llx\n"); +DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbA_dbgfs_ops, pnv_eeh_inbA_dbgfs_get, + pnv_eeh_inbA_dbgfs_set, "0x%llx\n"); +DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbB_dbgfs_ops, pnv_eeh_inbB_dbgfs_get, + pnv_eeh_inbB_dbgfs_set, "0x%llx\n"); +#endif /* CONFIG_DEBUG_FS */ + /** * pnv_eeh_post_init - EEH platform dependent post initialization * @@ -99,16 +235,54 @@ static int pnv_eeh_post_init(void) struct pnv_phb *phb; int ret = 0; + /* Register OPAL event notifier */ + if (!pnv_eeh_nb_init) { + ret = opal_notifier_register(&pnv_eeh_nb); + if (ret) { + pr_warn("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + + pnv_eeh_nb_init = true; + } + list_for_each_entry(hose, &hose_list, list_node) { phb = hose->private_data; - if (phb->eeh_ops && phb->eeh_ops->post_init) { - ret = phb->eeh_ops->post_init(hose); - if (ret) - break; - } + /* + * If EEH is enabled, we're going to rely on that. + * Otherwise, we restore to conventional mechanism + * to clear frozen PE during PCI config access. + */ + if (eeh_enabled()) + phb->flags |= PNV_PHB_FLAG_EEH; + else + phb->flags &= ~PNV_PHB_FLAG_EEH; + + /* Create debugfs entries */ +#ifdef CONFIG_DEBUG_FS + if (phb->has_dbgfs || !phb->dbgfs) + continue; + + phb->has_dbgfs = 1; + debugfs_create_file("err_injct", 0200, + phb->dbgfs, hose, + &pnv_eeh_ei_fops); + + debugfs_create_file("err_injct_outbound", 0600, + phb->dbgfs, hose, + &pnv_eeh_outb_dbgfs_ops); + debugfs_create_file("err_injct_inboundA", 0600, + phb->dbgfs, hose, + &pnv_eeh_inbA_dbgfs_ops); + debugfs_create_file("err_injct_inboundB", 0600, + phb->dbgfs, hose, + &pnv_eeh_inbB_dbgfs_ops); +#endif /* CONFIG_DEBUG_FS */ } + return ret; } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index a9f236229fe0..c7e047f19528 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -78,7 +78,6 @@ struct pnv_ioda_pe { /* IOC dependent EEH operations */ #ifdef CONFIG_EEH struct pnv_eeh_ops { - int (*post_init)(struct pci_controller *hose); int (*set_option)(struct eeh_pe *pe, int option); int (*get_state)(struct eeh_pe *pe); int (*reset)(struct eeh_pe *pe, int option); -- GitLab From 95edcdeadf1e838c7d6f1ef43194128d823c61a1 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:42 +1100 Subject: [PATCH 0403/1910] powerpc/powernv: Drop PHB operation get_log() The patch drops PHB operation get_log() and merges its logic to eeh_ops::get_log(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 20 -------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 10 +++------- arch/powerpc/platforms/powernv/pci.h | 2 -- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index bd509ad08211..7eb6e724fbc9 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -530,25 +530,6 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) return ret; } -/** - * ioda_eeh_get_log - Retrieve error log - * @pe: frozen PE - * @severity: permanent or temporary error - * @drv_log: device driver log - * @len: length of device driver log - * - * Retrieve error log, which contains log from device driver - * and firmware. - */ -static int ioda_eeh_get_log(struct eeh_pe *pe, int severity, - char *drv_log, unsigned long len) -{ - if (!eeh_has_flag(EEH_EARLY_DUMP_LOG)) - pnv_pci_dump_phb_diag_data(pe->phb, pe->data); - - return 0; -} - /** * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE * @pe: EEH PE @@ -905,7 +886,6 @@ struct pnv_eeh_ops ioda_eeh_ops = { .set_option = ioda_eeh_set_option, .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, - .get_log = ioda_eeh_get_log, .configure_bridge = ioda_eeh_configure_bridge, .next_error = ioda_eeh_next_error }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 641ba3378ccf..465deb5f5f46 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -533,14 +533,10 @@ static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait) static int pnv_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len) { - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - int ret = -EEXIST; + if (!eeh_has_flag(EEH_EARLY_DUMP_LOG)) + pnv_pci_dump_phb_diag_data(pe->phb, pe->data); - if (phb->eeh_ops && phb->eeh_ops->get_log) - ret = phb->eeh_ops->get_log(pe, severity, drv_log, len); - - return ret; + return 0; } /** diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index c7e047f19528..1e7a623cbff4 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -81,8 +81,6 @@ struct pnv_eeh_ops { int (*set_option)(struct eeh_pe *pe, int option); int (*get_state)(struct eeh_pe *pe); int (*reset)(struct eeh_pe *pe, int option); - int (*get_log)(struct eeh_pe *pe, int severity, - char *drv_log, unsigned long len); int (*configure_bridge)(struct eeh_pe *pe); int (*next_error)(struct eeh_pe **pe); }; -- GitLab From bbe170ede15b3b33361b95497fb164909b45ffa9 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:43 +1100 Subject: [PATCH 0404/1910] powerpc/powernv: Drop PHB operation configure_bridge() The patch drops PHB EEH operation configure_bridge() and merges its logic to eeh_ops::configure_bridge(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 15 --------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 9 +-------- arch/powerpc/platforms/powernv/pci.h | 1 - 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 7eb6e724fbc9..645951639b01 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -530,20 +530,6 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) return ret; } -/** - * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE - * @pe: EEH PE - * - * For particular PE, it might have included PCI bridges. In order - * to make the PE work properly, those PCI bridges should be configured - * correctly. However, we need do nothing on P7IOC since the reset - * function will do everything that should be covered by the function. - */ -static int ioda_eeh_configure_bridge(struct eeh_pe *pe) -{ - return 0; -} - static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data) { /* GEM */ @@ -886,6 +872,5 @@ struct pnv_eeh_ops ioda_eeh_ops = { .set_option = ioda_eeh_set_option, .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, - .configure_bridge = ioda_eeh_configure_bridge, .next_error = ioda_eeh_next_error }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 465deb5f5f46..a7087f4a739a 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -549,14 +549,7 @@ static int pnv_eeh_get_log(struct eeh_pe *pe, int severity, */ static int pnv_eeh_configure_bridge(struct eeh_pe *pe) { - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - int ret = 0; - - if (phb->eeh_ops && phb->eeh_ops->configure_bridge) - ret = phb->eeh_ops->configure_bridge(pe); - - return ret; + return 0; } /** diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 1e7a623cbff4..d8808caf19f2 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -81,7 +81,6 @@ struct pnv_eeh_ops { int (*set_option)(struct eeh_pe *pe, int option); int (*get_state)(struct eeh_pe *pe); int (*reset)(struct eeh_pe *pe, int option); - int (*configure_bridge)(struct eeh_pe *pe); int (*next_error)(struct eeh_pe **pe); }; #endif /* CONFIG_EEH */ -- GitLab From 7e3e4f8d5e80d2321cb1ab58a2070fbf28883ec1 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:44 +1100 Subject: [PATCH 0405/1910] powerpc/powernv: Drop PHB operation set_option() The patch drops PHB EEH operation set_option() and merges its logic to eeh_ops::set_option(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 84 -------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 61 ++++++++++++-- arch/powerpc/platforms/powernv/pci.h | 1 - 3 files changed, 54 insertions(+), 92 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 645951639b01..349c0830f535 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -34,89 +34,6 @@ #include "powernv.h" #include "pci.h" -/** - * ioda_eeh_set_option - Set EEH operation or I/O setting - * @pe: EEH PE - * @option: options - * - * Enable or disable EEH option for the indicated PE. The - * function also can be used to enable I/O or DMA for the - * PE. - */ -static int ioda_eeh_set_option(struct eeh_pe *pe, int option) -{ - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - bool freeze_pe = false; - int enable, ret = 0; - s64 rc; - - /* Check on PE number */ - if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) { - pr_err("%s: PE address %x out of range [0, %x] " - "on PHB#%x\n", - __func__, pe->addr, phb->ioda.total_pe, - hose->global_number); - return -EINVAL; - } - - switch (option) { - case EEH_OPT_DISABLE: - return -EPERM; - case EEH_OPT_ENABLE: - return 0; - case EEH_OPT_THAW_MMIO: - enable = OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO; - break; - case EEH_OPT_THAW_DMA: - enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA; - break; - case EEH_OPT_FREEZE_PE: - freeze_pe = true; - enable = OPAL_EEH_ACTION_SET_FREEZE_ALL; - break; - default: - pr_warn("%s: Invalid option %d\n", - __func__, option); - return -EINVAL; - } - - /* If PHB supports compound PE, to handle it */ - if (freeze_pe) { - if (phb->freeze_pe) { - phb->freeze_pe(phb, pe->addr); - } else { - rc = opal_pci_eeh_freeze_set(phb->opal_id, - pe->addr, - enable); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld freezing " - "PHB#%x-PE#%x\n", - __func__, rc, - phb->hose->global_number, pe->addr); - ret = -EIO; - } - } - } else { - if (phb->unfreeze_pe) { - ret = phb->unfreeze_pe(phb, pe->addr, enable); - } else { - rc = opal_pci_eeh_freeze_clear(phb->opal_id, - pe->addr, - enable); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld enable %d " - "for PHB#%x-PE#%x\n", - __func__, rc, option, - phb->hose->global_number, pe->addr); - ret = -EIO; - } - } - } - - return ret; -} - static void ioda_eeh_phb_diag(struct eeh_pe *pe) { struct pnv_phb *phb = pe->phb->private_data; @@ -869,7 +786,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) } struct pnv_eeh_ops ioda_eeh_ops = { - .set_option = ioda_eeh_set_option, .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, .next_error = ioda_eeh_next_error diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index a7087f4a739a..2429a23d4802 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -407,14 +407,61 @@ static int pnv_eeh_set_option(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; struct pnv_phb *phb = hose->private_data; - int ret = -EEXIST; + bool freeze_pe = false; + int opt, ret = 0; + s64 rc; - /* - * What we need do is pass it down for hardware - * implementation to handle it. - */ - if (phb->eeh_ops && phb->eeh_ops->set_option) - ret = phb->eeh_ops->set_option(pe, option); + /* Sanity check on option */ + switch (option) { + case EEH_OPT_DISABLE: + return -EPERM; + case EEH_OPT_ENABLE: + return 0; + case EEH_OPT_THAW_MMIO: + opt = OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO; + break; + case EEH_OPT_THAW_DMA: + opt = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA; + break; + case EEH_OPT_FREEZE_PE: + freeze_pe = true; + opt = OPAL_EEH_ACTION_SET_FREEZE_ALL; + break; + default: + pr_warn("%s: Invalid option %d\n", __func__, option); + return -EINVAL; + } + + /* If PHB supports compound PE, to handle it */ + if (freeze_pe) { + if (phb->freeze_pe) { + phb->freeze_pe(phb, pe->addr); + } else { + rc = opal_pci_eeh_freeze_set(phb->opal_id, + pe->addr, opt); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld freezing " + "PHB#%x-PE#%x\n", + __func__, rc, + phb->hose->global_number, pe->addr); + ret = -EIO; + } + } + } else { + if (phb->unfreeze_pe) { + ret = phb->unfreeze_pe(phb, pe->addr, opt); + } else { + rc = opal_pci_eeh_freeze_clear(phb->opal_id, + pe->addr, opt); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld enable %d " + "for PHB#%x-PE#%x\n", + __func__, rc, option, + phb->hose->global_number, pe->addr); + ret = -EIO; + } + } + } return ret; } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index d8808caf19f2..8043dee64a51 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -78,7 +78,6 @@ struct pnv_ioda_pe { /* IOC dependent EEH operations */ #ifdef CONFIG_EEH struct pnv_eeh_ops { - int (*set_option)(struct eeh_pe *pe, int option); int (*get_state)(struct eeh_pe *pe); int (*reset)(struct eeh_pe *pe, int option); int (*next_error)(struct eeh_pe **pe); -- GitLab From 40ae5f693f6ada75e0f2680872dd0bf52bce22c4 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:45 +1100 Subject: [PATCH 0406/1910] powerpc/powernv: Drop PHB operation get_state() The patch drops PHB EEH operation get_state() and merges its logic to eeh_ops::get_state(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 170 +---------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 185 +++++++++++++++++-- arch/powerpc/platforms/powernv/pci.h | 1 - 3 files changed, 170 insertions(+), 186 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 349c0830f535..dc34c36805dc 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -46,173 +46,6 @@ static void ioda_eeh_phb_diag(struct eeh_pe *pe) __func__, pe->phb->global_number, rc); } -static int ioda_eeh_get_phb_state(struct eeh_pe *pe) -{ - struct pnv_phb *phb = pe->phb->private_data; - u8 fstate; - __be16 pcierr; - s64 rc; - int result = 0; - - rc = opal_pci_eeh_freeze_status(phb->opal_id, - pe->addr, - &fstate, - &pcierr, - NULL); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld getting PHB#%x state\n", - __func__, rc, phb->hose->global_number); - return EEH_STATE_NOT_SUPPORT; - } - - /* - * Check PHB state. If the PHB is frozen for the - * first time, to dump the PHB diag-data. - */ - if (be16_to_cpu(pcierr) != OPAL_EEH_PHB_ERROR) { - result = (EEH_STATE_MMIO_ACTIVE | - EEH_STATE_DMA_ACTIVE | - EEH_STATE_MMIO_ENABLED | - EEH_STATE_DMA_ENABLED); - } else if (!(pe->state & EEH_PE_ISOLATED)) { - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); - ioda_eeh_phb_diag(pe); - - if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) - pnv_pci_dump_phb_diag_data(pe->phb, pe->data); - } - - return result; -} - -static int ioda_eeh_get_pe_state(struct eeh_pe *pe) -{ - struct pnv_phb *phb = pe->phb->private_data; - u8 fstate; - __be16 pcierr; - s64 rc; - int result; - - /* - * We don't clobber hardware frozen state until PE - * reset is completed. In order to keep EEH core - * moving forward, we have to return operational - * state during PE reset. - */ - if (pe->state & EEH_PE_RESET) { - result = (EEH_STATE_MMIO_ACTIVE | - EEH_STATE_DMA_ACTIVE | - EEH_STATE_MMIO_ENABLED | - EEH_STATE_DMA_ENABLED); - return result; - } - - /* - * Fetch PE state from hardware. If the PHB - * supports compound PE, let it handle that. - */ - if (phb->get_pe_state) { - fstate = phb->get_pe_state(phb, pe->addr); - } else { - rc = opal_pci_eeh_freeze_status(phb->opal_id, - pe->addr, - &fstate, - &pcierr, - NULL); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld getting PHB#%x-PE%x state\n", - __func__, rc, phb->hose->global_number, pe->addr); - return EEH_STATE_NOT_SUPPORT; - } - } - - /* Figure out state */ - switch (fstate) { - case OPAL_EEH_STOPPED_NOT_FROZEN: - result = (EEH_STATE_MMIO_ACTIVE | - EEH_STATE_DMA_ACTIVE | - EEH_STATE_MMIO_ENABLED | - EEH_STATE_DMA_ENABLED); - break; - case OPAL_EEH_STOPPED_MMIO_FREEZE: - result = (EEH_STATE_DMA_ACTIVE | - EEH_STATE_DMA_ENABLED); - break; - case OPAL_EEH_STOPPED_DMA_FREEZE: - result = (EEH_STATE_MMIO_ACTIVE | - EEH_STATE_MMIO_ENABLED); - break; - case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE: - result = 0; - break; - case OPAL_EEH_STOPPED_RESET: - result = EEH_STATE_RESET_ACTIVE; - break; - case OPAL_EEH_STOPPED_TEMP_UNAVAIL: - result = EEH_STATE_UNAVAILABLE; - break; - case OPAL_EEH_STOPPED_PERM_UNAVAIL: - result = EEH_STATE_NOT_SUPPORT; - break; - default: - result = EEH_STATE_NOT_SUPPORT; - pr_warn("%s: Invalid PHB#%x-PE#%x state %x\n", - __func__, phb->hose->global_number, - pe->addr, fstate); - } - - /* - * If PHB supports compound PE, to freeze all - * slave PEs for consistency. - * - * If the PE is switching to frozen state for the - * first time, to dump the PHB diag-data. - */ - if (!(result & EEH_STATE_NOT_SUPPORT) && - !(result & EEH_STATE_UNAVAILABLE) && - !(result & EEH_STATE_MMIO_ACTIVE) && - !(result & EEH_STATE_DMA_ACTIVE) && - !(pe->state & EEH_PE_ISOLATED)) { - if (phb->freeze_pe) - phb->freeze_pe(phb, pe->addr); - - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); - ioda_eeh_phb_diag(pe); - - if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) - pnv_pci_dump_phb_diag_data(pe->phb, pe->data); - } - - return result; -} - -/** - * ioda_eeh_get_state - Retrieve the state of PE - * @pe: EEH PE - * - * The PE's state should be retrieved from the PEEV, PEST - * IODA tables. Since the OPAL has exported the function - * to do it, it'd better to use that. - */ -static int ioda_eeh_get_state(struct eeh_pe *pe) -{ - struct pnv_phb *phb = pe->phb->private_data; - - /* Sanity check on PE number. PHB PE should have 0 */ - if (pe->addr < 0 || - pe->addr >= phb->ioda.total_pe) { - pr_warn("%s: PHB#%x-PE#%x out of range [0, %x]\n", - __func__, phb->hose->global_number, - pe->addr, phb->ioda.total_pe); - return EEH_STATE_NOT_SUPPORT; - } - - if (pe->type & EEH_PE_PHB) - return ioda_eeh_get_phb_state(pe); - - return ioda_eeh_get_pe_state(pe); -} - static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) { s64 rc = OPAL_HARDWARE; @@ -759,7 +592,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) break; /* Frozen parent PE ? */ - state = ioda_eeh_get_state(parent_pe); + state = eeh_ops->get_state(parent_pe, NULL); if (state > 0 && (state & active_flags) != active_flags) *pe = parent_pe; @@ -786,7 +619,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) } struct pnv_eeh_ops ioda_eeh_ops = { - .get_state = ioda_eeh_get_state, .reset = ioda_eeh_reset, .next_error = ioda_eeh_next_error }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 2429a23d4802..127ef0cc7c5b 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -478,6 +478,159 @@ static int pnv_eeh_get_pe_addr(struct eeh_pe *pe) return pe->addr; } +static void pnv_eeh_get_phb_diag(struct eeh_pe *pe) +{ + struct pnv_phb *phb = pe->phb->private_data; + s64 rc; + + rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data, + PNV_PCI_DIAG_BUF_SIZE); + if (rc != OPAL_SUCCESS) + pr_warn("%s: Failure %lld getting PHB#%x diag-data\n", + __func__, rc, pe->phb->global_number); +} + +static int pnv_eeh_get_phb_state(struct eeh_pe *pe) +{ + struct pnv_phb *phb = pe->phb->private_data; + u8 fstate; + __be16 pcierr; + s64 rc; + int result = 0; + + rc = opal_pci_eeh_freeze_status(phb->opal_id, + pe->addr, + &fstate, + &pcierr, + NULL); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld getting PHB#%x state\n", + __func__, rc, phb->hose->global_number); + return EEH_STATE_NOT_SUPPORT; + } + + /* + * Check PHB state. If the PHB is frozen for the + * first time, to dump the PHB diag-data. + */ + if (be16_to_cpu(pcierr) != OPAL_EEH_PHB_ERROR) { + result = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_DMA_ACTIVE | + EEH_STATE_MMIO_ENABLED | + EEH_STATE_DMA_ENABLED); + } else if (!(pe->state & EEH_PE_ISOLATED)) { + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + pnv_eeh_get_phb_diag(pe); + + if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) + pnv_pci_dump_phb_diag_data(pe->phb, pe->data); + } + + return result; +} + +static int pnv_eeh_get_pe_state(struct eeh_pe *pe) +{ + struct pnv_phb *phb = pe->phb->private_data; + u8 fstate; + __be16 pcierr; + s64 rc; + int result; + + /* + * We don't clobber hardware frozen state until PE + * reset is completed. In order to keep EEH core + * moving forward, we have to return operational + * state during PE reset. + */ + if (pe->state & EEH_PE_RESET) { + result = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_DMA_ACTIVE | + EEH_STATE_MMIO_ENABLED | + EEH_STATE_DMA_ENABLED); + return result; + } + + /* + * Fetch PE state from hardware. If the PHB + * supports compound PE, let it handle that. + */ + if (phb->get_pe_state) { + fstate = phb->get_pe_state(phb, pe->addr); + } else { + rc = opal_pci_eeh_freeze_status(phb->opal_id, + pe->addr, + &fstate, + &pcierr, + NULL); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld getting PHB#%x-PE%x state\n", + __func__, rc, phb->hose->global_number, + pe->addr); + return EEH_STATE_NOT_SUPPORT; + } + } + + /* Figure out state */ + switch (fstate) { + case OPAL_EEH_STOPPED_NOT_FROZEN: + result = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_DMA_ACTIVE | + EEH_STATE_MMIO_ENABLED | + EEH_STATE_DMA_ENABLED); + break; + case OPAL_EEH_STOPPED_MMIO_FREEZE: + result = (EEH_STATE_DMA_ACTIVE | + EEH_STATE_DMA_ENABLED); + break; + case OPAL_EEH_STOPPED_DMA_FREEZE: + result = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_MMIO_ENABLED); + break; + case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE: + result = 0; + break; + case OPAL_EEH_STOPPED_RESET: + result = EEH_STATE_RESET_ACTIVE; + break; + case OPAL_EEH_STOPPED_TEMP_UNAVAIL: + result = EEH_STATE_UNAVAILABLE; + break; + case OPAL_EEH_STOPPED_PERM_UNAVAIL: + result = EEH_STATE_NOT_SUPPORT; + break; + default: + result = EEH_STATE_NOT_SUPPORT; + pr_warn("%s: Invalid PHB#%x-PE#%x state %x\n", + __func__, phb->hose->global_number, + pe->addr, fstate); + } + + /* + * If PHB supports compound PE, to freeze all + * slave PEs for consistency. + * + * If the PE is switching to frozen state for the + * first time, to dump the PHB diag-data. + */ + if (!(result & EEH_STATE_NOT_SUPPORT) && + !(result & EEH_STATE_UNAVAILABLE) && + !(result & EEH_STATE_MMIO_ACTIVE) && + !(result & EEH_STATE_DMA_ACTIVE) && + !(pe->state & EEH_PE_ISOLATED)) { + if (phb->freeze_pe) + phb->freeze_pe(phb, pe->addr); + + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + pnv_eeh_get_phb_diag(pe); + + if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) + pnv_pci_dump_phb_diag_data(pe->phb, pe->data); + } + + return result; +} + /** * pnv_eeh_get_state - Retrieve PE state * @pe: EEH PE @@ -490,24 +643,24 @@ static int pnv_eeh_get_pe_addr(struct eeh_pe *pe) */ static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay) { - struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - int ret = EEH_STATE_NOT_SUPPORT; + int ret; - if (phb->eeh_ops && phb->eeh_ops->get_state) { - ret = phb->eeh_ops->get_state(pe); + if (pe->type & EEH_PE_PHB) + ret = pnv_eeh_get_phb_state(pe); + else + ret = pnv_eeh_get_pe_state(pe); - /* - * If the PE state is temporarily unavailable, - * to inform the EEH core delay for default - * period (1 second) - */ - if (delay) { - *delay = 0; - if (ret & EEH_STATE_UNAVAILABLE) - *delay = 1000; - } - } + if (!delay) + return ret; + + /* + * If the PE state is temporarily unavailable, + * to inform the EEH core delay for default + * period (1 second) + */ + *delay = 0; + if (ret & EEH_STATE_UNAVAILABLE) + *delay = 1000; return ret; } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 8043dee64a51..773a026bfee2 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -78,7 +78,6 @@ struct pnv_ioda_pe { /* IOC dependent EEH operations */ #ifdef CONFIG_EEH struct pnv_eeh_ops { - int (*get_state)(struct eeh_pe *pe); int (*reset)(struct eeh_pe *pe, int option); int (*next_error)(struct eeh_pe **pe); }; -- GitLab From 2a485ad7c88ddfdf59bea12ece52b81adfd7c5a7 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:46 +1100 Subject: [PATCH 0407/1910] powerpc/powernv: Drop PHB operation next_error() The patch drops PHB EEH operation next_error() and merges its logic to eeh_ops::next_error(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 351 ------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 334 +++++++++++++++++- arch/powerpc/platforms/powernv/pci.h | 1 - 3 files changed, 327 insertions(+), 359 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index dc34c36805dc..94d94b4811ad 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -34,18 +34,6 @@ #include "powernv.h" #include "pci.h" -static void ioda_eeh_phb_diag(struct eeh_pe *pe) -{ - struct pnv_phb *phb = pe->phb->private_data; - long rc; - - rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data, - PNV_PCI_DIAG_BUF_SIZE); - if (rc != OPAL_SUCCESS) - pr_warn("%s: Failed to get diag-data for PHB#%x (%ld)\n", - __func__, pe->phb->global_number, rc); -} - static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) { s64 rc = OPAL_HARDWARE; @@ -280,345 +268,6 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) return ret; } -static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data) -{ - /* GEM */ - if (data->gemXfir || data->gemRfir || - data->gemRirqfir || data->gemMask || data->gemRwof) - pr_info(" GEM: %016llx %016llx %016llx %016llx %016llx\n", - be64_to_cpu(data->gemXfir), - be64_to_cpu(data->gemRfir), - be64_to_cpu(data->gemRirqfir), - be64_to_cpu(data->gemMask), - be64_to_cpu(data->gemRwof)); - - /* LEM */ - if (data->lemFir || data->lemErrMask || - data->lemAction0 || data->lemAction1 || data->lemWof) - pr_info(" LEM: %016llx %016llx %016llx %016llx %016llx\n", - be64_to_cpu(data->lemFir), - be64_to_cpu(data->lemErrMask), - be64_to_cpu(data->lemAction0), - be64_to_cpu(data->lemAction1), - be64_to_cpu(data->lemWof)); -} - -static void ioda_eeh_hub_diag(struct pci_controller *hose) -{ - struct pnv_phb *phb = hose->private_data; - struct OpalIoP7IOCErrorData *data = &phb->diag.hub_diag; - long rc; - - rc = opal_pci_get_hub_diag_data(phb->hub_id, data, sizeof(*data)); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failed to get HUB#%llx diag-data (%ld)\n", - __func__, phb->hub_id, rc); - return; - } - - switch (data->type) { - case OPAL_P7IOC_DIAG_TYPE_RGC: - pr_info("P7IOC diag-data for RGC\n\n"); - ioda_eeh_hub_diag_common(data); - if (data->rgc.rgcStatus || data->rgc.rgcLdcp) - pr_info(" RGC: %016llx %016llx\n", - be64_to_cpu(data->rgc.rgcStatus), - be64_to_cpu(data->rgc.rgcLdcp)); - break; - case OPAL_P7IOC_DIAG_TYPE_BI: - pr_info("P7IOC diag-data for BI %s\n\n", - data->bi.biDownbound ? "Downbound" : "Upbound"); - ioda_eeh_hub_diag_common(data); - if (data->bi.biLdcp0 || data->bi.biLdcp1 || - data->bi.biLdcp2 || data->bi.biFenceStatus) - pr_info(" BI: %016llx %016llx %016llx %016llx\n", - be64_to_cpu(data->bi.biLdcp0), - be64_to_cpu(data->bi.biLdcp1), - be64_to_cpu(data->bi.biLdcp2), - be64_to_cpu(data->bi.biFenceStatus)); - break; - case OPAL_P7IOC_DIAG_TYPE_CI: - pr_info("P7IOC diag-data for CI Port %d\n\n", - data->ci.ciPort); - ioda_eeh_hub_diag_common(data); - if (data->ci.ciPortStatus || data->ci.ciPortLdcp) - pr_info(" CI: %016llx %016llx\n", - be64_to_cpu(data->ci.ciPortStatus), - be64_to_cpu(data->ci.ciPortLdcp)); - break; - case OPAL_P7IOC_DIAG_TYPE_MISC: - pr_info("P7IOC diag-data for MISC\n\n"); - ioda_eeh_hub_diag_common(data); - break; - case OPAL_P7IOC_DIAG_TYPE_I2C: - pr_info("P7IOC diag-data for I2C\n\n"); - ioda_eeh_hub_diag_common(data); - break; - default: - pr_warn("%s: Invalid type of HUB#%llx diag-data (%d)\n", - __func__, phb->hub_id, data->type); - } -} - -static int ioda_eeh_get_pe(struct pci_controller *hose, - u16 pe_no, struct eeh_pe **pe) -{ - struct pnv_phb *phb = hose->private_data; - struct pnv_ioda_pe *pnv_pe; - struct eeh_pe *dev_pe; - struct eeh_dev edev; - - /* - * If PHB supports compound PE, to fetch - * the master PE because slave PE is invisible - * to EEH core. - */ - pnv_pe = &phb->ioda.pe_array[pe_no]; - if (pnv_pe->flags & PNV_IODA_PE_SLAVE) { - pnv_pe = pnv_pe->master; - WARN_ON(!pnv_pe || - !(pnv_pe->flags & PNV_IODA_PE_MASTER)); - pe_no = pnv_pe->pe_number; - } - - /* Find the PE according to PE# */ - memset(&edev, 0, sizeof(struct eeh_dev)); - edev.phb = hose; - edev.pe_config_addr = pe_no; - dev_pe = eeh_pe_get(&edev); - if (!dev_pe) - return -EEXIST; - - /* Freeze the (compound) PE */ - *pe = dev_pe; - if (!(dev_pe->state & EEH_PE_ISOLATED)) - phb->freeze_pe(phb, pe_no); - - /* - * At this point, we're sure the (compound) PE should - * have been frozen. However, we still need poke until - * hitting the frozen PE on top level. - */ - dev_pe = dev_pe->parent; - while (dev_pe && !(dev_pe->type & EEH_PE_PHB)) { - int ret; - int active_flags = (EEH_STATE_MMIO_ACTIVE | - EEH_STATE_DMA_ACTIVE); - - ret = eeh_ops->get_state(dev_pe, NULL); - if (ret <= 0 || (ret & active_flags) == active_flags) { - dev_pe = dev_pe->parent; - continue; - } - - /* Frozen parent PE */ - *pe = dev_pe; - if (!(dev_pe->state & EEH_PE_ISOLATED)) - phb->freeze_pe(phb, dev_pe->addr); - - /* Next one */ - dev_pe = dev_pe->parent; - } - - return 0; -} - -/** - * ioda_eeh_next_error - Retrieve next error for EEH core to handle - * @pe: The affected PE - * - * The function is expected to be called by EEH core while it gets - * special EEH event (without binding PE). The function calls to - * OPAL APIs for next error to handle. The informational error is - * handled internally by platform. However, the dead IOC, dead PHB, - * fenced PHB and frozen PE should be handled by EEH core eventually. - */ -static int ioda_eeh_next_error(struct eeh_pe **pe) -{ - struct pci_controller *hose; - struct pnv_phb *phb; - struct eeh_pe *phb_pe, *parent_pe; - __be64 frozen_pe_no; - __be16 err_type, severity; - int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); - long rc; - int state, ret = EEH_NEXT_ERR_NONE; - - /* - * While running here, it's safe to purge the event queue. - * And we should keep the cached OPAL notifier event sychronized - * between the kernel and firmware. - */ - eeh_remove_event(NULL, false); - opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); - - list_for_each_entry(hose, &hose_list, list_node) { - /* - * If the subordinate PCI buses of the PHB has been - * removed or is exactly under error recovery, we - * needn't take care of it any more. - */ - phb = hose->private_data; - phb_pe = eeh_phb_pe_get(hose); - if (!phb_pe || (phb_pe->state & EEH_PE_ISOLATED)) - continue; - - rc = opal_pci_next_error(phb->opal_id, - &frozen_pe_no, &err_type, &severity); - - /* If OPAL API returns error, we needn't proceed */ - if (rc != OPAL_SUCCESS) { - pr_devel("%s: Invalid return value on " - "PHB#%x (0x%lx) from opal_pci_next_error", - __func__, hose->global_number, rc); - continue; - } - - /* If the PHB doesn't have error, stop processing */ - if (be16_to_cpu(err_type) == OPAL_EEH_NO_ERROR || - be16_to_cpu(severity) == OPAL_EEH_SEV_NO_ERROR) { - pr_devel("%s: No error found on PHB#%x\n", - __func__, hose->global_number); - continue; - } - - /* - * Processing the error. We're expecting the error with - * highest priority reported upon multiple errors on the - * specific PHB. - */ - pr_devel("%s: Error (%d, %d, %llu) on PHB#%x\n", - __func__, be16_to_cpu(err_type), be16_to_cpu(severity), - be64_to_cpu(frozen_pe_no), hose->global_number); - switch (be16_to_cpu(err_type)) { - case OPAL_EEH_IOC_ERROR: - if (be16_to_cpu(severity) == OPAL_EEH_SEV_IOC_DEAD) { - pr_err("EEH: dead IOC detected\n"); - ret = EEH_NEXT_ERR_DEAD_IOC; - } else if (be16_to_cpu(severity) == OPAL_EEH_SEV_INF) { - pr_info("EEH: IOC informative error " - "detected\n"); - ioda_eeh_hub_diag(hose); - ret = EEH_NEXT_ERR_NONE; - } - - break; - case OPAL_EEH_PHB_ERROR: - if (be16_to_cpu(severity) == OPAL_EEH_SEV_PHB_DEAD) { - *pe = phb_pe; - pr_err("EEH: dead PHB#%x detected, " - "location: %s\n", - hose->global_number, - eeh_pe_loc_get(phb_pe)); - ret = EEH_NEXT_ERR_DEAD_PHB; - } else if (be16_to_cpu(severity) == - OPAL_EEH_SEV_PHB_FENCED) { - *pe = phb_pe; - pr_err("EEH: Fenced PHB#%x detected, " - "location: %s\n", - hose->global_number, - eeh_pe_loc_get(phb_pe)); - ret = EEH_NEXT_ERR_FENCED_PHB; - } else if (be16_to_cpu(severity) == OPAL_EEH_SEV_INF) { - pr_info("EEH: PHB#%x informative error " - "detected, location: %s\n", - hose->global_number, - eeh_pe_loc_get(phb_pe)); - ioda_eeh_phb_diag(phb_pe); - pnv_pci_dump_phb_diag_data(hose, phb_pe->data); - ret = EEH_NEXT_ERR_NONE; - } - - break; - case OPAL_EEH_PE_ERROR: - /* - * If we can't find the corresponding PE, we - * just try to unfreeze. - */ - if (ioda_eeh_get_pe(hose, - be64_to_cpu(frozen_pe_no), pe)) { - /* Try best to clear it */ - pr_info("EEH: Clear non-existing PHB#%x-PE#%llx\n", - hose->global_number, frozen_pe_no); - pr_info("EEH: PHB location: %s\n", - eeh_pe_loc_get(phb_pe)); - opal_pci_eeh_freeze_clear(phb->opal_id, frozen_pe_no, - OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); - ret = EEH_NEXT_ERR_NONE; - } else if ((*pe)->state & EEH_PE_ISOLATED || - eeh_pe_passed(*pe)) { - ret = EEH_NEXT_ERR_NONE; - } else { - pr_err("EEH: Frozen PE#%x on PHB#%x detected\n", - (*pe)->addr, (*pe)->phb->global_number); - pr_err("EEH: PE location: %s, PHB location: %s\n", - eeh_pe_loc_get(*pe), eeh_pe_loc_get(phb_pe)); - ret = EEH_NEXT_ERR_FROZEN_PE; - } - - break; - default: - pr_warn("%s: Unexpected error type %d\n", - __func__, be16_to_cpu(err_type)); - } - - /* - * EEH core will try recover from fenced PHB or - * frozen PE. In the time for frozen PE, EEH core - * enable IO path for that before collecting logs, - * but it ruins the site. So we have to dump the - * log in advance here. - */ - if ((ret == EEH_NEXT_ERR_FROZEN_PE || - ret == EEH_NEXT_ERR_FENCED_PHB) && - !((*pe)->state & EEH_PE_ISOLATED)) { - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); - ioda_eeh_phb_diag(*pe); - - if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) - pnv_pci_dump_phb_diag_data((*pe)->phb, - (*pe)->data); - } - - /* - * We probably have the frozen parent PE out there and - * we need have to handle frozen parent PE firstly. - */ - if (ret == EEH_NEXT_ERR_FROZEN_PE) { - parent_pe = (*pe)->parent; - while (parent_pe) { - /* Hit the ceiling ? */ - if (parent_pe->type & EEH_PE_PHB) - break; - - /* Frozen parent PE ? */ - state = eeh_ops->get_state(parent_pe, NULL); - if (state > 0 && - (state & active_flags) != active_flags) - *pe = parent_pe; - - /* Next parent level */ - parent_pe = parent_pe->parent; - } - - /* We possibly migrate to another PE */ - eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); - } - - /* - * If we have no errors on the specific PHB or only - * informative error there, we continue poking it. - * Otherwise, we need actions to be taken by upper - * layer. - */ - if (ret > EEH_NEXT_ERR_INF) - break; - } - - return ret; -} - struct pnv_eeh_ops ioda_eeh_ops = { .reset = ioda_eeh_reset, - .next_error = ioda_eeh_next_error }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 127ef0cc7c5b..e51ac2dfde50 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -840,26 +840,346 @@ static int pnv_eeh_write_config(struct device_node *dn, return pnv_pci_cfg_write(dn, where, size, val); } +static void pnv_eeh_dump_hub_diag_common(struct OpalIoP7IOCErrorData *data) +{ + /* GEM */ + if (data->gemXfir || data->gemRfir || + data->gemRirqfir || data->gemMask || data->gemRwof) + pr_info(" GEM: %016llx %016llx %016llx %016llx %016llx\n", + be64_to_cpu(data->gemXfir), + be64_to_cpu(data->gemRfir), + be64_to_cpu(data->gemRirqfir), + be64_to_cpu(data->gemMask), + be64_to_cpu(data->gemRwof)); + + /* LEM */ + if (data->lemFir || data->lemErrMask || + data->lemAction0 || data->lemAction1 || data->lemWof) + pr_info(" LEM: %016llx %016llx %016llx %016llx %016llx\n", + be64_to_cpu(data->lemFir), + be64_to_cpu(data->lemErrMask), + be64_to_cpu(data->lemAction0), + be64_to_cpu(data->lemAction1), + be64_to_cpu(data->lemWof)); +} + +static void pnv_eeh_get_and_dump_hub_diag(struct pci_controller *hose) +{ + struct pnv_phb *phb = hose->private_data; + struct OpalIoP7IOCErrorData *data = &phb->diag.hub_diag; + long rc; + + rc = opal_pci_get_hub_diag_data(phb->hub_id, data, sizeof(*data)); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failed to get HUB#%llx diag-data (%ld)\n", + __func__, phb->hub_id, rc); + return; + } + + switch (data->type) { + case OPAL_P7IOC_DIAG_TYPE_RGC: + pr_info("P7IOC diag-data for RGC\n\n"); + pnv_eeh_dump_hub_diag_common(data); + if (data->rgc.rgcStatus || data->rgc.rgcLdcp) + pr_info(" RGC: %016llx %016llx\n", + be64_to_cpu(data->rgc.rgcStatus), + be64_to_cpu(data->rgc.rgcLdcp)); + break; + case OPAL_P7IOC_DIAG_TYPE_BI: + pr_info("P7IOC diag-data for BI %s\n\n", + data->bi.biDownbound ? "Downbound" : "Upbound"); + pnv_eeh_dump_hub_diag_common(data); + if (data->bi.biLdcp0 || data->bi.biLdcp1 || + data->bi.biLdcp2 || data->bi.biFenceStatus) + pr_info(" BI: %016llx %016llx %016llx %016llx\n", + be64_to_cpu(data->bi.biLdcp0), + be64_to_cpu(data->bi.biLdcp1), + be64_to_cpu(data->bi.biLdcp2), + be64_to_cpu(data->bi.biFenceStatus)); + break; + case OPAL_P7IOC_DIAG_TYPE_CI: + pr_info("P7IOC diag-data for CI Port %d\n\n", + data->ci.ciPort); + pnv_eeh_dump_hub_diag_common(data); + if (data->ci.ciPortStatus || data->ci.ciPortLdcp) + pr_info(" CI: %016llx %016llx\n", + be64_to_cpu(data->ci.ciPortStatus), + be64_to_cpu(data->ci.ciPortLdcp)); + break; + case OPAL_P7IOC_DIAG_TYPE_MISC: + pr_info("P7IOC diag-data for MISC\n\n"); + pnv_eeh_dump_hub_diag_common(data); + break; + case OPAL_P7IOC_DIAG_TYPE_I2C: + pr_info("P7IOC diag-data for I2C\n\n"); + pnv_eeh_dump_hub_diag_common(data); + break; + default: + pr_warn("%s: Invalid type of HUB#%llx diag-data (%d)\n", + __func__, phb->hub_id, data->type); + } +} + +static int pnv_eeh_get_pe(struct pci_controller *hose, + u16 pe_no, struct eeh_pe **pe) +{ + struct pnv_phb *phb = hose->private_data; + struct pnv_ioda_pe *pnv_pe; + struct eeh_pe *dev_pe; + struct eeh_dev edev; + + /* + * If PHB supports compound PE, to fetch + * the master PE because slave PE is invisible + * to EEH core. + */ + pnv_pe = &phb->ioda.pe_array[pe_no]; + if (pnv_pe->flags & PNV_IODA_PE_SLAVE) { + pnv_pe = pnv_pe->master; + WARN_ON(!pnv_pe || + !(pnv_pe->flags & PNV_IODA_PE_MASTER)); + pe_no = pnv_pe->pe_number; + } + + /* Find the PE according to PE# */ + memset(&edev, 0, sizeof(struct eeh_dev)); + edev.phb = hose; + edev.pe_config_addr = pe_no; + dev_pe = eeh_pe_get(&edev); + if (!dev_pe) + return -EEXIST; + + /* Freeze the (compound) PE */ + *pe = dev_pe; + if (!(dev_pe->state & EEH_PE_ISOLATED)) + phb->freeze_pe(phb, pe_no); + + /* + * At this point, we're sure the (compound) PE should + * have been frozen. However, we still need poke until + * hitting the frozen PE on top level. + */ + dev_pe = dev_pe->parent; + while (dev_pe && !(dev_pe->type & EEH_PE_PHB)) { + int ret; + int active_flags = (EEH_STATE_MMIO_ACTIVE | + EEH_STATE_DMA_ACTIVE); + + ret = eeh_ops->get_state(dev_pe, NULL); + if (ret <= 0 || (ret & active_flags) == active_flags) { + dev_pe = dev_pe->parent; + continue; + } + + /* Frozen parent PE */ + *pe = dev_pe; + if (!(dev_pe->state & EEH_PE_ISOLATED)) + phb->freeze_pe(phb, dev_pe->addr); + + /* Next one */ + dev_pe = dev_pe->parent; + } + + return 0; +} + /** * pnv_eeh_next_error - Retrieve next EEH error to handle * @pe: Affected PE * - * Using OPAL API, to retrieve next EEH error for EEH core to handle + * The function is expected to be called by EEH core while it gets + * special EEH event (without binding PE). The function calls to + * OPAL APIs for next error to handle. The informational error is + * handled internally by platform. However, the dead IOC, dead PHB, + * fenced PHB and frozen PE should be handled by EEH core eventually. */ static int pnv_eeh_next_error(struct eeh_pe **pe) { struct pci_controller *hose; - struct pnv_phb *phb = NULL; + struct pnv_phb *phb; + struct eeh_pe *phb_pe, *parent_pe; + __be64 frozen_pe_no; + __be16 err_type, severity; + int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); + long rc; + int state, ret = EEH_NEXT_ERR_NONE; + + /* + * While running here, it's safe to purge the event queue. + * And we should keep the cached OPAL notifier event sychronized + * between the kernel and firmware. + */ + eeh_remove_event(NULL, false); + opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); list_for_each_entry(hose, &hose_list, list_node) { + /* + * If the subordinate PCI buses of the PHB has been + * removed or is exactly under error recovery, we + * needn't take care of it any more. + */ phb = hose->private_data; - break; - } + phb_pe = eeh_phb_pe_get(hose); + if (!phb_pe || (phb_pe->state & EEH_PE_ISOLATED)) + continue; + + rc = opal_pci_next_error(phb->opal_id, + &frozen_pe_no, &err_type, &severity); + if (rc != OPAL_SUCCESS) { + pr_devel("%s: Invalid return value on " + "PHB#%x (0x%lx) from opal_pci_next_error", + __func__, hose->global_number, rc); + continue; + } + + /* If the PHB doesn't have error, stop processing */ + if (be16_to_cpu(err_type) == OPAL_EEH_NO_ERROR || + be16_to_cpu(severity) == OPAL_EEH_SEV_NO_ERROR) { + pr_devel("%s: No error found on PHB#%x\n", + __func__, hose->global_number); + continue; + } - if (phb && phb->eeh_ops->next_error) - return phb->eeh_ops->next_error(pe); + /* + * Processing the error. We're expecting the error with + * highest priority reported upon multiple errors on the + * specific PHB. + */ + pr_devel("%s: Error (%d, %d, %llu) on PHB#%x\n", + __func__, be16_to_cpu(err_type), + be16_to_cpu(severity), be64_to_cpu(frozen_pe_no), + hose->global_number); + switch (be16_to_cpu(err_type)) { + case OPAL_EEH_IOC_ERROR: + if (be16_to_cpu(severity) == OPAL_EEH_SEV_IOC_DEAD) { + pr_err("EEH: dead IOC detected\n"); + ret = EEH_NEXT_ERR_DEAD_IOC; + } else if (be16_to_cpu(severity) == OPAL_EEH_SEV_INF) { + pr_info("EEH: IOC informative error " + "detected\n"); + pnv_eeh_get_and_dump_hub_diag(hose); + ret = EEH_NEXT_ERR_NONE; + } + + break; + case OPAL_EEH_PHB_ERROR: + if (be16_to_cpu(severity) == OPAL_EEH_SEV_PHB_DEAD) { + *pe = phb_pe; + pr_err("EEH: dead PHB#%x detected, " + "location: %s\n", + hose->global_number, + eeh_pe_loc_get(phb_pe)); + ret = EEH_NEXT_ERR_DEAD_PHB; + } else if (be16_to_cpu(severity) == + OPAL_EEH_SEV_PHB_FENCED) { + *pe = phb_pe; + pr_err("EEH: Fenced PHB#%x detected, " + "location: %s\n", + hose->global_number, + eeh_pe_loc_get(phb_pe)); + ret = EEH_NEXT_ERR_FENCED_PHB; + } else if (be16_to_cpu(severity) == OPAL_EEH_SEV_INF) { + pr_info("EEH: PHB#%x informative error " + "detected, location: %s\n", + hose->global_number, + eeh_pe_loc_get(phb_pe)); + pnv_eeh_get_phb_diag(phb_pe); + pnv_pci_dump_phb_diag_data(hose, phb_pe->data); + ret = EEH_NEXT_ERR_NONE; + } - return -EEXIST; + break; + case OPAL_EEH_PE_ERROR: + /* + * If we can't find the corresponding PE, we + * just try to unfreeze. + */ + if (pnv_eeh_get_pe(hose, + be64_to_cpu(frozen_pe_no), pe)) { + /* Try best to clear it */ + pr_info("EEH: Clear non-existing PHB#%x-PE#%llx\n", + hose->global_number, frozen_pe_no); + pr_info("EEH: PHB location: %s\n", + eeh_pe_loc_get(phb_pe)); + opal_pci_eeh_freeze_clear(phb->opal_id, + frozen_pe_no, + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); + ret = EEH_NEXT_ERR_NONE; + } else if ((*pe)->state & EEH_PE_ISOLATED || + eeh_pe_passed(*pe)) { + ret = EEH_NEXT_ERR_NONE; + } else { + pr_err("EEH: Frozen PE#%x " + "on PHB#%x detected\n", + (*pe)->addr, + (*pe)->phb->global_number); + pr_err("EEH: PE location: %s, " + "PHB location: %s\n", + eeh_pe_loc_get(*pe), + eeh_pe_loc_get(phb_pe)); + ret = EEH_NEXT_ERR_FROZEN_PE; + } + + break; + default: + pr_warn("%s: Unexpected error type %d\n", + __func__, be16_to_cpu(err_type)); + } + + /* + * EEH core will try recover from fenced PHB or + * frozen PE. In the time for frozen PE, EEH core + * enable IO path for that before collecting logs, + * but it ruins the site. So we have to dump the + * log in advance here. + */ + if ((ret == EEH_NEXT_ERR_FROZEN_PE || + ret == EEH_NEXT_ERR_FENCED_PHB) && + !((*pe)->state & EEH_PE_ISOLATED)) { + eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); + pnv_eeh_get_phb_diag(*pe); + + if (eeh_has_flag(EEH_EARLY_DUMP_LOG)) + pnv_pci_dump_phb_diag_data((*pe)->phb, + (*pe)->data); + } + + /* + * We probably have the frozen parent PE out there and + * we need have to handle frozen parent PE firstly. + */ + if (ret == EEH_NEXT_ERR_FROZEN_PE) { + parent_pe = (*pe)->parent; + while (parent_pe) { + /* Hit the ceiling ? */ + if (parent_pe->type & EEH_PE_PHB) + break; + + /* Frozen parent PE ? */ + state = eeh_ops->get_state(parent_pe, NULL); + if (state > 0 && + (state & active_flags) != active_flags) + *pe = parent_pe; + + /* Next parent level */ + parent_pe = parent_pe->parent; + } + + /* We possibly migrate to another PE */ + eeh_pe_state_mark(*pe, EEH_PE_ISOLATED); + } + + /* + * If we have no errors on the specific PHB or only + * informative error there, we continue poking it. + * Otherwise, we need actions to be taken by upper + * layer. + */ + if (ret > EEH_NEXT_ERR_INF) + break; + } + + return ret; } static int pnv_eeh_restore_config(struct device_node *dn) diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 773a026bfee2..5275d8928d94 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -79,7 +79,6 @@ struct pnv_ioda_pe { #ifdef CONFIG_EEH struct pnv_eeh_ops { int (*reset)(struct eeh_pe *pe, int option); - int (*next_error)(struct eeh_pe **pe); }; #endif /* CONFIG_EEH */ -- GitLab From cadf364d14f629119ba02c69f17a697d21880079 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:47 +1100 Subject: [PATCH 0408/1910] powerpc/powernv: Drop PHB operation reset() The patch drops PHB EEH operation reset() and merges its logic to eeh_ops::reset(). Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/eeh-ioda.c | 235 ------------------- arch/powerpc/platforms/powernv/eeh-powernv.c | 225 +++++++++++++++++- arch/powerpc/platforms/powernv/pci-ioda.c | 4 +- arch/powerpc/platforms/powernv/pci.h | 3 +- 4 files changed, 223 insertions(+), 244 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 94d94b4811ad..9fcfc45595ad 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -34,240 +34,5 @@ #include "powernv.h" #include "pci.h" -static s64 ioda_eeh_phb_poll(struct pnv_phb *phb) -{ - s64 rc = OPAL_HARDWARE; - - while (1) { - rc = opal_pci_poll(phb->opal_id); - if (rc <= 0) - break; - - if (system_state < SYSTEM_RUNNING) - udelay(1000 * rc); - else - msleep(rc); - } - - return rc; -} - -int ioda_eeh_phb_reset(struct pci_controller *hose, int option) -{ - struct pnv_phb *phb = hose->private_data; - s64 rc = OPAL_HARDWARE; - - pr_debug("%s: Reset PHB#%x, option=%d\n", - __func__, hose->global_number, option); - - /* Issue PHB complete reset request */ - if (option == EEH_RESET_FUNDAMENTAL || - option == EEH_RESET_HOT) - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PHB_COMPLETE, - OPAL_ASSERT_RESET); - else if (option == EEH_RESET_DEACTIVATE) - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PHB_COMPLETE, - OPAL_DEASSERT_RESET); - if (rc < 0) - goto out; - - /* - * Poll state of the PHB until the request is done - * successfully. The PHB reset is usually PHB complete - * reset followed by hot reset on root bus. So we also - * need the PCI bus settlement delay. - */ - rc = ioda_eeh_phb_poll(phb); - if (option == EEH_RESET_DEACTIVATE) { - if (system_state < SYSTEM_RUNNING) - udelay(1000 * EEH_PE_RST_SETTLE_TIME); - else - msleep(EEH_PE_RST_SETTLE_TIME); - } -out: - if (rc != OPAL_SUCCESS) - return -EIO; - - return 0; -} - -static int ioda_eeh_root_reset(struct pci_controller *hose, int option) -{ - struct pnv_phb *phb = hose->private_data; - s64 rc = OPAL_SUCCESS; - - pr_debug("%s: Reset PHB#%x, option=%d\n", - __func__, hose->global_number, option); - - /* - * During the reset deassert time, we needn't care - * the reset scope because the firmware does nothing - * for fundamental or hot reset during deassert phase. - */ - if (option == EEH_RESET_FUNDAMENTAL) - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PCI_FUNDAMENTAL, - OPAL_ASSERT_RESET); - else if (option == EEH_RESET_HOT) - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PCI_HOT, - OPAL_ASSERT_RESET); - else if (option == EEH_RESET_DEACTIVATE) - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PCI_HOT, - OPAL_DEASSERT_RESET); - if (rc < 0) - goto out; - - /* Poll state of the PHB until the request is done */ - rc = ioda_eeh_phb_poll(phb); - if (option == EEH_RESET_DEACTIVATE) - msleep(EEH_PE_RST_SETTLE_TIME); -out: - if (rc != OPAL_SUCCESS) - return -EIO; - - return 0; -} - -static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option) - -{ - struct device_node *dn = pci_device_to_OF_node(dev); - struct eeh_dev *edev = of_node_to_eeh_dev(dn); - int aer = edev ? edev->aer_cap : 0; - u32 ctrl; - - pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", - __func__, pci_domain_nr(dev->bus), - dev->bus->number, option); - - switch (option) { - case EEH_RESET_FUNDAMENTAL: - case EEH_RESET_HOT: - /* Don't report linkDown event */ - if (aer) { - eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, - 4, &ctrl); - ctrl |= PCI_ERR_UNC_SURPDN; - eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, - 4, ctrl); - } - - eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); - ctrl |= PCI_BRIDGE_CTL_BUS_RESET; - eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); - msleep(EEH_PE_RST_HOLD_TIME); - - break; - case EEH_RESET_DEACTIVATE: - eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); - ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; - eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); - msleep(EEH_PE_RST_SETTLE_TIME); - - /* Continue reporting linkDown event */ - if (aer) { - eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, - 4, &ctrl); - ctrl &= ~PCI_ERR_UNC_SURPDN; - eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, - 4, ctrl); - } - - break; - } - - return 0; -} - -void pnv_pci_reset_secondary_bus(struct pci_dev *dev) -{ - struct pci_controller *hose; - - if (pci_is_root_bus(dev->bus)) { - hose = pci_bus_to_host(dev->bus); - ioda_eeh_root_reset(hose, EEH_RESET_HOT); - ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE); - } else { - ioda_eeh_bridge_reset(dev, EEH_RESET_HOT); - ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE); - } -} - -/** - * ioda_eeh_reset - Reset the indicated PE - * @pe: EEH PE - * @option: reset option - * - * Do reset on the indicated PE. For PCI bus sensitive PE, - * we need to reset the parent p2p bridge. The PHB has to - * be reinitialized if the p2p bridge is root bridge. For - * PCI device sensitive PE, we will try to reset the device - * through FLR. For now, we don't have OPAL APIs to do HARD - * reset yet, so all reset would be SOFT (HOT) reset. - */ -static int ioda_eeh_reset(struct eeh_pe *pe, int option) -{ - struct pci_controller *hose = pe->phb; - struct pci_bus *bus; - int ret; - - /* - * For PHB reset, we always have complete reset. For those PEs whose - * primary bus derived from root complex (root bus) or root port - * (usually bus#1), we apply hot or fundamental reset on the root port. - * For other PEs, we always have hot reset on the PE primary bus. - * - * Here, we have different design to pHyp, which always clear the - * frozen state during PE reset. However, the good idea here from - * benh is to keep frozen state before we get PE reset done completely - * (until BAR restore). With the frozen state, HW drops illegal IO - * or MMIO access, which can incur recrusive frozen PE during PE - * reset. The side effect is that EEH core has to clear the frozen - * state explicitly after BAR restore. - */ - if (pe->type & EEH_PE_PHB) { - ret = ioda_eeh_phb_reset(hose, option); - } else { - struct pnv_phb *phb; - s64 rc; - - /* - * The frozen PE might be caused by PAPR error injection - * registers, which are expected to be cleared after hitting - * frozen PE as stated in the hardware spec. Unfortunately, - * that's not true on P7IOC. So we have to clear it manually - * to avoid recursive EEH errors during recovery. - */ - phb = hose->private_data; - if (phb->model == PNV_PHB_MODEL_P7IOC && - (option == EEH_RESET_HOT || - option == EEH_RESET_FUNDAMENTAL)) { - rc = opal_pci_reset(phb->opal_id, - OPAL_RESET_PHB_ERROR, - OPAL_ASSERT_RESET); - if (rc != OPAL_SUCCESS) { - pr_warn("%s: Failure %lld clearing " - "error injection registers\n", - __func__, rc); - return -EIO; - } - } - - bus = eeh_pe_bus_get(pe); - if (pci_is_root_bus(bus) || - pci_is_root_bus(bus->parent)) - ret = ioda_eeh_root_reset(hose, option); - else - ret = ioda_eeh_bridge_reset(bus->self, option); - } - - return ret; -} - struct pnv_eeh_ops ioda_eeh_ops = { - .reset = ioda_eeh_reset, }; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index e51ac2dfde50..ede690630dfc 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -665,21 +665,236 @@ static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay) return ret; } +static s64 pnv_eeh_phb_poll(struct pnv_phb *phb) +{ + s64 rc = OPAL_HARDWARE; + + while (1) { + rc = opal_pci_poll(phb->opal_id); + if (rc <= 0) + break; + + if (system_state < SYSTEM_RUNNING) + udelay(1000 * rc); + else + msleep(rc); + } + + return rc; +} + +int pnv_eeh_phb_reset(struct pci_controller *hose, int option) +{ + struct pnv_phb *phb = hose->private_data; + s64 rc = OPAL_HARDWARE; + + pr_debug("%s: Reset PHB#%x, option=%d\n", + __func__, hose->global_number, option); + + /* Issue PHB complete reset request */ + if (option == EEH_RESET_FUNDAMENTAL || + option == EEH_RESET_HOT) + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PHB_COMPLETE, + OPAL_ASSERT_RESET); + else if (option == EEH_RESET_DEACTIVATE) + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PHB_COMPLETE, + OPAL_DEASSERT_RESET); + if (rc < 0) + goto out; + + /* + * Poll state of the PHB until the request is done + * successfully. The PHB reset is usually PHB complete + * reset followed by hot reset on root bus. So we also + * need the PCI bus settlement delay. + */ + rc = pnv_eeh_phb_poll(phb); + if (option == EEH_RESET_DEACTIVATE) { + if (system_state < SYSTEM_RUNNING) + udelay(1000 * EEH_PE_RST_SETTLE_TIME); + else + msleep(EEH_PE_RST_SETTLE_TIME); + } +out: + if (rc != OPAL_SUCCESS) + return -EIO; + + return 0; +} + +static int pnv_eeh_root_reset(struct pci_controller *hose, int option) +{ + struct pnv_phb *phb = hose->private_data; + s64 rc = OPAL_HARDWARE; + + pr_debug("%s: Reset PHB#%x, option=%d\n", + __func__, hose->global_number, option); + + /* + * During the reset deassert time, we needn't care + * the reset scope because the firmware does nothing + * for fundamental or hot reset during deassert phase. + */ + if (option == EEH_RESET_FUNDAMENTAL) + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PCI_FUNDAMENTAL, + OPAL_ASSERT_RESET); + else if (option == EEH_RESET_HOT) + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PCI_HOT, + OPAL_ASSERT_RESET); + else if (option == EEH_RESET_DEACTIVATE) + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PCI_HOT, + OPAL_DEASSERT_RESET); + if (rc < 0) + goto out; + + /* Poll state of the PHB until the request is done */ + rc = pnv_eeh_phb_poll(phb); + if (option == EEH_RESET_DEACTIVATE) + msleep(EEH_PE_RST_SETTLE_TIME); +out: + if (rc != OPAL_SUCCESS) + return -EIO; + + return 0; +} + +static int pnv_eeh_bridge_reset(struct pci_dev *dev, int option) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = of_node_to_eeh_dev(dn); + int aer = edev ? edev->aer_cap : 0; + u32 ctrl; + + pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", + __func__, pci_domain_nr(dev->bus), + dev->bus->number, option); + + switch (option) { + case EEH_RESET_FUNDAMENTAL: + case EEH_RESET_HOT: + /* Don't report linkDown event */ + if (aer) { + eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, &ctrl); + ctrl |= PCI_ERR_UNC_SURPDN; + eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, ctrl); + } + + eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); + ctrl |= PCI_BRIDGE_CTL_BUS_RESET; + eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); + + msleep(EEH_PE_RST_HOLD_TIME); + break; + case EEH_RESET_DEACTIVATE: + eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); + ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; + eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); + + msleep(EEH_PE_RST_SETTLE_TIME); + + /* Continue reporting linkDown event */ + if (aer) { + eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, &ctrl); + ctrl &= ~PCI_ERR_UNC_SURPDN; + eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK, + 4, ctrl); + } + + break; + } + + return 0; +} + +void pnv_pci_reset_secondary_bus(struct pci_dev *dev) +{ + struct pci_controller *hose; + + if (pci_is_root_bus(dev->bus)) { + hose = pci_bus_to_host(dev->bus); + pnv_eeh_root_reset(hose, EEH_RESET_HOT); + pnv_eeh_root_reset(hose, EEH_RESET_DEACTIVATE); + } else { + pnv_eeh_bridge_reset(dev, EEH_RESET_HOT); + pnv_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE); + } +} + /** * pnv_eeh_reset - Reset the specified PE * @pe: EEH PE * @option: reset option * - * Reset the specified PE + * Do reset on the indicated PE. For PCI bus sensitive PE, + * we need to reset the parent p2p bridge. The PHB has to + * be reinitialized if the p2p bridge is root bridge. For + * PCI device sensitive PE, we will try to reset the device + * through FLR. For now, we don't have OPAL APIs to do HARD + * reset yet, so all reset would be SOFT (HOT) reset. */ static int pnv_eeh_reset(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; - struct pnv_phb *phb = hose->private_data; - int ret = -EEXIST; + struct pci_bus *bus; + int ret; + + /* + * For PHB reset, we always have complete reset. For those PEs whose + * primary bus derived from root complex (root bus) or root port + * (usually bus#1), we apply hot or fundamental reset on the root port. + * For other PEs, we always have hot reset on the PE primary bus. + * + * Here, we have different design to pHyp, which always clear the + * frozen state during PE reset. However, the good idea here from + * benh is to keep frozen state before we get PE reset done completely + * (until BAR restore). With the frozen state, HW drops illegal IO + * or MMIO access, which can incur recrusive frozen PE during PE + * reset. The side effect is that EEH core has to clear the frozen + * state explicitly after BAR restore. + */ + if (pe->type & EEH_PE_PHB) { + ret = pnv_eeh_phb_reset(hose, option); + } else { + struct pnv_phb *phb; + s64 rc; - if (phb->eeh_ops && phb->eeh_ops->reset) - ret = phb->eeh_ops->reset(pe, option); + /* + * The frozen PE might be caused by PAPR error injection + * registers, which are expected to be cleared after hitting + * frozen PE as stated in the hardware spec. Unfortunately, + * that's not true on P7IOC. So we have to clear it manually + * to avoid recursive EEH errors during recovery. + */ + phb = hose->private_data; + if (phb->model == PNV_PHB_MODEL_P7IOC && + (option == EEH_RESET_HOT || + option == EEH_RESET_FUNDAMENTAL)) { + rc = opal_pci_reset(phb->opal_id, + OPAL_RESET_PHB_ERROR, + OPAL_ASSERT_RESET); + if (rc != OPAL_SUCCESS) { + pr_warn("%s: Failure %lld clearing " + "error injection registers\n", + __func__, rc); + return -EIO; + } + } + + bus = eeh_pe_bus_get(pe); + if (pci_is_root_bus(bus) || + pci_is_root_bus(bus->parent)) + ret = pnv_eeh_root_reset(hose, option); + else + ret = pnv_eeh_bridge_reset(bus->self, option); + } return ret; } diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 6c9ff2b95119..4e21596bed48 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2121,8 +2121,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np, */ if (is_kdump_kernel()) { pr_info(" Issue PHB reset ...\n"); - ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); - ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE); + pnv_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); + pnv_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE); } /* Remove M64 resource if we can't configure it successfully */ diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 5275d8928d94..39f2ca37b19e 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -78,7 +78,6 @@ struct pnv_ioda_pe { /* IOC dependent EEH operations */ #ifdef CONFIG_EEH struct pnv_eeh_ops { - int (*reset)(struct eeh_pe *pe, int option); }; #endif /* CONFIG_EEH */ @@ -223,6 +222,6 @@ extern void pnv_pci_init_ioda2_phb(struct device_node *np); extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, __be64 *startp, __be64 *endp, bool rm); extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev); -extern int ioda_eeh_phb_reset(struct pci_controller *hose, int option); +extern int pnv_eeh_phb_reset(struct pci_controller *hose, int option); #endif /* __POWERNV_PCI_H */ -- GitLab From 2f6cf7944833bf9c63b945799b460988aec30040 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 16 Feb 2015 14:45:48 +1100 Subject: [PATCH 0409/1910] powerpc/powernv: Remove unused file The patch removes unused file eeh-ioda.c and updates makefile accordingly. Besides, the definition of "struct pnv_eeh_ops" and the instances are all removed. Until now, the chip layer of EEH implementation for PowerNV platform is removed completely. Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/Makefile | 2 +- arch/powerpc/platforms/powernv/eeh-ioda.c | 38 ----------------------- arch/powerpc/platforms/powernv/pci-ioda.c | 3 -- arch/powerpc/platforms/powernv/pci.h | 13 -------- 4 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 arch/powerpc/platforms/powernv/eeh-ioda.c diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 6f3c5d33c3af..33e44f37212f 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -5,7 +5,7 @@ obj-y += opal-msglog.o opal-hmi.o opal-power.o obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o -obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o +obj-$(CONFIG_EEH) += eeh-powernv.o obj-$(CONFIG_PPC_SCOM) += opal-xscom.o obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o obj-$(CONFIG_TRACEPOINTS) += opal-tracepoints.o diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c deleted file mode 100644 index 9fcfc45595ad..000000000000 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * The file intends to implement the functions needed by EEH, which is - * built on IODA compliant chip. Actually, lots of functions related - * to EEH would be built based on the OPAL APIs. - * - * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "powernv.h" -#include "pci.h" - -struct pnv_eeh_ops ioda_eeh_ops = { -}; diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 4e21596bed48..26fe09936935 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2078,9 +2078,6 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np, phb->get_pe_state = pnv_ioda_get_pe_state; phb->freeze_pe = pnv_ioda_freeze_pe; phb->unfreeze_pe = pnv_ioda_unfreeze_pe; -#ifdef CONFIG_EEH - phb->eeh_ops = &ioda_eeh_ops; -#endif /* Setup RID -> PE mapping function */ phb->bdfn_to_pe = pnv_ioda_bdfn_to_pe; diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 39f2ca37b19e..18ae927f7819 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -75,12 +75,6 @@ struct pnv_ioda_pe { struct list_head list; }; -/* IOC dependent EEH operations */ -#ifdef CONFIG_EEH -struct pnv_eeh_ops { -}; -#endif /* CONFIG_EEH */ - #define PNV_PHB_FLAG_EEH (1 << 0) struct pnv_phb { @@ -94,10 +88,6 @@ struct pnv_phb { int initialized; spinlock_t lock; -#ifdef CONFIG_EEH - struct pnv_eeh_ops *eeh_ops; -#endif - #ifdef CONFIG_DEBUG_FS int has_dbgfs; struct dentry *dbgfs; @@ -203,9 +193,6 @@ struct pnv_phb { }; extern struct pci_ops pnv_pci_ops; -#ifdef CONFIG_EEH -extern struct pnv_eeh_ops ioda_eeh_ops; -#endif void pnv_pci_dump_phb_diag_data(struct pci_controller *hose, unsigned char *log_buff); -- GitLab From 366d395c8dd8f1d92f967e4a7691dadd9b9ae1bb Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 10 Feb 2015 13:43:24 -0600 Subject: [PATCH 0410/1910] powerpc/pseries: Define rtas hotplug event sections In order to handle device hotplug in the kernel on pseries the hotplug request will be communicated in the kernel in the form of a rtas hotplug event. This patch adds the definition of rtas hotplug event sections. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/rtas.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 2e23e92a4372..eddc8469543a 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -273,6 +273,7 @@ inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log) #define PSERIES_ELOG_SECT_ID_MANUFACT_INFO (('M' << 8) | 'I') #define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H') #define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D') +#define PSERIES_ELOG_SECT_ID_HOTPLUG (('H' << 8) | 'P') /* Vendor specific Platform Event Log Format, Version 6, section header */ struct pseries_errorlog { @@ -296,6 +297,31 @@ inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect) return be16_to_cpu(sect->length); } +/* RTAS pseries hotplug errorlog section */ +struct pseries_hp_errorlog { + u8 resource; + u8 action; + u8 id_type; + u8 reserved; + union { + __be32 drc_index; + __be32 drc_count; + char drc_name[1]; + } _drc_u; +}; + +#define PSERIES_HP_ELOG_RESOURCE_CPU 1 +#define PSERIES_HP_ELOG_RESOURCE_MEM 2 +#define PSERIES_HP_ELOG_RESOURCE_SLOT 3 +#define PSERIES_HP_ELOG_RESOURCE_PHB 4 + +#define PSERIES_HP_ELOG_ACTION_ADD 1 +#define PSERIES_HP_ELOG_ACTION_REMOVE 2 + +#define PSERIES_HP_ELOG_ID_DRC_NAME 1 +#define PSERIES_HP_ELOG_ID_DRC_INDEX 2 +#define PSERIES_HP_ELOG_ID_DRC_COUNT 3 + struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log, uint16_t section_id); -- GitLab From 5e51d3c2a46b0131d31594b33aacdff5aa99f0f3 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 10 Feb 2015 13:45:01 -0600 Subject: [PATCH 0411/1910] powerpc/pseries: Declare the acquire/release drc index routines Add declarations for dlpar_{acquire,release}_drc(...) They are already marked non-static but were missing a prototype/ [BenH: Added extern to be consistent with the rest of the file] Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/pseries.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 1796c5438cc6..b760c9c45055 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -60,6 +60,8 @@ extern struct device_node *dlpar_configure_connector(__be32, struct device_node *); extern int dlpar_attach_node(struct device_node *); extern int dlpar_detach_node(struct device_node *); +extern int dlpar_acquire_drc(u32 drc_index); +extern int dlpar_release_drc(u32 drc_index); /* PCI root bridge prepare function override for pseries */ struct pci_host_bridge; -- GitLab From 999e2dadb6058568b8bcffec44da2a07952d84fe Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 10 Feb 2015 13:47:02 -0600 Subject: [PATCH 0412/1910] powerpc/pseries: Create new device hotplug entry point The current hotplug (or dlpar) of devices (the process is generally the same for memory, cpu, and pci) on PowerVM systems is initiated from the HMC, which communicates the request to the partitions through the RSCT framework. The RSCT framework then invokes the drmgr command. The drmgr command performs the hotplug operation by doing some pieces, such as most of the rtas calls and device tree parsing, in userspace and make requests to the kernel to online/offline the device, update the device tree and add/remove the device. For PowerKVM the approach for device hotplug is to follow what is currently being done for pci hotplug. A hotplug request is initiated from the host. QEMU then generates an EPOW interrupt to the guest which causes the guest to make the rtas,check-exception call. In QEMU, the rtas,check-exception call returns a rtas hotplug event to the guest. Please note that the current pci hotplug path for PowerKVM involves the kernel receiving the rtas hotplug event, passing it to rtas_errd in userspace, and having rtas_errd invoke drmgr. The drmgr command then handles the request as described above for PowerVM systems. There is no need for this circuitous route, we should just handle the entire hotplug of devices in the kernel. What I am planning is to enable this by moving the code to handle hotplug from drmgr into the kernel to provide a single path for handling device hotplug for both PowerVM and PowerKVM systems. This patch provides the common iframework and entry point. For PowerKVM a future update to the kernel rtas code will recognize rtas hotplug events returned from rtas,check-exception calls and use the common entry point to handle hotplug of the device. For PowerVM systems, This patch creates /sys/kernel/dlpar that can be used by the drmgr command to initiate hotplug requests. In order to do this a string of the format " " is written to this file. The string consists of a resource (cpu, memory, pci, phb), an action (add or remove), an id_type (count, drc index, drc name), and the corresponding id. The kernel will parse the string and create a rtas hotplug section that can be passed to the common entry point for handling hotplug requests. It should be noted that there is no chance of updating how we receive hotplug (dlpar) requests from the HMC on PowerVM systems. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/dlpar.c | 118 +++++++++++++++++- .../platforms/pseries/hotplug-memory.c | 19 +++ arch/powerpc/platforms/pseries/pseries.h | 10 ++ 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index c22bb1b4beb8..b4b11096ea8b 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -10,6 +10,8 @@ * 2 as published by the Free Software Foundation. */ +#define pr_fmt(fmt) "dlpar: " fmt + #include #include #include @@ -535,13 +537,125 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count) return count; } +#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ + +static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) +{ + int rc; + + /* pseries error logs are in BE format, convert to cpu type */ + switch (hp_elog->id_type) { + case PSERIES_HP_ELOG_ID_DRC_COUNT: + hp_elog->_drc_u.drc_count = + be32_to_cpu(hp_elog->_drc_u.drc_count); + break; + case PSERIES_HP_ELOG_ID_DRC_INDEX: + hp_elog->_drc_u.drc_index = + be32_to_cpu(hp_elog->_drc_u.drc_index); + } + + switch (hp_elog->resource) { + case PSERIES_HP_ELOG_RESOURCE_MEM: + rc = dlpar_memory(hp_elog); + break; + default: + pr_warn_ratelimited("Invalid resource (%d) specified\n", + hp_elog->resource); + rc = -EINVAL; + } + + return rc; +} + +static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct pseries_hp_errorlog *hp_elog; + const char *arg; + int rc; + + hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); + if (!hp_elog) { + rc = -ENOMEM; + goto dlpar_store_out; + } + + /* Parse out the request from the user, this will be in the form + * + */ + arg = buf; + if (!strncmp(arg, "memory", 6)) { + hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; + arg += strlen("memory "); + } else { + pr_err("Invalid resource specified: \"%s\"\n", buf); + rc = -EINVAL; + goto dlpar_store_out; + } + + if (!strncmp(arg, "add", 3)) { + hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD; + arg += strlen("add "); + } else if (!strncmp(arg, "remove", 6)) { + hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE; + arg += strlen("remove "); + } else { + pr_err("Invalid action specified: \"%s\"\n", buf); + rc = -EINVAL; + goto dlpar_store_out; + } + + if (!strncmp(arg, "index", 5)) { + u32 index; + + hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; + arg += strlen("index "); + if (kstrtou32(arg, 0, &index)) { + rc = -EINVAL; + pr_err("Invalid drc_index specified: \"%s\"\n", buf); + goto dlpar_store_out; + } + + hp_elog->_drc_u.drc_index = cpu_to_be32(index); + } else if (!strncmp(arg, "count", 5)) { + u32 count; + + hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT; + arg += strlen("count "); + if (kstrtou32(arg, 0, &count)) { + rc = -EINVAL; + pr_err("Invalid count specified: \"%s\"\n", buf); + goto dlpar_store_out; + } + + hp_elog->_drc_u.drc_count = cpu_to_be32(count); + } else { + pr_err("Invalid id_type specified: \"%s\"\n", buf); + rc = -EINVAL; + goto dlpar_store_out; + } + + rc = handle_dlpar_errorlog(hp_elog); + +dlpar_store_out: + kfree(hp_elog); + return rc ? rc : count; +} + +static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store); + static int __init pseries_dlpar_init(void) { + int rc; + +#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE ppc_md.cpu_probe = dlpar_cpu_probe; ppc_md.cpu_release = dlpar_cpu_release; +#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ - return 0; + rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); + + return rc; } machine_device_initcall(pseries, pseries_dlpar_init); -#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index fa41f0da5b6f..211d0bf7f5d9 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -9,6 +9,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "pseries-hotplug-mem: " fmt + #include #include #include @@ -134,6 +136,23 @@ static inline int pseries_remove_mem_node(struct device_node *np) } #endif /* CONFIG_MEMORY_HOTREMOVE */ +int dlpar_memory(struct pseries_hp_errorlog *hp_elog) +{ + int rc = 0; + + lock_device_hotplug(); + + switch (hp_elog->action) { + default: + pr_err("Invalid action (%d) specified\n", hp_elog->action); + rc = -EINVAL; + break; + } + + unlock_device_hotplug(); + return rc; +} + static int pseries_add_mem_node(struct device_node *np) { const char *type; diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index b760c9c45055..2d261fc56c42 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -11,6 +11,7 @@ #define _PSERIES_PSERIES_H #include +#include struct device_node; @@ -63,6 +64,15 @@ extern int dlpar_detach_node(struct device_node *); extern int dlpar_acquire_drc(u32 drc_index); extern int dlpar_release_drc(u32 drc_index); +#ifdef CONFIG_MEMORY_HOTPLUG +int dlpar_memory(struct pseries_hp_errorlog *hp_elog); +#else +static inline int dlpar_memory(struct pseries_hp_errorlog *hp_elog) +{ + return -EOPNOTSUPP; +} +#endif + /* PCI root bridge prepare function override for pseries */ struct pci_host_bridge; int pseries_root_bridge_prepare(struct pci_host_bridge *bridge); -- GitLab From 5f97b2a0d176a94815ee1d3a0511d91a5575bf4a Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 10 Feb 2015 13:48:25 -0600 Subject: [PATCH 0413/1910] powerpc/pseries: Implement memory hotplug add in the kernel This patch adds the ability to do memory hotplug add in the kernel. Currently the operation to hotplug add memory is handled by the drmgr command which performs the operation by performing some work in user-space and making requests to the kernel to handle other pieces. By moving all of the work to the kernel we can do the add faster, and provide a common code path to do memory hotplug for both the PowerVM and PowerKVM environments. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- .../platforms/pseries/hotplug-memory.c | 266 +++++++++++++++++- 1 file changed, 265 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 211d0bf7f5d9..f5eec0fc46df 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,8 @@ #include #include "pseries.h" +static bool rtas_hp_event; + unsigned long pseries_memory_block_size(void) { struct device_node *np; @@ -66,6 +69,67 @@ unsigned long pseries_memory_block_size(void) return memblock_size; } +static void dlpar_free_drconf_property(struct property *prop) +{ + kfree(prop->name); + kfree(prop->value); + kfree(prop); +} + +static struct property *dlpar_clone_drconf_property(struct device_node *dn) +{ + struct property *prop, *new_prop; + struct of_drconf_cell *lmbs; + u32 num_lmbs, *p; + int i; + + prop = of_find_property(dn, "ibm,dynamic-memory", NULL); + if (!prop) + return NULL; + + new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); + if (!new_prop) + return NULL; + + new_prop->name = kstrdup(prop->name, GFP_KERNEL); + new_prop->value = kmalloc(prop->length, GFP_KERNEL); + if (!new_prop->name || !new_prop->value) { + dlpar_free_drconf_property(new_prop); + return NULL; + } + + memcpy(new_prop->value, prop->value, prop->length); + new_prop->length = prop->length; + + /* Convert the property to cpu endian-ness */ + p = new_prop->value; + *p = be32_to_cpu(*p); + + num_lmbs = *p++; + lmbs = (struct of_drconf_cell *)p; + + for (i = 0; i < num_lmbs; i++) { + lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr); + lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index); + lmbs[i].flags = be32_to_cpu(lmbs[i].flags); + } + + return new_prop; +} + +static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb) +{ + unsigned long section_nr; + struct mem_section *mem_sect; + struct memory_block *mem_block; + + section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr)); + mem_sect = __nr_to_section(section_nr); + + mem_block = find_memory_block(mem_sect); + return mem_block; +} + #ifdef CONFIG_MEMORY_HOTREMOVE static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) { @@ -136,19 +200,216 @@ static inline int pseries_remove_mem_node(struct device_node *np) } #endif /* CONFIG_MEMORY_HOTREMOVE */ +static int dlpar_add_lmb(struct of_drconf_cell *lmb) +{ + struct memory_block *mem_block; + unsigned long block_sz; + int nid, rc; + + if (lmb->flags & DRCONF_MEM_ASSIGNED) + return -EINVAL; + + block_sz = memory_block_size_bytes(); + + rc = dlpar_acquire_drc(lmb->drc_index); + if (rc) + return rc; + + /* Find the node id for this address */ + nid = memory_add_physaddr_to_nid(lmb->base_addr); + + /* Add the memory */ + rc = add_memory(nid, lmb->base_addr, block_sz); + if (rc) { + dlpar_release_drc(lmb->drc_index); + return rc; + } + + /* Register this block of memory */ + rc = memblock_add(lmb->base_addr, block_sz); + if (rc) { + remove_memory(nid, lmb->base_addr, block_sz); + dlpar_release_drc(lmb->drc_index); + return rc; + } + + mem_block = lmb_to_memblock(lmb); + if (!mem_block) { + remove_memory(nid, lmb->base_addr, block_sz); + dlpar_release_drc(lmb->drc_index); + return -EINVAL; + } + + rc = device_online(&mem_block->dev); + put_device(&mem_block->dev); + if (rc) { + remove_memory(nid, lmb->base_addr, block_sz); + dlpar_release_drc(lmb->drc_index); + return rc; + } + + lmb->flags |= DRCONF_MEM_ASSIGNED; + return 0; +} + +static int dlpar_memory_add_by_count(u32 lmbs_to_add, struct property *prop) +{ + struct of_drconf_cell *lmbs; + u32 num_lmbs, *p; + int lmbs_available = 0; + int lmbs_added = 0; + int i, rc; + + pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add); + + if (lmbs_to_add == 0) + return -EINVAL; + + p = prop->value; + num_lmbs = *p++; + lmbs = (struct of_drconf_cell *)p; + + /* Validate that there are enough LMBs to satisfy the request */ + for (i = 0; i < num_lmbs; i++) { + if (!(lmbs[i].flags & DRCONF_MEM_ASSIGNED)) + lmbs_available++; + } + + if (lmbs_available < lmbs_to_add) + return -EINVAL; + + for (i = 0; i < num_lmbs && lmbs_to_add != lmbs_added; i++) { + rc = dlpar_add_lmb(&lmbs[i]); + if (rc) + continue; + + lmbs_added++; + + /* Mark this lmb so we can remove it later if all of the + * requested LMBs cannot be added. + */ + lmbs[i].reserved = 1; + } + + if (lmbs_added != lmbs_to_add) { + /* TODO: remove added lmbs */ + rc = -EINVAL; + } else { + for (i = 0; i < num_lmbs; i++) { + if (!lmbs[i].reserved) + continue; + + pr_info("Memory at %llx (drc index %x) was hot-added\n", + lmbs[i].base_addr, lmbs[i].drc_index); + lmbs[i].reserved = 0; + } + } + + return rc; +} + +static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop) +{ + struct of_drconf_cell *lmbs; + u32 num_lmbs, *p; + int i, lmb_found; + int rc; + + pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index); + + p = prop->value; + num_lmbs = *p++; + lmbs = (struct of_drconf_cell *)p; + + lmb_found = 0; + for (i = 0; i < num_lmbs; i++) { + if (lmbs[i].drc_index == drc_index) { + lmb_found = 1; + rc = dlpar_add_lmb(&lmbs[i]); + break; + } + } + + if (!lmb_found) + rc = -EINVAL; + + if (rc) + pr_info("Failed to hot-add memory, drc index %x\n", drc_index); + else + pr_info("Memory at %llx (drc index %x) was hot-added\n", + lmbs[i].base_addr, drc_index); + + return rc; +} + +static void dlpar_update_drconf_property(struct device_node *dn, + struct property *prop) +{ + struct of_drconf_cell *lmbs; + u32 num_lmbs, *p; + int i; + + /* Convert the property back to BE */ + p = prop->value; + num_lmbs = *p; + *p = cpu_to_be32(*p); + p++; + + lmbs = (struct of_drconf_cell *)p; + for (i = 0; i < num_lmbs; i++) { + lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr); + lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index); + lmbs[i].flags = cpu_to_be32(lmbs[i].flags); + } + + rtas_hp_event = true; + of_update_property(dn, prop); + rtas_hp_event = false; +} + int dlpar_memory(struct pseries_hp_errorlog *hp_elog) { - int rc = 0; + struct device_node *dn; + struct property *prop; + u32 count, drc_index; + int rc; + + count = hp_elog->_drc_u.drc_count; + drc_index = hp_elog->_drc_u.drc_index; lock_device_hotplug(); + dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!dn) + return -EINVAL; + + prop = dlpar_clone_drconf_property(dn); + if (!prop) { + of_node_put(dn); + return -EINVAL; + } + switch (hp_elog->action) { + case PSERIES_HP_ELOG_ACTION_ADD: + if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) + rc = dlpar_memory_add_by_count(count, prop); + else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) + rc = dlpar_memory_add_by_index(drc_index, prop); + else + rc = -EINVAL; + break; default: pr_err("Invalid action (%d) specified\n", hp_elog->action); rc = -EINVAL; break; } + if (rc) + dlpar_free_drconf_property(prop); + else + dlpar_update_drconf_property(dn, prop); + + of_node_put(dn); unlock_device_hotplug(); return rc; } @@ -193,6 +454,9 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr) __be32 *p; int i, rc = -EINVAL; + if (rtas_hp_event) + return 0; + memblock_size = pseries_memory_block_size(); if (!memblock_size) return -EINVAL; -- GitLab From 51925fb3c5c901aa06cdc853268a6e19e19bcdc7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 10 Feb 2015 13:49:22 -0600 Subject: [PATCH 0414/1910] powerpc/pseries: Implement memory hotplug remove in the kernel This patch adds the ability to do memory hotplug remove in the kernel. Currently the operation to hotplug remove memory is handled by the drmgr command which performs the operation by performing some work in user-space and making requests to the kernel to handle other pieces. By moving all of the work to the kernel we can do the remove faster, and provide a common code path to do memory hotplug for both the PowerVM and PowerKVM environments. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- .../platforms/pseries/hotplug-memory.c | 192 +++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index f5eec0fc46df..742ef88ffd7b 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -188,6 +188,173 @@ static int pseries_remove_mem_node(struct device_node *np) pseries_remove_memblock(base, lmb_size); return 0; } + +static bool lmb_is_removable(struct of_drconf_cell *lmb) +{ + int i, scns_per_block; + int rc = 1; + unsigned long pfn, block_sz; + u64 phys_addr; + + if (!(lmb->flags & DRCONF_MEM_ASSIGNED)) + return false; + + block_sz = memory_block_size_bytes(); + scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; + phys_addr = lmb->base_addr; + + for (i = 0; i < scns_per_block; i++) { + pfn = PFN_DOWN(phys_addr); + if (!pfn_present(pfn)) + continue; + + rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION); + phys_addr += MIN_MEMORY_BLOCK_SIZE; + } + + return rc ? true : false; +} + +static int dlpar_add_lmb(struct of_drconf_cell *); + +static int dlpar_remove_lmb(struct of_drconf_cell *lmb) +{ + struct memory_block *mem_block; + unsigned long block_sz; + int nid, rc; + + if (!lmb_is_removable(lmb)) + return -EINVAL; + + mem_block = lmb_to_memblock(lmb); + if (!mem_block) + return -EINVAL; + + rc = device_offline(&mem_block->dev); + put_device(&mem_block->dev); + if (rc) + return rc; + + block_sz = pseries_memory_block_size(); + nid = memory_add_physaddr_to_nid(lmb->base_addr); + + remove_memory(nid, lmb->base_addr, block_sz); + + /* Update memory regions for memory remove */ + memblock_remove(lmb->base_addr, block_sz); + + dlpar_release_drc(lmb->drc_index); + + lmb->flags &= ~DRCONF_MEM_ASSIGNED; + return 0; +} + +static int dlpar_memory_remove_by_count(u32 lmbs_to_remove, + struct property *prop) +{ + struct of_drconf_cell *lmbs; + int lmbs_removed = 0; + int lmbs_available = 0; + u32 num_lmbs, *p; + int i, rc; + + pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove); + + if (lmbs_to_remove == 0) + return -EINVAL; + + p = prop->value; + num_lmbs = *p++; + lmbs = (struct of_drconf_cell *)p; + + /* Validate that there are enough LMBs to satisfy the request */ + for (i = 0; i < num_lmbs; i++) { + if (lmbs[i].flags & DRCONF_MEM_ASSIGNED) + lmbs_available++; + } + + if (lmbs_available < lmbs_to_remove) + return -EINVAL; + + for (i = 0; i < num_lmbs && lmbs_removed < lmbs_to_remove; i++) { + rc = dlpar_remove_lmb(&lmbs[i]); + if (rc) + continue; + + lmbs_removed++; + + /* Mark this lmb so we can add it later if all of the + * requested LMBs cannot be removed. + */ + lmbs[i].reserved = 1; + } + + if (lmbs_removed != lmbs_to_remove) { + pr_err("Memory hot-remove failed, adding LMB's back\n"); + + for (i = 0; i < num_lmbs; i++) { + if (!lmbs[i].reserved) + continue; + + rc = dlpar_add_lmb(&lmbs[i]); + if (rc) + pr_err("Failed to add LMB back, drc index %x\n", + lmbs[i].drc_index); + + lmbs[i].reserved = 0; + } + + rc = -EINVAL; + } else { + for (i = 0; i < num_lmbs; i++) { + if (!lmbs[i].reserved) + continue; + + pr_info("Memory at %llx was hot-removed\n", + lmbs[i].base_addr); + + lmbs[i].reserved = 0; + } + rc = 0; + } + + return rc; +} + +static int dlpar_memory_remove_by_index(u32 drc_index, struct property *prop) +{ + struct of_drconf_cell *lmbs; + u32 num_lmbs, *p; + int lmb_found; + int i, rc; + + pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index); + + p = prop->value; + num_lmbs = *p++; + lmbs = (struct of_drconf_cell *)p; + + lmb_found = 0; + for (i = 0; i < num_lmbs; i++) { + if (lmbs[i].drc_index == drc_index) { + lmb_found = 1; + rc = dlpar_remove_lmb(&lmbs[i]); + break; + } + } + + if (!lmb_found) + rc = -EINVAL; + + if (rc) + pr_info("Failed to hot-remove memory at %llx\n", + lmbs[i].base_addr); + else + pr_info("Memory at %llx was hot-removed\n", lmbs[i].base_addr); + + return rc; +} + #else static inline int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) @@ -198,6 +365,11 @@ static inline int pseries_remove_mem_node(struct device_node *np) { return 0; } +static inline int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_MEMORY_HOTREMOVE */ static int dlpar_add_lmb(struct of_drconf_cell *lmb) @@ -292,7 +464,17 @@ static int dlpar_memory_add_by_count(u32 lmbs_to_add, struct property *prop) } if (lmbs_added != lmbs_to_add) { - /* TODO: remove added lmbs */ + pr_err("Memory hot-add failed, removing any added LMBs\n"); + + for (i = 0; i < num_lmbs; i++) { + if (!lmbs[i].reserved) + continue; + + rc = dlpar_remove_lmb(&lmbs[i]); + if (rc) + pr_err("Failed to remove LMB, drc index %x\n", + be32_to_cpu(lmbs[i].drc_index)); + } rc = -EINVAL; } else { for (i = 0; i < num_lmbs; i++) { @@ -398,6 +580,14 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog) else rc = -EINVAL; break; + case PSERIES_HP_ELOG_ACTION_REMOVE: + if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) + rc = dlpar_memory_remove_by_count(count, prop); + else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) + rc = dlpar_memory_remove_by_index(drc_index, prop); + else + rc = -EINVAL; + break; default: pr_err("Invalid action (%d) specified\n", hp_elog->action); rc = -EINVAL; -- GitLab From b05ae4ee602b7dc90771408ccf0972e1b3801a35 Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Mon, 14 Nov 2011 21:32:10 -0500 Subject: [PATCH 0415/1910] powerpc: Remove duplicate cacheable_memcpy/memzero functions These functions are only used from one place each. If the cacheable_* versions really are more efficient, then those changes should be migrated into the common code instead. NOTE: The old routines are just flat buggy on kernels that support hardware with different cacheline sizes. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/cache.h | 3 - arch/powerpc/lib/copy_32.S | 127 --------------------------- arch/powerpc/lib/ppc_ksyms.c | 4 - arch/powerpc/mm/ppc_mmu_32.c | 2 +- drivers/net/ethernet/ibm/emac/core.c | 12 +-- 5 files changed, 3 insertions(+), 145 deletions(-) diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 34a05a1a990b..0dc42c5082b7 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -76,9 +76,6 @@ extern void _set_L3CR(unsigned long); #define _set_L3CR(val) do { } while(0) #endif -extern void cacheable_memzero(void *p, unsigned int nb); -extern void *cacheable_memcpy(void *, const void *, unsigned int); - #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_CACHE_H */ diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S index 55f19f9fd708..6813f80d1eec 100644 --- a/arch/powerpc/lib/copy_32.S +++ b/arch/powerpc/lib/copy_32.S @@ -69,54 +69,6 @@ CACHELINE_BYTES = L1_CACHE_BYTES LG_CACHELINE_BYTES = L1_CACHE_SHIFT CACHELINE_MASK = (L1_CACHE_BYTES-1) -/* - * Use dcbz on the complete cache lines in the destination - * to set them to zero. This requires that the destination - * area is cacheable. -- paulus - */ -_GLOBAL(cacheable_memzero) - mr r5,r4 - li r4,0 - addi r6,r3,-4 - cmplwi 0,r5,4 - blt 7f - stwu r4,4(r6) - beqlr - andi. r0,r6,3 - add r5,r0,r5 - subf r6,r0,r6 - clrlwi r7,r6,32-LG_CACHELINE_BYTES - add r8,r7,r5 - srwi r9,r8,LG_CACHELINE_BYTES - addic. r9,r9,-1 /* total number of complete cachelines */ - ble 2f - xori r0,r7,CACHELINE_MASK & ~3 - srwi. r0,r0,2 - beq 3f - mtctr r0 -4: stwu r4,4(r6) - bdnz 4b -3: mtctr r9 - li r7,4 -10: dcbz r7,r6 - addi r6,r6,CACHELINE_BYTES - bdnz 10b - clrlwi r5,r8,32-LG_CACHELINE_BYTES - addi r5,r5,4 -2: srwi r0,r5,2 - mtctr r0 - bdz 6f -1: stwu r4,4(r6) - bdnz 1b -6: andi. r5,r5,3 -7: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r6,3 -8: stbu r4,1(r6) - bdnz 8b - blr - _GLOBAL(memset) rlwimi r4,r4,8,16,23 rlwimi r4,r4,16,0,15 @@ -142,85 +94,6 @@ _GLOBAL(memset) bdnz 8b blr -/* - * This version uses dcbz on the complete cache lines in the - * destination area to reduce memory traffic. This requires that - * the destination area is cacheable. - * We only use this version if the source and dest don't overlap. - * -- paulus. - */ -_GLOBAL(cacheable_memcpy) - add r7,r3,r5 /* test if the src & dst overlap */ - add r8,r4,r5 - cmplw 0,r4,r7 - cmplw 1,r3,r8 - crand 0,0,4 /* cr0.lt &= cr1.lt */ - blt memcpy /* if regions overlap */ - - addi r4,r4,-4 - addi r6,r3,-4 - neg r0,r3 - andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ - beq 58f - - cmplw 0,r5,r0 /* is this more than total to do? */ - blt 63f /* if not much to do */ - andi. r8,r0,3 /* get it word-aligned first */ - subf r5,r0,r5 - mtctr r8 - beq+ 61f -70: lbz r9,4(r4) /* do some bytes */ - stb r9,4(r6) - addi r4,r4,1 - addi r6,r6,1 - bdnz 70b -61: srwi. r0,r0,2 - mtctr r0 - beq 58f -72: lwzu r9,4(r4) /* do some words */ - stwu r9,4(r6) - bdnz 72b - -58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ - clrlwi r5,r5,32-LG_CACHELINE_BYTES - li r11,4 - mtctr r0 - beq 63f -53: - dcbz r11,r6 - COPY_16_BYTES -#if L1_CACHE_BYTES >= 32 - COPY_16_BYTES -#if L1_CACHE_BYTES >= 64 - COPY_16_BYTES - COPY_16_BYTES -#if L1_CACHE_BYTES >= 128 - COPY_16_BYTES - COPY_16_BYTES - COPY_16_BYTES - COPY_16_BYTES -#endif -#endif -#endif - bdnz 53b - -63: srwi. r0,r5,2 - mtctr r0 - beq 64f -30: lwzu r0,4(r4) - stwu r0,4(r6) - bdnz 30b - -64: andi. r0,r5,3 - mtctr r0 - beq+ 65f -40: lbz r0,4(r4) - stb r0,4(r6) - addi r4,r4,1 - addi r6,r6,1 - bdnz 40b -65: blr - _GLOBAL(memmove) cmplw 0,r3,r4 bgt backwards_memcpy diff --git a/arch/powerpc/lib/ppc_ksyms.c b/arch/powerpc/lib/ppc_ksyms.c index f993959647b5..c7f8e9586316 100644 --- a/arch/powerpc/lib/ppc_ksyms.c +++ b/arch/powerpc/lib/ppc_ksyms.c @@ -8,10 +8,6 @@ EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memchr); -#ifdef CONFIG_PPC32 -EXPORT_SYMBOL(cacheable_memcpy); -EXPORT_SYMBOL(cacheable_memzero); -#endif EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index 5029dc19b517..eb0e489b1bb7 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -224,7 +224,7 @@ void __init MMU_init_hw(void) */ if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); Hash = __va(memblock_alloc(Hash_size, Hash_size)); - cacheable_memzero(Hash, Hash_size); + memset(Hash, 0, Hash_size); _SDR1 = __pa(Hash) | SDR1_LOW_BITS; Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size); diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 162762d1a12c..220bae6f5e43 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -79,13 +79,6 @@ MODULE_AUTHOR ("Eugene Surovegin or "); MODULE_LICENSE("GPL"); -/* - * PPC64 doesn't (yet) have a cacheable_memcpy - */ -#ifdef CONFIG_PPC64 -#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n)) -#endif - /* minimum number of free TX descriptors required to wake up TX process */ #define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) @@ -1673,7 +1666,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot) dev_kfree_skb(dev->rx_sg_skb); dev->rx_sg_skb = NULL; } else { - cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb), + memcpy(skb_tail_pointer(dev->rx_sg_skb), dev->rx_skb[slot]->data, len); skb_put(dev->rx_sg_skb, len); emac_recycle_rx_skb(dev, slot, len); @@ -1730,8 +1723,7 @@ static int emac_poll_rx(void *param, int budget) goto oom; skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); - cacheable_memcpy(copy_skb->data - 2, skb->data - 2, - len + 2); + memcpy(copy_skb->data - 2, skb->data - 2, len + 2); emac_recycle_rx_skb(dev, slot, len); skb = copy_skb; } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) -- GitLab From ffa3eb010dd8edc696cd958ba684d8a6d1cf3dff Mon Sep 17 00:00:00 2001 From: Phil Carmody Date: Wed, 17 Sep 2014 01:00:53 +0300 Subject: [PATCH 0416/1910] powerpc/via-pmu: fix error path in find_via_pmu() Cleanup was not in the reverse order from the set-up, so not all the gotos made sense, and also it was being avoided completely upon failure of init_pmu(). Signed-off-by: Phil Carmody Signed-off-by: Aaro Koskinen Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/via-pmu.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index dee88e59f0d3..62212358640d 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -332,7 +332,7 @@ int __init find_via_pmu(void) } if (gpio_reg == NULL) { printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n"); - goto fail_gpio; + goto fail; } } else pmu_kind = PMU_UNKNOWN; @@ -340,7 +340,7 @@ int __init find_via_pmu(void) via = ioremap(taddr, 0x2000); if (via == NULL) { printk(KERN_ERR "via-pmu: Can't map address !\n"); - goto fail; + goto fail_via_remap; } out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -348,10 +348,8 @@ int __init find_via_pmu(void) pmu_state = idle; - if (!init_pmu()) { - via = NULL; - return 0; - } + if (!init_pmu()) + goto fail_init; printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n", PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); @@ -359,11 +357,15 @@ int __init find_via_pmu(void) sys_ctrler = SYS_CTRLER_PMU; return 1; - fail: - of_node_put(vias); + + fail_init: + iounmap(via); + via = NULL; + fail_via_remap: iounmap(gpio_reg); gpio_reg = NULL; - fail_gpio: + fail: + of_node_put(vias); vias = NULL; return 0; } -- GitLab From e702240e8364952e260829c8700fbc870aa4b053 Mon Sep 17 00:00:00 2001 From: Phil Carmody Date: Wed, 17 Sep 2014 01:00:54 +0300 Subject: [PATCH 0417/1910] powerpc/via-pmu: fix OF node leak in Keylargo init If we of_find_node_by_name() then we must of_node_put() too. Signed-off-by: Phil Carmody Signed-off-by: Aaro Koskinen Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/via-pmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 62212358640d..aed3cb07a6fa 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -329,6 +329,7 @@ int __init find_via_pmu(void) gaddr = of_translate_address(gpiop, reg); if (gaddr != OF_BAD_ADDR) gpio_reg = ioremap(gaddr, 0x10); + of_node_put(gpiop); } if (gpio_reg == NULL) { printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n"); -- GitLab From 8edcee0e1f7dd703a2f3049ea1bc8c19bd945eb6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 17 Mar 2015 15:16:12 +1100 Subject: [PATCH 0418/1910] selftests/powerpc: Build the copyloops with -maltivec The recent change to remove the vrX defines exposed the fact that we are building the copyloops tests without altivec enabled. It depends on the toolchain as to whether altivec is on by default or not, so it only breaks on some toolchains. But we should always enable it. Fixes: c2ce6f9f3dc0 ("powerpc: Change vrX register defines to vX to match gcc and glibc") Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/copyloops/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index 6f2d3be227f9..9de81296ebc4 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -2,6 +2,7 @@ CFLAGS += -m64 CFLAGS += -I$(CURDIR) CFLAGS += -D SELFTEST +CFLAGS += -maltivec # Use our CFLAGS for the implicit .S rule ASFLAGS = $(CFLAGS) -- GitLab From a02c0af2f0c4b3c85e828f60ac3459456cfad1e6 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sat, 26 Jul 2014 18:45:05 +0200 Subject: [PATCH 0419/1910] powerpc/powermac: Cleaning up missing null-terminate in conjunction with strncpy Replacing strncpy with strlcpy to avoid strings that lacks null terminate. And removed unnecessary magic numbers. Signed-off-by: Rickard Strandqvist Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/bootx_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 3e91ef538114..76f5013c35e5 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -246,7 +246,7 @@ static void __init bootx_scan_dt_build_strings(unsigned long base, DBG(" detected display ! adding properties names !\n"); bootx_dt_add_string("linux,boot-display", mem_end); bootx_dt_add_string("linux,opened", mem_end); - strncpy(bootx_disp_path, namep, 255); + strlcpy(bootx_disp_path, namep, sizeof(bootx_disp_path)); } /* get and store all property names */ -- GitLab From ee23d66af9219dfe2407a9b08ef9a165dbe6f994 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Thu, 26 Jun 2014 19:09:42 +0530 Subject: [PATCH 0420/1910] mailbox: arm_mhu: add driver for ARM MHU controller Add driver for the ARM Primecell Message-Handling-Unit(MHU) controller. Signed-off-by: Jassi Brar Signed-off-by: Andy Green Signed-off-by: Vincent Yang Signed-off-by: Tetsuya Nuriya --- .../devicetree/bindings/mailbox/arm-mhu.txt | 43 ++++ drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/arm_mhu.c | 195 ++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/arm-mhu.txt create mode 100644 drivers/mailbox/arm_mhu.c diff --git a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt new file mode 100644 index 000000000000..4971f03f0b33 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt @@ -0,0 +1,43 @@ +ARM MHU Mailbox Driver +====================== + +The ARM's Message-Handling-Unit (MHU) is a mailbox controller that has +3 independent channels/links to communicate with remote processor(s). + MHU links are hardwired on a platform. A link raises interrupt for any +received data. However, there is no specified way of knowing if the sent +data has been read by the remote. This driver assumes the sender polls +STAT register and the remote clears it after having read the data. +The last channel is specified to be a 'Secure' resource, hence can't be +used by Linux running NS. + +Mailbox Device Node: +==================== + +Required properties: +-------------------- +- compatible: Shall be "arm,mhu" & "arm,primecell" +- reg: Contains the mailbox register address range (base + address and length) +- #mbox-cells Shall be 1 - the index of the channel needed. +- interrupts: Contains the interrupt information corresponding to + each of the 3 links of MHU. + +Example: +-------- + + mhu: mailbox@2b1f0000 { + #mbox-cells = <1>; + compatible = "arm,mhu", "arm,primecell"; + reg = <0 0x2b1f0000 0x1000>; + interrupts = <0 36 4>, /* LP-NonSecure */ + <0 35 4>, /* HP-NonSecure */ + <0 37 4>; /* Secure */ + clocks = <&clock 0 2 1>; + clock-names = "apb_pclk"; + }; + + mhu_client: scb@2e000000 { + compatible = "fujitsu,mb86s70-scb-1.0"; + reg = <0 0x2e000000 0x4000>; + mboxes = <&mhu 1>; /* HP-NonSecure */ + }; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 84325f267acf..84b0a2d74d60 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -6,6 +6,15 @@ menuconfig MAILBOX signals. Say Y if your platform supports hardware mailboxes. if MAILBOX + +config ARM_MHU + tristate "ARM MHU Mailbox" + depends on ARM_AMBA + help + Say Y here if you want to build the ARM MHU controller driver. + The controller has 3 mailbox channels, the last of which can be + used in Secure mode only. + config PL320_MBOX bool "ARM PL320 Mailbox" depends on ARM_AMBA diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 2e79231154cf..b18201e97e29 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -2,6 +2,8 @@ obj-$(CONFIG_MAILBOX) += mailbox.o +obj-$(CONFIG_ARM_MHU) += arm_mhu.o + obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c new file mode 100644 index 000000000000..ac693c635357 --- /dev/null +++ b/drivers/mailbox/arm_mhu.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd. + * Copyright (C) 2015 Linaro Ltd. + * Author: Jassi Brar + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTR_STAT_OFS 0x0 +#define INTR_SET_OFS 0x8 +#define INTR_CLR_OFS 0x10 + +#define MHU_LP_OFFSET 0x0 +#define MHU_HP_OFFSET 0x20 +#define MHU_SEC_OFFSET 0x200 +#define TX_REG_OFFSET 0x100 + +#define MHU_CHANS 3 + +struct mhu_link { + unsigned irq; + void __iomem *tx_reg; + void __iomem *rx_reg; +}; + +struct arm_mhu { + void __iomem *base; + struct mhu_link mlink[MHU_CHANS]; + struct mbox_chan chan[MHU_CHANS]; + struct mbox_controller mbox; +}; + +static irqreturn_t mhu_rx_interrupt(int irq, void *p) +{ + struct mbox_chan *chan = p; + struct mhu_link *mlink = chan->con_priv; + u32 val; + + val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS); + if (!val) + return IRQ_NONE; + + mbox_chan_received_data(chan, (void *)&val); + + writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS); + + return IRQ_HANDLED; +} + +static bool mhu_last_tx_done(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); + + return (val == 0); +} + +static int mhu_send_data(struct mbox_chan *chan, void *data) +{ + struct mhu_link *mlink = chan->con_priv; + u32 *arg = data; + + writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS); + + return 0; +} + +static int mhu_startup(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + u32 val; + int ret; + + val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); + writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS); + + ret = request_irq(mlink->irq, mhu_rx_interrupt, + IRQF_SHARED, "mhu_link", chan); + if (ret) { + dev_err(chan->mbox->dev, + "Unable to aquire IRQ %d\n", mlink->irq); + return ret; + } + + return 0; +} + +static void mhu_shutdown(struct mbox_chan *chan) +{ + struct mhu_link *mlink = chan->con_priv; + + free_irq(mlink->irq, chan); +} + +static struct mbox_chan_ops mhu_ops = { + .send_data = mhu_send_data, + .startup = mhu_startup, + .shutdown = mhu_shutdown, + .last_tx_done = mhu_last_tx_done, +}; + +static int mhu_probe(struct amba_device *adev, const struct amba_id *id) +{ + int i, err; + struct arm_mhu *mhu; + struct device *dev = &adev->dev; + int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET}; + + /* Allocate memory for device */ + mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL); + if (!mhu) + return -ENOMEM; + + mhu->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(mhu->base)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(mhu->base); + } + + for (i = 0; i < MHU_CHANS; i++) { + mhu->chan[i].con_priv = &mhu->mlink[i]; + mhu->mlink[i].irq = adev->irq[i]; + mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; + mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; + } + + mhu->mbox.dev = dev; + mhu->mbox.chans = &mhu->chan[0]; + mhu->mbox.num_chans = MHU_CHANS; + mhu->mbox.ops = &mhu_ops; + mhu->mbox.txdone_irq = false; + mhu->mbox.txdone_poll = true; + mhu->mbox.txpoll_period = 10; + + amba_set_drvdata(adev, mhu); + + err = mbox_controller_register(&mhu->mbox); + if (err) { + dev_err(dev, "Failed to register mailboxes %d\n", err); + return err; + } + + dev_info(dev, "ARM MHU Mailbox registered\n"); + return 0; +} + +static int mhu_remove(struct amba_device *adev) +{ + struct arm_mhu *mhu = amba_get_drvdata(adev); + + mbox_controller_unregister(&mhu->mbox); + + return 0; +} + +static struct amba_id mhu_ids[] = { + { + .id = 0x1bb098, + .mask = 0xffffff, + }, + { 0, 0 }, +}; +MODULE_DEVICE_TABLE(amba, mhu_ids); + +static struct amba_driver arm_mhu_driver = { + .drv = { + .name = "mhu", + }, + .id_table = mhu_ids, + .probe = mhu_probe, + .remove = mhu_remove, +}; +module_amba_driver(arm_mhu_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ARM MHU Driver"); +MODULE_AUTHOR("Jassi Brar "); -- GitLab From d610f503612ddb5bf55e477fd48c678b3deab7ca Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:42 +0800 Subject: [PATCH 0421/1910] sata_svw: remove the dependency on PPC_OF The OF functionality has moved to a common place and be used by many archs. So we don't need to include the ppc arch specific header files and depend on PPC_OF option any more. This is a preparation for killing PPC_OF. Signed-off-by: Kevin Hao Acked-by: Tejun Heo Acked-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- drivers/ata/sata_svw.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index c630fa812624..4c06f6281d74 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -47,11 +47,7 @@ #include #include #include - -#ifdef CONFIG_PPC_OF -#include -#include -#endif /* CONFIG_PPC_OF */ +#include #define DRV_NAME "sata_svw" #define DRV_VERSION "2.3" @@ -320,7 +316,6 @@ static u8 k2_stat_check_status(struct ata_port *ap) return readl(ap->ioaddr.status_addr); } -#ifdef CONFIG_PPC_OF static int k2_sata_show_info(struct seq_file *m, struct Scsi_Host *shost) { struct ata_port *ap; @@ -350,14 +345,10 @@ static int k2_sata_show_info(struct seq_file *m, struct Scsi_Host *shost) } return 0; } -#endif /* CONFIG_PPC_OF */ - static struct scsi_host_template k2_sata_sht = { ATA_BMDMA_SHT(DRV_NAME), -#ifdef CONFIG_PPC_OF .show_info = k2_sata_show_info, -#endif }; -- GitLab From e7b410ef74b3d917db2545086578b663bed19d81 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:43 +0800 Subject: [PATCH 0422/1910] fbdev: aty128fb: replace PPC_OF with PPC The PPC_OF is a ppc specific option which is used to mean that the firmware device tree access functions are available. Since all the ppc platforms have a device tree, it is aways set to 'y' for ppc. So it makes no sense to keep a such option in the current kernel. Replace it with PPC. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/aty/aty128fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index aedf2fbf9bf6..0156954bf340 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -965,7 +965,7 @@ static void __iomem *aty128_find_mem_vbios(struct aty128fb_par *par) /* fill in known card constants if pll_block is not available */ static void aty128_timings(struct aty128fb_par *par) { -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC /* instead of a table lookup, assume OF has properly * setup the PLL registers and use their values * to set the XCLK values and reference divider values */ @@ -979,7 +979,7 @@ static void aty128_timings(struct aty128fb_par *par) if (!par->constants.ref_clk) par->constants.ref_clk = 2950; -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; -- GitLab From 758ddd1d11da5616851dd0d269e321cd1d2d4c1b Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:44 +0800 Subject: [PATCH 0423/1910] fbdev: radeon: replace PPC_OF with PPC The PPC_OF is a ppc specific option which is used to mean that the firmware device tree access functions are available. Since all the ppc platforms have a device tree, it is aways set to 'y' for ppc. So it makes no sense to keep a such option in the current kernel. Replace it with PPC. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/Kconfig | 2 +- drivers/video/fbdev/aty/radeon_base.c | 24 ++++++++++++------------ drivers/video/fbdev/aty/radeon_monitor.c | 20 ++++++++++---------- drivers/video/fbdev/aty/radeon_pm.c | 16 ++++++++-------- drivers/video/fbdev/aty/radeonfb.h | 4 ++-- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index b3dd417b4719..3b818d7a0983 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1333,7 +1333,7 @@ config FB_RADEON select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC_OF + select FB_MACMODES if PPC help Choose this option if you want to use an ATI Radeon graphics card as a framebuffer device. There are both PCI and AGP versions. You diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index 26d80a4486fb..01237c8fcdc6 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -74,7 +74,7 @@ #include #include -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC #include #include "../macmodes.h" @@ -83,7 +83,7 @@ #include #endif -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ #ifdef CONFIG_MTRR #include @@ -418,7 +418,7 @@ static int radeon_find_mem_vbios(struct radeonfb_info *rinfo) } #endif -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) /* * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device * tree. Hopefully, ATI OF driver is kind enough to fill these @@ -448,7 +448,7 @@ static int radeon_read_xtal_OF(struct radeonfb_info *rinfo) return 0; } -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#endif /* CONFIG_PPC || CONFIG_SPARC */ /* * Read PLL infos from chip registers @@ -653,7 +653,7 @@ static void radeon_get_pllinfo(struct radeonfb_info *rinfo) rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) /* * Retrieve PLL infos from Open Firmware first */ @@ -661,7 +661,7 @@ static void radeon_get_pllinfo(struct radeonfb_info *rinfo) printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n"); goto found; } -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#endif /* CONFIG_PPC || CONFIG_SPARC */ /* * Check out if we have an X86 which gave us some PLL informations @@ -1910,7 +1910,7 @@ static int radeon_set_fbinfo(struct radeonfb_info *rinfo) * I put the card's memory at 0 in card space and AGP at some random high * local (0xe0000000 for now) that will be changed by XFree/DRI anyway */ -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC #undef SET_MC_FB_FROM_APERTURE static void fixup_memory_mappings(struct radeonfb_info *rinfo) { @@ -1984,7 +1984,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 0xffff0000 | (agp_base >> 16)); } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ static void radeon_identify_vram(struct radeonfb_info *rinfo) @@ -2236,7 +2236,7 @@ static int radeonfb_pci_register(struct pci_dev *pdev, rinfo->family == CHIP_FAMILY_RS200) rinfo->errata |= CHIP_ERRATA_PLL_DELAY; -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) /* On PPC, we obtain the OF device-node pointer to the firmware * data for this chip */ @@ -2245,14 +2245,14 @@ static int radeonfb_pci_register(struct pci_dev *pdev, printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n", pci_name(rinfo->pdev)); -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ -#ifdef CONFIG_PPC_OF +#endif /* CONFIG_PPC || CONFIG_SPARC */ +#ifdef CONFIG_PPC /* On PPC, the firmware sets up a memory mapping that tends * to cause lockups when enabling the engine. We reconfigure * the card internal memory mappings properly */ fixup_memory_mappings(rinfo); -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ /* Get VRAM size and type */ radeon_identify_vram(rinfo); diff --git a/drivers/video/fbdev/aty/radeon_monitor.c b/drivers/video/fbdev/aty/radeon_monitor.c index bc078d50d8f1..f1ce229de78d 100644 --- a/drivers/video/fbdev/aty/radeon_monitor.c +++ b/drivers/video/fbdev/aty/radeon_monitor.c @@ -55,7 +55,7 @@ static char *radeon_get_mon_name(int type) } -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) /* * Try to find monitor informations & EDID data out of the Open Firmware * device-tree. This also contains some "hacks" to work around a few machine @@ -160,7 +160,7 @@ static int radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no, } return MT_NONE; } -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#endif /* CONFIG_PPC || CONFIG_SPARC */ static int radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) @@ -499,11 +499,11 @@ void radeon_probe_screens(struct radeonfb_info *rinfo, * Old single head cards */ if (!rinfo->has_CRTC2) { -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID); -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#endif /* CONFIG_PPC || CONFIG_SPARC */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = @@ -548,11 +548,11 @@ void radeon_probe_screens(struct radeonfb_info *rinfo, /* * Probe primary head (DVI or laptop internal panel) */ -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID); -#endif /* CONFIG_PPC_OF || CONFIG_SPARC */ +#endif /* CONFIG_PPC || CONFIG_SPARC */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon1_type == MT_NONE) rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, @@ -576,11 +576,11 @@ void radeon_probe_screens(struct radeonfb_info *rinfo, /* * Probe secondary head (mostly VGA, can be DVI) */ -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) if (rinfo->mon2_type == MT_NONE) rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, &rinfo->mon2_EDID); -#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */ +#endif /* CONFIG_PPC || defined(CONFIG_SPARC) */ #ifdef CONFIG_FB_RADEON_I2C if (rinfo->mon2_type == MT_NONE) rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga, @@ -653,7 +653,7 @@ void radeon_probe_screens(struct radeonfb_info *rinfo, */ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) { -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC /* * LCD Flat panels should use fixed dividers, we enfore that on * PPC only for now... @@ -676,7 +676,7 @@ static void radeon_fixup_panel_info(struct radeonfb_info *rinfo) (rinfo->panel_info.post_divider << 16), ppll_div_sel); } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ } diff --git a/drivers/video/fbdev/aty/radeon_pm.c b/drivers/video/fbdev/aty/radeon_pm.c index 46a12f1a93c3..1417542738fc 100644 --- a/drivers/video/fbdev/aty/radeon_pm.c +++ b/drivers/video/fbdev/aty/radeon_pm.c @@ -523,7 +523,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo) OUTPLL(pllVCLK_ECP_CNTL, tmp); /* X doesn't do that ... hrm, we do on mobility && Macs */ -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC if (rinfo->is_mobility) { tmp = INPLL(pllMCLK_CNTL); tmp &= ~(MCLK_CNTL__FORCE_MCLKA | @@ -541,7 +541,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo) OUTPLL(pllMCLK_MISC, tmp); radeon_msleep(15); } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ } #ifdef CONFIG_PM @@ -1288,7 +1288,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) radeon_pm_enable_dll_m10(rinfo); radeon_pm_yclk_mclk_sync_m10(rinfo); -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC if (rinfo->of_node != NULL) { int size; @@ -1298,7 +1298,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) else mrtable = default_mrtable; } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ /* Program the SDRAM */ sdram_mode_reg = mrtable[0]; @@ -1943,7 +1943,7 @@ static void radeon_reinitialize_M10(struct radeonfb_info *rinfo) } #endif -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC #ifdef CONFIG_PPC_PMAC static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo) { @@ -2512,7 +2512,7 @@ static void radeon_reinitialize_QW(struct radeonfb_info *rinfo) } #endif /* 0 */ -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ static void radeonfb_whack_power_state(struct radeonfb_info *rinfo, pci_power_t state) { @@ -2793,7 +2793,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev) return rc; } -#ifdef CONFIG_PPC_OF__disabled +#ifdef CONFIG_PPC__disabled static void radeonfb_early_resume(void *data) { struct radeonfb_info *rinfo = data; @@ -2803,7 +2803,7 @@ static void radeonfb_early_resume(void *data) radeonfb_pci_resume(rinfo->pdev); rinfo->no_schedule = 0; } -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC */ #endif /* CONFIG_PM */ diff --git a/drivers/video/fbdev/aty/radeonfb.h b/drivers/video/fbdev/aty/radeonfb.h index cb846044f57c..039def41c920 100644 --- a/drivers/video/fbdev/aty/radeonfb.h +++ b/drivers/video/fbdev/aty/radeonfb.h @@ -20,7 +20,7 @@ #include -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) #include #endif @@ -301,7 +301,7 @@ struct radeonfb_info { unsigned long fb_local_base; struct pci_dev *pdev; -#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC) +#if defined(CONFIG_PPC) || defined(CONFIG_SPARC) struct device_node *of_node; #endif -- GitLab From e9cfb2d62befcd562291e6a8a63d3bdff89b135b Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:45 +0800 Subject: [PATCH 0424/1910] fbdev: imsttfb: remove the dependency on PPC_OF The OF functionality has moved to a common place and be used by many archs. So we don't need to depend on PPC_OF option any more. This is a preparation for killing PPC_OF. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/imsttfb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c index aae10ce74f14..9b167f7ef6c6 100644 --- a/drivers/video/fbdev/imsttfb.c +++ b/drivers/video/fbdev/imsttfb.c @@ -1470,15 +1470,13 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned long addr, size; struct imstt_par *par; struct fb_info *info; -#ifdef CONFIG_PPC_OF struct device_node *dp; dp = pci_device_to_OF_node(pdev); if(dp) printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name); - else + else if (IS_ENABLED(CONFIG_OF)) printk(KERN_ERR "imsttfb: no OF node for pci device\n"); -#endif /* CONFIG_PPC_OF */ info = framebuffer_alloc(sizeof(struct imstt_par), &pdev->dev); @@ -1501,11 +1499,9 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) switch (pdev->device) { case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */ par->ramdac = IBM; -#ifdef CONFIG_PPC_OF if (dp && ((strcmp(dp->name, "IMS,tt128mb8") == 0) || (strcmp(dp->name, "IMS,tt128mb8A") == 0))) par->ramdac = TVP; -#endif /* CONFIG_PPC_OF */ break; case PCI_DEVICE_ID_IMS_TT3D: /* IMS,tt3d */ par->ramdac = TVP; -- GitLab From 5299b620977ed6b1edbbedd5d9641c0afa9780fe Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:46 +0800 Subject: [PATCH 0425/1910] fbdev: nvidia: remove the dependency on PPC_OF The OF functionality has moved to a common place and be used by many archs. So we don't need to include the ppc arch specific header files and depend on PPC_OF option any more. This is a preparation for killing PPC_OF. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/nvidia/Makefile | 3 +-- drivers/video/fbdev/nvidia/nv_of.c | 3 --- drivers/video/fbdev/nvidia/nv_proto.h | 8 -------- drivers/video/fbdev/nvidia/nvidia.c | 4 ---- 4 files changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/video/fbdev/nvidia/Makefile b/drivers/video/fbdev/nvidia/Makefile index ca47432113e0..917d3eb05feb 100644 --- a/drivers/video/fbdev/nvidia/Makefile +++ b/drivers/video/fbdev/nvidia/Makefile @@ -5,9 +5,8 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ - nv_accel.o + nv_accel.o nv_of.o nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o -nvidiafb-$(CONFIG_PPC_OF) += nv_of.o nvidiafb-objs := $(nvidiafb-y) diff --git a/drivers/video/fbdev/nvidia/nv_of.c b/drivers/video/fbdev/nvidia/nv_of.c index 3bc13df4b120..5f3e5179c25a 100644 --- a/drivers/video/fbdev/nvidia/nv_of.c +++ b/drivers/video/fbdev/nvidia/nv_of.c @@ -19,9 +19,6 @@ #include -#include -#include - #include "nv_type.h" #include "nv_local.h" #include "nv_proto.h" diff --git a/drivers/video/fbdev/nvidia/nv_proto.h b/drivers/video/fbdev/nvidia/nv_proto.h index ff5c410355ea..878a5ce02299 100644 --- a/drivers/video/fbdev/nvidia/nv_proto.h +++ b/drivers/video/fbdev/nvidia/nv_proto.h @@ -42,16 +42,8 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, #define nvidia_probe_i2c_connector(p, c, edid) (-1) #endif -#ifdef CONFIG_PPC_OF int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 ** out_edid); -#else -static inline int nvidia_probe_of_connector(struct fb_info *info, int conn, - u8 ** out_edid) -{ - return -1; -} -#endif /* in nv_accel.c */ extern void NVResetGraphics(struct fb_info *info); diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index def041204676..4273c6ee8cf6 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -24,10 +24,6 @@ #ifdef CONFIG_MTRR #include #endif -#ifdef CONFIG_PPC_OF -#include -#include -#endif #ifdef CONFIG_BOOTX_TEXT #include #endif -- GitLab From d14c374c2e4d2a42692d7fddf86f7261fbe99c5a Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:47 +0800 Subject: [PATCH 0426/1910] fbdev: riva: remove the dependency on PPC_OF The OF functionality has moved to a common place and be used by many archs. So we don't need to include the ppc arch specific header files and depend on PPC_OF option any more. This is a preparation for killing PPC_OF. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/riva/fbdev.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index be73727c7227..294a80908c8c 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -44,10 +44,6 @@ #ifdef CONFIG_MTRR #include #endif -#ifdef CONFIG_PPC_OF -#include -#include -#endif #ifdef CONFIG_PMAC_BACKLIGHT #include #include @@ -1735,7 +1731,6 @@ static int riva_set_fbinfo(struct fb_info *info) return (rivafb_check_var(&info->var, info)); } -#ifdef CONFIG_PPC_OF static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) { struct riva_par *par = info->par; @@ -1766,9 +1761,8 @@ static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) NVTRACE_LEAVE(); return 0; } -#endif /* CONFIG_PPC_OF */ -#if defined(CONFIG_FB_RIVA_I2C) && !defined(CONFIG_PPC_OF) +#if defined(CONFIG_FB_RIVA_I2C) static int riva_get_EDID_i2c(struct fb_info *info) { struct riva_par *par = info->par; @@ -1828,10 +1822,13 @@ static void riva_update_default_var(struct fb_var_screeninfo *var, static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev) { NVTRACE_ENTER(); -#ifdef CONFIG_PPC_OF - if (!riva_get_EDID_OF(info, pdev)) + if (riva_get_EDID_OF(info, pdev)) { + NVTRACE_LEAVE(); + return; + } + if (IS_ENABLED(CONFIG_OF)) printk(PFX "could not retrieve EDID from OF\n"); -#elif defined(CONFIG_FB_RIVA_I2C) +#if defined(CONFIG_FB_RIVA_I2C) if (!riva_get_EDID_i2c(info)) printk(PFX "could not retrieve EDID from DDC/I2C\n"); #endif -- GitLab From 45ae00a50dbea917e3f06b30ba5fb8110be2402b Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Mar 2015 20:32:48 +0800 Subject: [PATCH 0427/1910] fbdev: remove the unnecessary includes of ppc specific header files In the current kernel, we don't need to include these arch specific header files for ppc. Signed-off-by: Kevin Hao Acked-by: Benjamin Herrenschmidt Acked-by: Tomi Valkeinen Signed-off-by: Michael Ellerman --- drivers/video/fbdev/core/fbmon.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 868facdec638..01ef1b953390 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -33,10 +33,6 @@ #include