From 30b03d05e07467b8c6ec683ea96b5bffcbcd3931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 26 Jun 2015 03:28:24 +0200 Subject: xen/gntdevt: Fix race condition in gntdev_release() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While gntdev_release() is called the MMU notifier is still registered and can traverse priv->maps list even if no pages are mapped (which is the case -- gntdev_release() is called after all). But gntdev_release() will clear that list, so make sure that only one of those things happens at the same time. Signed-off-by: Marek Marczykowski-Górecki Cc: Signed-off-by: David Vrabel diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 67b9163..0dbb222 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip) pr_debug("priv %p\n", priv); + mutex_lock(&priv->lock); while (!list_empty(&priv->maps)) { map = list_entry(priv->maps.next, struct grant_map, next); list_del(&map->next); gntdev_put_map(NULL /* already removed */, map); } WARN_ON(!list_empty(&priv->freeable_maps)); + mutex_unlock(&priv->lock); if (use_ptemod) mmu_notifier_unregister(&priv->mn, priv->mm); -- cgit v0.10.2 From cdeb1755d7b965ad0d58cff4db1cf6de4ba3b2ba Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 26 Jun 2015 16:28:13 -0300 Subject: [media] media/dvb: fix ts2020.c Kconfig and build Fix kconfig warning that is caused by DVB_TS2020: warning: (DVB_TS2020 && SND_SOC_ADAU1761_I2C && SND_SOC_ADAU1781_I2C && SND_SOC_ADAU1977_I2C && SND_SOC_RT5677 && EXTCON_MAX14577 && EXTCON_MAX77693 && EXTCON_MAX77843) selects REGMAP_I2C which has unmet direct dependencies (I2C) This fixes many subsequent build errors. Signed-off-by: Randy Dunlap Cc: Konstantin Dimitrov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 0d35f58..5ab90f3 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -240,7 +240,7 @@ config DVB_SI21XX config DVB_TS2020 tristate "Montage Tehnology TS2020 based tuners" - depends on DVB_CORE + depends on DVB_CORE && I2C select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help -- cgit v0.10.2 From 5bab86243d949cf021b0f104faafc18f5d20283c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 26 Jun 2015 17:43:24 -0300 Subject: [media] media/pci/cobalt: fix Kconfig and build when SND is not enabled Fix build errors in cobalt driver when CONFIG_SND is not enabled. Fixes these build errors: ERROR: "snd_pcm_period_elapsed" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "_snd_pcm_stream_lock_irqsave" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_pcm_hw_constraint_integer" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_pcm_set_ops" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_pcm_stream_unlock_irqrestore" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_pcm_lib_ioctl" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_card_new" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_card_free" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_card_register" [drivers/media/pci/cobalt/cobalt.ko] undefined! ERROR: "snd_pcm_new" [drivers/media/pci/cobalt/cobalt.ko] undefined! Signed-off-by: Randy Dunlap Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 3be1b2c..6a1c008 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -2,6 +2,7 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + depends on SND select I2C_ALGOBIT select VIDEO_ADV7604 select VIDEO_ADV7511 -- cgit v0.10.2 From efc4720dfbf737903ca4c1366bc45ca780d13412 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 20 Jun 2015 22:47:01 +0200 Subject: ASoC: Add gtm601 codec driver This driver add PCM interface to a GTM601 UMTS modem chip. There is no configuration interface. Signed-off-by: Marek Belisko Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..1b7c492 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C + select SND_SOC_GTM601 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -446,6 +447,9 @@ config SND_SOC_ES8328_SPI tristate select SND_SOC_ES8328 +config SND_SOC_GTM601 + tristate 'GTM601 UMTS modem audio codec' + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..365529d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-gtm601-objs := gtm601.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -242,6 +243,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c new file mode 100644 index 0000000..1b77ff2 --- /dev/null +++ b/sound/soc/codecs/gtm601.c @@ -0,0 +1,98 @@ +/* + * This is a simple driver for the GTM601 Voice PCM interface + * + * Copyright (C) 2015 Goldelico GmbH + * + * Author: Marek Belisko + * + * Based on wm8727.c driver + * + * This program is free software; you can 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 + +static const struct snd_soc_dapm_widget gtm601_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("AOUT"), + SND_SOC_DAPM_INPUT("AIN"), +}; + +static const struct snd_soc_dapm_route gtm601_dapm_routes[] = { + { "AOUT", NULL, "Playback" }, + { "Capture", NULL, "AIN" }, +}; + +struct snd_soc_dai_driver gtm601_dai = { + .name = "gtm601", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_gtm601 = { + .dapm_widgets = gtm601_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), + .dapm_routes = gtm601_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes), +}; + +static int gtm601_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_gtm601, >m601_dai, 1); +} + +static int gtm601_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +MODULE_ALIAS("platform:gtm601_codec_audio"); + +#if defined(CONFIG_OF) +static const struct of_device_id gtm601_codec_of_match[] = { + { .compatible = "option,gtm601", }, + {}, +}; +MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); +#endif + +static struct platform_driver gtm601_codec_driver = { + .driver = { + .name = "gtm601", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gtm601_codec_of_match), + }, + + .probe = gtm601_platform_probe, + .remove = gtm601_platform_remove, +}; + +module_platform_driver(gtm601_codec_driver); + +MODULE_DESCRIPTION("ASoC gtm601 driver"); +MODULE_AUTHOR("Marek Belisko "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 1fdc5ae80868637926e76a32e8c62cdd093b48f4 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 20 Jun 2015 22:47:02 +0200 Subject: Documentation: vendor-prefixes: Add option prefix Add option to vendor-prefixes file which will be used for Option NV company. Signed-off-by: Marek Belisko Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757..d247994 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -150,6 +150,7 @@ nvidia NVIDIA nxp NXP Semiconductors onnn ON Semiconductor Corp. opencores OpenCores.org +option Option NV ortustech Ortus Technology Co., Ltd. ovti OmniVision Technologies panasonic Panasonic Corporation -- cgit v0.10.2 From 726f783e803cc254b1a8a9a1dc3e5808fee02760 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 22 Jun 2015 23:36:03 +0800 Subject: ASoC: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/gtm601.c:86:4-9: 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: Marek Belisko Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 1b77ff2..393001c 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -83,7 +83,6 @@ MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); static struct platform_driver gtm601_codec_driver = { .driver = { .name = "gtm601", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(gtm601_codec_of_match), }, -- cgit v0.10.2 From beb5f8659ccd89a70b0a3ff28e32dbd8065df818 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 22 Jun 2015 23:48:25 +0800 Subject: ASoC: gtm601_dai can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 393001c..7004eba 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -33,7 +33,7 @@ static const struct snd_soc_dapm_route gtm601_dapm_routes[] = { { "Capture", NULL, "AIN" }, }; -struct snd_soc_dai_driver gtm601_dai = { +static struct snd_soc_dai_driver gtm601_dai = { .name = "gtm601", .playback = { .stream_name = "Playback", -- cgit v0.10.2 From d49796317d4968b29ccdee7b9586385ae20b60a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 24 Jun 2015 10:55:24 +0800 Subject: ASoC: gtm601: Fix modalias The MODULE_ALIAS needs to match the driver name to make module auto-loading work. Also move MODULE_ALIAS close to other MODULE_* macro. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 7004eba..12d15e5 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -70,8 +70,6 @@ static int gtm601_platform_remove(struct platform_device *pdev) return 0; } -MODULE_ALIAS("platform:gtm601_codec_audio"); - #if defined(CONFIG_OF) static const struct of_device_id gtm601_codec_of_match[] = { { .compatible = "option,gtm601", }, @@ -95,3 +93,4 @@ module_platform_driver(gtm601_codec_driver); MODULE_DESCRIPTION("ASoC gtm601 driver"); MODULE_AUTHOR("Marek Belisko "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gtm601"); -- cgit v0.10.2 From e608aaefd8f3b868866a2438dbad8e01cb0ce993 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:56 +0300 Subject: ASoC: rt286: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e26..2f39843 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1157,7 +1157,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, } if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt286\n", val); + "Device with ID register %#x is not rt286\n", val); return -ENODEV; } -- cgit v0.10.2 From 818454d1abcc127eef7e7d1cb169c69f53f7cd6d Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:57 +0300 Subject: ASoC: rt5640: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..0cbdac6 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2207,7 +2207,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5640/39\n", val); + "Device with ID register %#x is not rt5640/39\n", val); return -ENODEV; } -- cgit v0.10.2 From 8f68e80f5f434980ab9bae713bab6a3ff1ac07df Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:58 +0300 Subject: ASoC: rt5645: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..a5bc96a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3296,7 +3296,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, break; default: dev_err(&i2c->dev, - "Device with ID register %x is not rt5645 or rt5650\n", + "Device with ID register %#x is not rt5645 or rt5650\n", val); return -ENODEV; } -- cgit v0.10.2 From 469444fb134259384f3396833f6f1edde8bae203 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:59 +0300 Subject: ASoC: rt5651: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..96bbb7d 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1769,7 +1769,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5651\n", ret); + "Device with ID register %#x is not rt5651\n", ret); return -ENODEV; } -- cgit v0.10.2 From 387ad57fe187b10fb4dec521e8d0ba5cefae7b35 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:59:00 +0300 Subject: ASoC: rt5670: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..a791d7e 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2863,7 +2863,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_read(rt5670->regmap, RT5670_VENDOR_ID2, &val); if (val != RT5670_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5670/72\n", val); + "Device with ID register %#x is not rt5670/72\n", val); return -ENODEV; } -- cgit v0.10.2 From aa0bcc5c44437457307c8c22e57a67bb57424041 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:59:01 +0300 Subject: ASoC: rt5677: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..9048ba7 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5209,7 +5209,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); if (val != RT5677_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5677\n", val); + "Device with ID register %#x is not rt5677\n", val); return -ENODEV; } -- cgit v0.10.2 From 93d5fc8bd143d94105279796451dcfd3d657453a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:12 +0800 Subject: ASoC: wm0010: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 6560a66..e1da49f 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -1003,7 +1003,6 @@ static int wm0010_spi_remove(struct spi_device *spi) static struct spi_driver wm0010_spi_driver = { .driver = { .name = "wm0010", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = wm0010_spi_probe, -- cgit v0.10.2 From 0bc7d10c4abb7cec52d4d88f761476ed04225c83 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 11:41:19 +0800 Subject: ASoC: rt5645: Constify dmi_system_id table dmi_check_system() takes "const struct dmi_system_id *", so make the dmi_system_id table const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a5bc96a..a07966b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3221,7 +3221,7 @@ static int strago_quirk_cb(const struct dmi_system_id *id) return 1; } -static struct dmi_system_id dmi_platform_intel_braswell[] = { +static const struct dmi_system_id dmi_platform_intel_braswell[] = { { .ident = "Intel Strago", .callback = strago_quirk_cb, -- cgit v0.10.2 From e22579713ae1384a3dff545369cebe42b01370fa Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 5 Jun 2015 10:19:06 +0200 Subject: ASoC: simple card: set cpu-dai sysclk with mclk-fs Allows to request a specific mclk frequency per cpu_dai. To support some codecs with mclk provided by the cpu_dai, the mclk rate must be set depending on frame rate. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d555493..3ff76d4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -76,6 +76,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = &priv->dai_props[rtd - rtd->card->rtd]; @@ -91,8 +92,16 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, mclk = params_rate(params) * mclk_fs; ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) + goto err; + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) + goto err; } +err: return ret; } -- cgit v0.10.2 From 6702dfcc571d962df499f7466f54e07d044e6cd1 Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Fri, 5 Jun 2015 11:55:27 -0700 Subject: ASoC: wm8731: initialize the hardware when loading the codec driver This patch moves the requesting supplies, hardware reset and initialization from wm8731_probe to wm8731_i2c_probe and wm8731_spi_probe. So that the codec hardware is initialized when loading the codec driver, and not when loading the machine driver. This avoids unnecesary hardware resets and re-initializations when re-loading the machine driver. Signed-off-by: Sergey Kiselev Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 915ea11..f22935a 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -84,7 +84,7 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg) return reg <= WM8731_RESET; } -#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) +#define wm8731_reset(m) regmap_write(m, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; @@ -571,69 +571,63 @@ static struct snd_soc_dai_driver wm8731_dai = { .symmetric_rates = 1, }; -static int wm8731_probe(struct snd_soc_codec *codec) +static int wm8731_request_supplies(struct device *dev, + struct wm8731_priv *wm8731) { - struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); int ret = 0, i; for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) wm8731->supplies[i].supply = wm8731_supply_names[i]; - ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies), wm8731->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + dev_err(dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret; } - ret = wm8731_reset(codec); + return 0; +} + +static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731) +{ + int ret = 0; + + ret = wm8731_reset(wm8731->regmap); if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + dev_err(dev, "Failed to issue reset: %d\n", ret); goto err_regulator_enable; } - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Clear POWEROFF, keep everything else disabled */ + regmap_write(wm8731->regmap, WM8731_PWR, 0x7f); /* Latch the update bits */ - snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); - snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0); /* Disable bypass path by default */ - snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0); + regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0); - /* Regulators will have been enabled by bias management */ - regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - - return 0; + regcache_mark_dirty(wm8731->regmap); err_regulator_enable: + /* Regulators will be enabled by bias management */ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return ret; } -/* power down chip */ -static int wm8731_remove(struct snd_soc_codec *codec) -{ - struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - - regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { - .probe = wm8731_probe, - .remove = wm8731_remove, .set_bias_level = wm8731_set_bias_level, .suspend_bias_off = true, @@ -690,6 +684,12 @@ static int wm8731_spi_probe(struct spi_device *spi) mutex_init(&wm8731->lock); + spi_set_drvdata(spi, wm8731); + + ret = wm8731_request_supplies(&spi->dev, wm8731); + if (ret != 0) + return ret; + wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); @@ -698,7 +698,9 @@ static int wm8731_spi_probe(struct spi_device *spi) return ret; } - spi_set_drvdata(spi, wm8731); + ret = wm8731_hw_init(&spi->dev, wm8731); + if (ret != 0) + return ret; ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); @@ -754,6 +756,12 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, mutex_init(&wm8731->lock); + i2c_set_clientdata(i2c, wm8731); + + ret = wm8731_request_supplies(&i2c->dev, wm8731); + if (ret != 0) + return ret; + wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); @@ -762,7 +770,9 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, return ret; } - i2c_set_clientdata(i2c, wm8731); + ret = wm8731_hw_init(&i2c->dev, wm8731); + if (ret != 0) + return ret; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); -- cgit v0.10.2 From 83c09290adfb025d9a109d9c3c2956c81bcb241b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 29 Jun 2015 14:20:50 +0800 Subject: ASoC: rt5645: move RT5645 muxes to rt5645_specific_dapm_widgets This is a similar patch to "move RT5650 muxes to rt5650_specific_ dapm_widgets" patch. The purpose is to silence the "has no paths" warnings. Signed-off-by: Bard Liao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a07966b..1d821da 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1697,15 +1697,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), /* IF1 2 Mux */ - SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc1_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc2_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc3_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc_in_mux), - SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0, &rt5645_if2_adc_in_mux), @@ -1716,14 +1707,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac0_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac1_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac2_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac3_tdm_sel_mux), SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -1856,6 +1839,25 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("SPOR"), }; +static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = { + SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac0_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac1_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac2_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac3_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc1_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc2_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc3_in_mux), +}; + static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5650_a_dac1_l_mux), @@ -3049,6 +3051,9 @@ static int rt5645_probe(struct snd_soc_codec *codec) switch (rt5645->codec_type) { case CODEC_TYPE_RT5645: + snd_soc_dapm_new_controls(&codec->dapm, + rt5645_specific_dapm_widgets, + ARRAY_SIZE(rt5645_specific_dapm_widgets)); snd_soc_dapm_add_routes(&codec->dapm, rt5645_specific_dapm_routes, ARRAY_SIZE(rt5645_specific_dapm_routes)); -- cgit v0.10.2 From b650247da5a8c5d8991eeb9cf31e2e71d7be1b08 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Tue, 30 Jun 2015 17:43:02 -0400 Subject: ASoC: codecs: max98088: fix typo in constant This fixes a typo in the M98088_REG_02_JACK_STATUS constant. Signed-off-by: Nik Nyby Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h index be89a4f..efa39bf 100644 --- a/sound/soc/codecs/max98088.h +++ b/sound/soc/codecs/max98088.h @@ -16,7 +16,7 @@ */ #define M98088_REG_00_IRQ_STATUS 0x00 #define M98088_REG_01_MIC_STATUS 0x01 -#define M98088_REG_02_JACK_STAUS 0x02 +#define M98088_REG_02_JACK_STATUS 0x02 #define M98088_REG_03_BATTERY_VOLTAGE 0x03 #define M98088_REG_0F_IRQ_ENABLE 0x0F #define M98088_REG_10_SYS_CLK 0x10 -- cgit v0.10.2 From c05d9a8c7f55a901d9e8ec2a5f0730137bbfea4a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jun 2015 09:35:11 +0100 Subject: ASoC: arizona: Implement stability check for EQ coefficients Specifying unstable coefficients for the EQ can have a severe impact on the audio. This patchs adds a stability check on the coefficients written to the EQ, for this it is necessary to merge the mode control and the coefficients as some coefficients may only be unstable with a certain mode setting so it is ideal if these are always updated in sync. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05e..3996786 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2313,6 +2313,65 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = { }; EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls); +static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b) +{ + s16 a = be16_to_cpu(_a); + s16 b = be16_to_cpu(_b); + + if (!mode) { + return abs(a) >= 4096; + } else { + if (abs(b) >= 4096) + return true; + + return (abs((a << 16) / (4096 - b)) >= 4096 << 4); + } +} + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct soc_bytes *params = (void *)kcontrol->private_value; + unsigned int val; + __be16 *data; + int len; + int ret; + + len = params->num_regs * regmap_get_val_bytes(arizona->regmap); + + data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE); + + if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) || + arizona_eq_filter_unstable(true, data[4], data[5]) || + arizona_eq_filter_unstable(true, data[8], data[9]) || + arizona_eq_filter_unstable(true, data[12], data[13]) || + arizona_eq_filter_unstable(false, data[16], data[17])) { + dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n"); + ret = -EINVAL; + goto out; + } + + ret = regmap_read(arizona->regmap, params->base, &val); + if (ret != 0) + goto out; + + val &= ~ARIZONA_EQ1_B1_MODE; + data[0] |= cpu_to_be16(val); + + ret = regmap_raw_write(arizona->regmap, params->base, data, len); + +out: + kfree(data); + return ret; +} +EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 43deb04..ebe50cf 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -194,6 +194,13 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \ ARIZONA_MIXER_ROUTES(name " Preloader", name "R") +#define ARIZONA_EQ_CONTROL(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = arizona_eq_coeff_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) { .base = xbase, \ + .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) } + #define ARIZONA_RATE_ENUM_SIZE 4 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; @@ -229,6 +236,9 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index d097f09e5..556bd98 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -788,8 +788,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -801,8 +800,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -814,8 +812,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -827,8 +824,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 709fcc6..dfa4d4b 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -247,8 +247,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -260,8 +259,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -273,8 +271,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -286,8 +283,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 4134dc7..53e0a46 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -174,8 +174,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -187,8 +186,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -200,8 +198,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -213,8 +210,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, -- cgit v0.10.2 From 5f8e671a49e1d608fcf52c8944ea7818cd4c99a9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jun 2015 09:35:12 +0100 Subject: ASoC: arizona: Implement stability check for LHPF coefficients Specifying unstable coefficients for the low/high pass filters can have a severe impact on the audio. This patchs adds a stability check on the coefficients written to the low/high pass filter block to prevent this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 3996786..a88202d 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2372,6 +2372,23 @@ out: } EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); +int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + __be16 *data = (__be16 *)ucontrol->value.bytes.data; + s16 val = be16_to_cpu(*data); + + if (abs(val) >= 4096) { + dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n"); + return -EINVAL; + } + + return snd_soc_bytes_put(kcontrol, ucontrol); +} +EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index ebe50cf..13598b0 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,13 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ((unsigned long)&(struct soc_bytes) { .base = xbase, \ .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) } +#define ARIZONA_LHPF_CONTROL(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = arizona_lhpf_coeff_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) { .base = xbase, \ + .num_regs = 1 }) } + #define ARIZONA_RATE_ENUM_SIZE 4 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; @@ -238,6 +245,8 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 556bd98..6ddee99 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -847,10 +847,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index dfa4d4b..05aa5bc 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -310,10 +310,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 53e0a46..b4dba3a 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -238,10 +238,10 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), -- cgit v0.10.2 From 0d69e0dddf5fe86675c56bc0f0520ffb0cbf1fcd Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 23 Jun 2015 18:23:53 +0800 Subject: ASoC: fsl: Add dedicated DMA buffer size for each cpu dai As the ssi is not the only cpu dai, there are esai, spdif, sai. and imx_pcm_dma can be used by all of them. Especially ESAI need a larger DMA buffer size. So Add dedicated DMA buffer for each cpu dai. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Acked-by: Timur Tabi Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 5c75971..8c2ddc1 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -839,7 +839,7 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE); if (ret) dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5c73bea..a18fd92 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -791,7 +791,7 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; if (sai->sai_on_imx) - return imx_pcm_dma_init(pdev); + return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); else return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); } diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e93221..d1e9be7 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1255,7 +1255,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) return ret; } - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); if (ret) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c7647e0..e122dab 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1257,7 +1257,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, if (ret) goto error_pcm; } else { - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE); if (ret) goto error_pcm; } diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 0db94f49..1fc01ed 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -40,7 +40,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, + .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, @@ -52,13 +52,30 @@ static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = { .pcm_hardware = &imx_pcm_hardware, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .compat_filter_fn = filter, - .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE, + .prealloc_buffer_size = IMX_DEFAULT_DMABUF_SIZE, }; -int imx_pcm_dma_init(struct platform_device *pdev) +int imx_pcm_dma_init(struct platform_device *pdev, size_t size) { + struct snd_dmaengine_pcm_config *config; + struct snd_pcm_hardware *pcm_hardware; + + config = devm_kzalloc(&pdev->dev, + sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); + *config = imx_dmaengine_pcm_config; + if (size) + config->prealloc_buffer_size = size; + + pcm_hardware = devm_kzalloc(&pdev->dev, + sizeof(struct snd_pcm_hardware), GFP_KERNEL); + *pcm_hardware = imx_pcm_hardware; + if (size) + pcm_hardware->buffer_bytes_max = size; + + config->pcm_hardware = pcm_hardware; + return devm_snd_dmaengine_pcm_register(&pdev->dev, - &imx_dmaengine_pcm_config, + config, SND_DMAENGINE_PCM_FLAG_COMPAT); } EXPORT_SYMBOL_GPL(imx_pcm_dma_init); diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index c79cb27..133c4470a 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -20,6 +20,11 @@ */ #define IMX_SSI_DMABUF_SIZE (64 * 1024) +#define IMX_DEFAULT_DMABUF_SIZE (64 * 1024) +#define IMX_SAI_DMABUF_SIZE (64 * 1024) +#define IMX_SPDIF_DMABUF_SIZE (64 * 1024) +#define IMX_ESAI_DMABUF_SIZE (256 * 1024) + static inline void imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, int dma, enum sdma_peripheral_type peripheral_type) @@ -39,9 +44,9 @@ struct imx_pcm_fiq_params { }; #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA) -int imx_pcm_dma_init(struct platform_device *pdev); +int imx_pcm_dma_init(struct platform_device *pdev, size_t size); #else -static inline int imx_pcm_dma_init(struct platform_device *pdev) +static inline int imx_pcm_dma_init(struct platform_device *pdev, size_t size) { return -ENODEV; } diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 461ce27..48b2d24 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -603,7 +603,7 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params); - ssi->dma_init = imx_pcm_dma_init(pdev); + ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE); if (ssi->fiq_init && ssi->dma_init) { ret = ssi->fiq_init; -- cgit v0.10.2 From b1ade0f2afe283d59eb313e5717870fdb831fc4e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:00:13 -0300 Subject: ASoC: fsl: fsl_asrc: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index c068494..9f087d4 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -931,14 +931,29 @@ static int fsl_asrc_probe(struct platform_device *pdev) static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); - int i; + int i, ret; - clk_prepare_enable(asrc_priv->mem_clk); - clk_prepare_enable(asrc_priv->ipg_clk); - for (i = 0; i < ASRC_CLK_MAX_NUM; i++) - clk_prepare_enable(asrc_priv->asrck_clk[i]); + ret = clk_prepare_enable(asrc_priv->mem_clk); + if (ret) + return ret; + ret = clk_prepare_enable(asrc_priv->ipg_clk); + if (ret) + goto disable_mem_clk; + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { + ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); + if (ret) + goto disable_asrck_clk; + } return 0; + +disable_asrck_clk: + for (i--; i >= 0; i--) + clk_disable_unprepare(asrc_priv->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->ipg_clk); +disable_mem_clk: + clk_disable_unprepare(asrc_priv->mem_clk); + return ret; } static int fsl_asrc_runtime_suspend(struct device *dev) -- cgit v0.10.2 From fa3be9208dcb21ae4185f6122137fe7d5cf29d74 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:18:06 -0300 Subject: ASoC: fsl: fsl_spdif: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e93221..489fa86 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -482,13 +482,18 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) - clk_prepare_enable(spdif_priv->txclk[i]); + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { + ret = clk_prepare_enable(spdif_priv->txclk[i]); + if (ret) + goto disable_txclk; + } } else { scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; - clk_prepare_enable(spdif_priv->rxclk); + ret = clk_prepare_enable(spdif_priv->rxclk); + if (ret) + goto err; } regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); @@ -497,6 +502,9 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, return 0; +disable_txclk: + for (i--; i >= 0; i--) + clk_disable_unprepare(spdif_priv->txclk[i]); err: clk_disable_unprepare(spdif_priv->coreclk); -- cgit v0.10.2 From efd901ee4bc8312e3bbf5561fdab8e3765e26334 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:12:59 -0700 Subject: ASoC: rt5677: Switch to use descriptor-based gpiod API This patch makes the driver use the new descriptor-based gpiod API so that gpio assignment info can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9048ba7..2322430 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -15,13 +15,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -4764,10 +4762,10 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4781,10 +4779,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec) 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->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4795,12 +4793,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 1); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 1); - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 1); + if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); regcache_cache_only(rt5677->regmap, false); @@ -5037,24 +5034,6 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) rt5677->pdata.lout3_diff = of_property_read_bool(np, "realtek,lout3-differential"); - rt5677->pow_ldo2 = of_get_named_gpio(np, - "realtek,pow-ldo2-gpio", 0); - rt5677->reset_pin = of_get_named_gpio(np, - "realtek,reset-gpio", 0); - - /* - * POW_LDO2 is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5677->pow_ldo2) && - (rt5677->pow_ldo2 != -ENOENT)) - return rt5677->pow_ldo2; - if (!gpio_is_valid(rt5677->reset_pin) && - (rt5677->reset_pin != -ENOENT)) - return rt5677->reset_pin; - of_property_read_u8_array(np, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); @@ -5158,30 +5137,26 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, rt5677->reset_pin = -EINVAL; } - if (gpio_is_valid(rt5677->pow_ldo2)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, - GPIOF_OUT_INIT_HIGH, - "RT5677 POW_LDO2"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", - rt5677->pow_ldo2, ret); - return ret; - } + /* pow-ldo2 and reset are optional. The codec pins may be statically + * connected on the board without gpios. If the gpio device property + * isn't specified, devm_gpiod_get_optional returns NULL. + */ + rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev, + "realtek,pow-ldo2", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->pow_ldo2)) { + ret = PTR_ERR(rt5677->pow_ldo2); + dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); + rt5677->pow_ldo2 = 0; } - - if (gpio_is_valid(rt5677->reset_pin)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, - GPIOF_OUT_INIT_HIGH, - "RT5677 RESET"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", - rt5677->reset_pin, ret); - return ret; - } + rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, + "realtek,reset", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->reset_pin)) { + ret = PTR_ERR(rt5677->reset_pin); + dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); + rt5677->reset_pin = 0; } - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) { + if (rt5677->pow_ldo2 || rt5677->reset_pin) { /* Wait a while until I2C bus becomes available. The datasheet * does not specify the exact we should wait but startup * sequence mentiones at least a few milliseconds. diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 7eca38a..d46855a 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -14,6 +14,7 @@ #include #include +#include /* Info */ #define RT5677_RESET 0x00 @@ -1775,8 +1776,8 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; - int pow_ldo2; /* POW_LDO2 pin */ - int reset_pin; /* RESET pin */ + struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */ + struct gpio_desc *reset_pin; /* RESET pin */ enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; -- cgit v0.10.2 From 9bfde72157036f4eaa44f3e8982217ce1b3e14b6 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:13:00 -0700 Subject: ASoC: rt5677: Switch to use unified device property API This patch makes the driver use the unified device property API so that platform data can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 2322430..13b871f 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -5021,27 +5022,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); -static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) +static void rt5677_read_device_properties(struct rt5677_priv *rt5677, + struct device *dev) { - rt5677->pdata.in1_diff = of_property_read_bool(np, - "realtek,in1-differential"); - rt5677->pdata.in2_diff = of_property_read_bool(np, - "realtek,in2-differential"); - rt5677->pdata.lout1_diff = of_property_read_bool(np, - "realtek,lout1-differential"); - rt5677->pdata.lout2_diff = of_property_read_bool(np, - "realtek,lout2-differential"); - rt5677->pdata.lout3_diff = of_property_read_bool(np, - "realtek,lout3-differential"); - - of_property_read_u8_array(np, "realtek,gpio-config", - rt5677->pdata.gpio_config, RT5677_GPIO_NUM); - - of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); - of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); - of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); - - return 0; + rt5677->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5677->pdata.in2_diff = device_property_read_bool(dev, + "realtek,in2-differential"); + rt5677->pdata.lout1_diff = device_property_read_bool(dev, + "realtek,lout1-differential"); + rt5677->pdata.lout2_diff = device_property_read_bool(dev, + "realtek,lout2-differential"); + rt5677->pdata.lout3_diff = device_property_read_bool(dev, + "realtek,lout3-differential"); + + device_property_read_u8_array(dev, "realtek,gpio-config", + rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + + device_property_read_u32(dev, "realtek,jd1-gpio", + &rt5677->pdata.jd1_gpio); + device_property_read_u32(dev, "realtek,jd2-gpio", + &rt5677->pdata.jd2_gpio); + device_property_read_u32(dev, "realtek,jd3-gpio", + &rt5677->pdata.jd3_gpio); } static struct regmap_irq rt5677_irqs[] = { @@ -5124,18 +5127,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; - - if (i2c->dev.of_node) { - ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); - if (ret) { - dev_err(&i2c->dev, "Failed to parse device tree: %d\n", - ret); - return ret; - } - } else { - rt5677->pow_ldo2 = -EINVAL; - rt5677->reset_pin = -EINVAL; - } + else + rt5677_read_device_properties(rt5677, &i2c->dev); /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property -- cgit v0.10.2 From d375d0abcd625cd09cd90a252ad22a1085452e3c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 21:41:43 +0800 Subject: ASoC: cs42xx8: Move the code checking *regmap argument earlier Slightly improve the readability by moving the code checking *regmap argument earlier. Also move the assignment of of_id close to the place testing it. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index e1d4686..ab39514 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -435,16 +435,24 @@ EXPORT_SYMBOL_GPL(cs42xx8_of_match); int cs42xx8_probe(struct device *dev, struct regmap *regmap) { - const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev); + const struct of_device_id *of_id; struct cs42xx8_priv *cs42xx8; int ret, val, i; + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "failed to allocate regmap: %d\n", ret); + return ret; + } + cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL); if (cs42xx8 == NULL) return -ENOMEM; + cs42xx8->regmap = regmap; dev_set_drvdata(dev, cs42xx8); + of_id = of_match_device(cs42xx8_of_match, dev); if (of_id) cs42xx8->drvdata = of_id->data; @@ -482,13 +490,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) /* Make sure hardware reset done */ msleep(5); - cs42xx8->regmap = regmap; - if (IS_ERR(cs42xx8->regmap)) { - ret = PTR_ERR(cs42xx8->regmap); - dev_err(dev, "failed to allocate regmap: %d\n", ret); - goto err_enable; - } - /* * We haven't marked the chip revision as volatile due to * sharing a register with the right input volume; explicitly -- cgit v0.10.2 From 5e4cb7b60833b0124a9f71dbc5118144ca79c3c4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 21:44:13 +0800 Subject: ASoC: cs42xx8: Setup of_match_table Setup of_match_table and since cs42xx8_of_match is exported and used in cs42xx8-i2c.c, it cannot be static. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 657dce2..5a71c9e 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -20,7 +20,7 @@ static int cs42xx8_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - u32 ret = cs42xx8_probe(&i2c->dev, + int ret = cs42xx8_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); if (ret) return ret; @@ -51,6 +51,7 @@ static struct i2c_driver cs42xx8_i2c_driver = { .name = "cs42xx8", .owner = THIS_MODULE, .pm = &cs42xx8_pm, + .of_match_table = cs42xx8_of_match, }, .probe = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index ab39514..d562e1b 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -425,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = { }; EXPORT_SYMBOL_GPL(cs42888_data); -static const struct of_device_id cs42xx8_of_match[] = { +const struct of_device_id cs42xx8_of_match[] = { { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, { /* sentinel */ } diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h index b2c10e5..d36c61b 100644 --- a/sound/soc/codecs/cs42xx8.h +++ b/sound/soc/codecs/cs42xx8.h @@ -22,6 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm; extern const struct cs42xx8_driver_data cs42448_data; extern const struct cs42xx8_driver_data cs42888_data; extern const struct regmap_config cs42xx8_regmap_config; +extern const struct of_device_id cs42xx8_of_match[]; int cs42xx8_probe(struct device *dev, struct regmap *regmap); /* CS42888 register map */ -- cgit v0.10.2 From 93ec3a1ad5b86aef8ca90d2b149ded0f6bb689f5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 29 Jun 2015 11:15:23 +0800 Subject: ASoC: 88pm860x: Don't change pm860x->dir setting if pm860x_set_dai_sysclk fails 88pm860x does not support slave mode, so it returns -EINVAL for PM860X_CLK_DIR_IN. Current code changes pm860x->dir setting before return error, so it has impact on the logic of pm860x_pcm_set_dai_fmt. This patch adds comment for the reason to return -EINVAL for PM860X_CLK_DIR_IN, and avoid changing pm860x->dir setting if pm860x_set_dai_sysclk fails. Signed-off-by: Axel Lin Acked-by: Haojian Zhuang Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 38b3dad..4d91a6a 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1028,10 +1028,8 @@ static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (dir == PM860X_CLK_DIR_OUT) pm860x->dir = PM860X_CLK_DIR_OUT; - else { - pm860x->dir = PM860X_CLK_DIR_IN; + else /* Slave mode is not supported */ return -EINVAL; - } return 0; } -- cgit v0.10.2 From f8ea6cebcfa6499949392da71fc427567c9e5a0e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 1 Jul 2015 00:56:36 +0800 Subject: ASoC: ak4642: Fix up max_register setting The max_register setting for ak4642, ak4643 and ak4648 are wrong, fix it. According to the datasheet: the maximum valid register for ak4642 is 0x1f the maximum valid register for ak4643 is 0x24 the maximum valid register for ak4648 is 0x27 The default settings for ak4642 and ak4643 are the same for 0x0 ~ 0x1f registers, so it's fine to use the same reg_default table with differnt num_reg_defaults setting. Signed-off-by: Axel Lin Tested-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7c0f6552..fe963e1 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -64,12 +64,15 @@ #define FIL1_0 0x1c #define FIL1_1 0x1d #define FIL1_2 0x1e -#define FIL1_3 0x1f +#define FIL1_3 0x1f /* The maximum valid register for ak4642 */ #define PW_MGMT4 0x20 #define MD_CTL5 0x21 #define LO_MS 0x22 #define HP_MS 0x23 -#define SPK_MS 0x24 +#define SPK_MS 0x24 /* The maximum valid register for ak4643 */ +#define EQ_FBEQAB 0x25 +#define EQ_FBEQCD 0x26 +#define EQ_FBEQE 0x27 /* The maximum valid register for ak4648 */ /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ @@ -241,7 +244,7 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { /* * ak4642 register cache */ -static const struct reg_default ak4642_reg[] = { +static const struct reg_default ak4643_reg[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 }, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 }, { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 }, @@ -254,6 +257,14 @@ static const struct reg_default ak4642_reg[] = { { 36, 0x00 }, }; +/* The default settings for 0x0 ~ 0x1f registers are the same for ak4642 + and ak4643. So we reuse the ak4643 reg_default for ak4642. + The valid registers for ak4642 are 0x0 ~ 0x1f which is a subset of ak4643, + so define NUM_AK4642_REG_DEFAULTS for ak4642. +*/ +#define ak4642_reg ak4643_reg +#define NUM_AK4642_REG_DEFAULTS (FIL1_3 + 1) + static const struct reg_default ak4648_reg[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 }, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 }, @@ -535,15 +546,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { static const struct regmap_config ak4642_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = ARRAY_SIZE(ak4642_reg) + 1, + .max_register = FIL1_3, .reg_defaults = ak4642_reg, - .num_reg_defaults = ARRAY_SIZE(ak4642_reg), + .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, +}; + +static const struct regmap_config ak4643_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPK_MS, + .reg_defaults = ak4643_reg, + .num_reg_defaults = ARRAY_SIZE(ak4643_reg), }; static const struct regmap_config ak4648_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = ARRAY_SIZE(ak4648_reg) + 1, + .max_register = EQ_FBEQE, .reg_defaults = ak4648_reg, .num_reg_defaults = ARRAY_SIZE(ak4648_reg), }; @@ -553,7 +572,7 @@ static const struct ak4642_drvdata ak4642_drvdata = { }; static const struct ak4642_drvdata ak4643_drvdata = { - .regmap_config = &ak4642_regmap, + .regmap_config = &ak4643_regmap, }; static const struct ak4642_drvdata ak4648_drvdata = { -- cgit v0.10.2 From 6f4397949689d74c3bd0016c80d59a90c6e8afee Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 17:01:14 +0800 Subject: ASoC: lm49453: Remove fs_rate from struct lm49453_priv fs_rate is only used in lm49453_hw_params() so don't need to store it in private data. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0..5b4086d 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -188,7 +188,6 @@ static struct reg_default lm49453_reg_defs[] = { /* codec private data */ struct lm49453_priv { struct regmap *regmap; - int fs_rate; }; /* capture path controls */ @@ -1112,13 +1111,10 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec); u16 clk_div = 0; - lm49453->fs_rate = params_rate(params); - /* Setting DAC clock dividers based on substream sample rate. */ - switch (lm49453->fs_rate) { + switch (params_rate(params)) { case 8000: case 16000: case 32000: -- cgit v0.10.2 From 02a9547e9b3f10d73fde66f52fc8b2a375a300cd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Jul 2015 12:57:19 +0800 Subject: ASoC: gtm601: Constify soc_codec_dev_gtm601 Also clean up the code a bit by fixing indent. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 12d15e5..0b80052 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -51,7 +51,7 @@ static struct snd_soc_dai_driver gtm601_dai = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_gtm601 = { +static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = { .dapm_widgets = gtm601_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), .dapm_routes = gtm601_dapm_routes, @@ -80,10 +80,9 @@ MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); static struct platform_driver gtm601_codec_driver = { .driver = { - .name = "gtm601", - .of_match_table = of_match_ptr(gtm601_codec_of_match), + .name = "gtm601", + .of_match_table = of_match_ptr(gtm601_codec_of_match), }, - .probe = gtm601_platform_probe, .remove = gtm601_platform_remove, }; -- cgit v0.10.2 From c418a84a8c8f98b1a0f30cd68d0cdf40d77aed01 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 5 Jul 2015 17:48:29 +0800 Subject: ASoC: Constify reg_default tables Signed-off-by: Axel Lin Acked-by: Peter Rosin Acked-by: Charles Keepax Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 36d8425..88fd37c 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -113,7 +113,7 @@ #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) -static struct reg_default adav80x_reg_defaults[] = { +static const struct reg_default adav80x_reg_defaults[] = { { ADAV80X_PLAYBACK_CTRL, 0x01 }, { ADAV80X_AUX_IN_CTRL, 0x01 }, { ADAV80X_REC_CTRL, 0x02 }, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 607a63b..29a2645 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -35,7 +35,7 @@ /* * ALC5632 register cache */ -static struct reg_default alc5632_reg_defaults[] = { +static const struct reg_default alc5632_reg_defaults[] = { { 2, 0x8080 }, /* R2 - Speaker Output Volume */ { 4, 0x8080 }, /* R4 - Headphone Output Volume */ { 6, 0x8080 }, /* R6 - AUXOUT Volume */ diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5..a44ead6 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -680,7 +680,7 @@ struct da7210_priv { int master; }; -static struct reg_default da7210_reg_defaults[] = { +static const struct reg_default da7210_reg_defaults[] = { { 0x00, 0x00 }, { 0x01, 0x11 }, { 0x03, 0x00 }, @@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { #if IS_ENABLED(CONFIG_I2C) -static struct reg_default da7210_regmap_i2c_patch[] = { +static const struct reg_default da7210_regmap_i2c_patch[] = { /* System controller master disable */ { DA7210_STARTUP1, 0x00 }, @@ -1269,7 +1269,7 @@ static struct i2c_driver da7210_i2c_driver = { #if defined(CONFIG_SPI_MASTER) -static struct reg_default da7210_regmap_spi_patch[] = { +static const struct reg_default da7210_regmap_spi_patch[] = { /* Dummy read to give two pulses over nCS for SPI */ { DA7210_AUX2, 0x00 }, { DA7210_AUX2, 0x00 }, diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 238e48a..baa36f6 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -954,7 +954,7 @@ static const struct snd_soc_dapm_route da7213_audio_map[] = { {"LINE", NULL, "Lineout PGA"}, }; -static struct reg_default da7213_reg_defaults[] = { +static const struct reg_default da7213_reg_defaults[] = { { DA7213_DIG_ROUTING_DAI, 0x10 }, { DA7213_SR, 0x0A }, { DA7213_REFERENCES, 0x80 }, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2075236..b1cb465 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -43,7 +43,7 @@ struct da732x_priv { /* * da732x register cache - default settings */ -static struct reg_default da732x_reg_cache[] = { +static const struct reg_default da732x_reg_cache[] = { { DA732X_REG_REF1 , 0x02 }, { DA732X_REG_BIAS_EN , 0x80 }, { DA732X_REG_BIAS1 , 0x00 }, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446..925d822 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -948,7 +948,7 @@ struct da9055_priv { struct da9055_platform_data *pdata; }; -static struct reg_default da9055_reg_defaults[] = { +static const struct reg_default da9055_reg_defaults[] = { { 0x21, 0x10 }, { 0x22, 0x0A }, { 0x23, 0x00 }, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd9028..ac7dfe7 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -33,7 +33,7 @@ /* Register default values for ISABELLE driver. */ -static struct reg_default isabelle_reg_defs[] = { +static const struct reg_default isabelle_reg_defs[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0..bf77462 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -30,7 +30,7 @@ #include #include "lm49453.h" -static struct reg_default lm49453_reg_defs[] = { +static const struct reg_default lm49453_reg_defs[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index e1c196a..e3ccea2 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -35,7 +35,7 @@ struct max9768 { u32 flags; }; -static struct reg_default max9768_default_regs[] = { +static const struct reg_default max9768_default_regs[] = { { 0, 0 }, { 3, MAX9768_CTRL_FILTERLESS}, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 29549cd..8df99fb 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -22,7 +22,7 @@ static struct regmap *regmap; -static struct reg_default max9877_regs[] = { +static const struct reg_default max9877_regs[] = { { 0, 0x40 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index b74118e..1e8ede8 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -199,7 +199,7 @@ static const struct clk_coeff coeff_div[] = { {12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4}, }; -static struct reg_default ml26124_reg[] = { +static const struct reg_default ml26124_reg[] = { /* CLOCK control Register */ {0x00, 0x00 }, /* Sampling Rate */ {0x02, 0x00}, /* PLL NL */ diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e26..7069fe8 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -38,7 +38,7 @@ #define RT288_VENDOR_ID 0x10ec0288 struct rt286_priv { - struct reg_default *index_cache; + const struct reg_default *index_cache; int index_cache_size; struct regmap *regmap; struct snd_soc_codec *codec; @@ -50,7 +50,7 @@ struct rt286_priv { int clk_id; }; -static struct reg_default rt286_index_def[] = { +static const struct reg_default rt286_index_def[] = { { 0x01, 0xaaaa }, { 0x02, 0x8aaa }, { 0x03, 0x0002 }, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..3ee0574 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = { .window_len = 0x1, }, }; -static struct reg_default init_list[] = { +static const struct reg_default init_list[] = { {RT5651_PR_BASE + 0x3d, 0x3e00}, }; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d..71cfae0 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -38,7 +38,7 @@ #include "tas2552.h" -static struct reg_default tas2552_reg_defs[] = { +static const struct reg_default tas2552_reg_defs[] = { {TAS2552_CFG_1, 0x22}, {TAS2552_CFG_3, 0x80}, {TAS2552_DOUT, 0x00}, diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index aab0af6..bf7596b 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -160,7 +160,7 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static struct reg_default tfa9879_regs[] = { +static const struct reg_default tfa9879_regs[] = { { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */ { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */ { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */ diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c830832..01aeb75 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -166,7 +166,7 @@ static const struct wm_adsp_region wm2200_dsp2_regions[] = { { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, }; -static struct reg_default wm2200_reg_defaults[] = { +static const struct reg_default wm2200_reg_defaults[] = { { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ { 0x0103, 0x0011 }, /* R259 - Clocking 4 */ diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd..8edc6d2 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -113,7 +113,7 @@ WM8962_REGULATOR_EVENT(5) WM8962_REGULATOR_EVENT(6) WM8962_REGULATOR_EVENT(7) -static struct reg_default wm8962_reg[] = { +static const struct reg_default wm8962_reg[] = { { 0, 0x009F }, /* R0 - Left Input volume */ { 1, 0x049F }, /* R1 - Right Input volume */ { 2, 0x0000 }, /* R2 - HPOUTL volume */ diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db86..f2d5211 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -41,7 +41,7 @@ static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { "SPKVDD", }; -static struct reg_default wm8993_reg_defaults[] = { +static const struct reg_default wm8993_reg_defaults[] = { { 1, 0x0000 }, /* R1 - Power Management (1) */ { 2, 0x6000 }, /* R2 - Power Management (2) */ { 3, 0x0000 }, /* R3 - Power Management (3) */ @@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) #endif /* Tune DC servo configuration */ -static struct reg_default wm8993_regmap_patch[] = { +static const struct reg_default wm8993_regmap_patch[] = { { 0x44, 3 }, { 0x56, 3 }, { 0x44, 0 }, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f..66f32be 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -117,7 +117,7 @@ WM8996_REGULATOR_EVENT(0) WM8996_REGULATOR_EVENT(1) WM8996_REGULATOR_EVENT(2) -static struct reg_default wm8996_reg[] = { +static const struct reg_default wm8996_reg[] = { { WM8996_POWER_MANAGEMENT_1, 0x0 }, { WM8996_POWER_MANAGEMENT_2, 0x0 }, { WM8996_POWER_MANAGEMENT_3, 0x0 }, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 8a8b1c0..ec91ce8 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -30,7 +30,7 @@ #include #include "wm9081.h" -static struct reg_default wm9081_reg[] = { +static const struct reg_default wm9081_reg[] = { { 2, 0x00B9 }, /* R2 - Analogue Lineout */ { 3, 0x00B9 }, /* R3 - Analogue Speaker PGA */ { 4, 0x0001 }, /* R4 - VMID Control */ -- cgit v0.10.2 From 02c4b9c28b973d999073c810a78375e38346d7a3 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 18 Jun 2015 15:16:07 -0700 Subject: ASoC: qcom: move board Kconfig deps to parent config Rather than have each board define the same set of dependencies; move the common dependencies to the SND_SOC_QCOM parent config. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 807fedf..d6ccda7 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -1,5 +1,6 @@ config SND_SOC_QCOM tristate "ASoC support for QCOM platforms" + depends on ARCH_QCOM || COMPILE_TEST help Say Y or M if you want to add support to use audio devices in Qualcomm Technologies SOC-based platforms. @@ -26,7 +27,7 @@ config SND_SOC_LPASS_APQ8016 config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) + depends on SND_SOC_QCOM select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help @@ -35,7 +36,7 @@ config SND_SOC_STORM config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) + depends on SND_SOC_QCOM select SND_SOC_LPASS_APQ8016 help Support for Qualcomm Technologies LPASS audio block in -- cgit v0.10.2 From 7f005256f70a8c1c60b2f8a7449137da0c5e5bd9 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 18 Jun 2015 15:16:08 -0700 Subject: ASoC: qcom: remove Kconfig deps from variant configs Remove the SND_SOC_QCOM dependency from the variant configs. The board configs, which select the variants, already have this dependency. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index d6ccda7..3cc252e 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -15,13 +15,11 @@ config SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_IPQ806X tristate - depends on SND_SOC_QCOM select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_APQ8016 tristate - depends on SND_SOC_QCOM select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM -- cgit v0.10.2 From e2ada8187bc8b46c30a623e7d6b5a72c209f70cd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:06 +0200 Subject: ASoC: rt5645: Replace direct snd_soc_codec dapm field access The dapm field of the snd_soc_codec struct is eventually going to be removed, in preparation for this replace all manual access to codec->dapm.bias_level with snd_soc_codec_get_bias_level() and replace all other manual access to codec->dapm with snd_soc_codec_get_dapm(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..571e4b5 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2642,7 +2642,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_PREPARE: - if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { + if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { snd_soc_update_bits(codec, RT5645_PWR_ANLG1, RT5645_PWR_VREF1 | RT5645_PWR_MB | RT5645_PWR_BG | RT5645_PWR_VREF2, @@ -2760,20 +2760,17 @@ static int rt5650_calibration(struct rt5645_priv *rt5645) static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { - snd_soc_dapm_mutex_lock(&codec->dapm); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "ADC L power"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "ADC R power"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "LDO2"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync_unlocked(&codec->dapm); - snd_soc_dapm_mutex_unlock(&codec->dapm); + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC L power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC R power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Det Power"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); @@ -2786,23 +2783,20 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); - snd_soc_dapm_mutex_lock(&codec->dapm); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "ADC L power"); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "ADC R power"); + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "ADC L power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "ADC R power"); if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "LDO2"); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync_unlocked(&codec->dapm); - snd_soc_dapm_mutex_unlock(&codec->dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Det Power"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); } } static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); unsigned int val; @@ -2811,10 +2805,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (codec->component.card->instantiated) { /* for jack type detect */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); - snd_soc_dapm_force_enable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else { /* Power up necessary bits for JD if dapm is not ready yet */ @@ -2847,9 +2840,8 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } } else { if (codec->component.card->instantiated) { - snd_soc_dapm_disable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); @@ -2863,11 +2855,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) else { if (codec->component.card->instantiated) { if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(&codec->dapm, - "LDO2"); - snd_soc_dapm_disable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else { if (rt5645->pdata.jd_mode == 0) regmap_update_bits(rt5645->regmap, @@ -3043,21 +3033,22 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) static int rt5645_probe(struct snd_soc_codec *codec) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); rt5645->codec = codec; switch (rt5645->codec_type) { case CODEC_TYPE_RT5645: - snd_soc_dapm_add_routes(&codec->dapm, + snd_soc_dapm_add_routes(dapm, rt5645_specific_dapm_routes, ARRAY_SIZE(rt5645_specific_dapm_routes)); break; case CODEC_TYPE_RT5650: - snd_soc_dapm_new_controls(&codec->dapm, + snd_soc_dapm_new_controls(dapm, rt5650_specific_dapm_widgets, ARRAY_SIZE(rt5650_specific_dapm_widgets)); - snd_soc_dapm_add_routes(&codec->dapm, + snd_soc_dapm_add_routes(dapm, rt5650_specific_dapm_routes, ARRAY_SIZE(rt5650_specific_dapm_routes)); break; @@ -3067,9 +3058,9 @@ static int rt5645_probe(struct snd_soc_codec *codec) /* for JD function */ if (rt5645->pdata.jd_mode) { - snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "JD Power"); + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_sync(dapm); } return 0; -- cgit v0.10.2 From 8f218fa93d20a7b4ef8a088e5eed2d84b8ef4ab5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:07 +0200 Subject: ASoC: tas571x: Replace direct snd_soc_codec dapm field access The dapm field of the snd_soc_codec struct is eventually going to be removed, in preparation for this replace all manual access to codec->dapm.bias_level with snd_soc_codec_get_bias_level(). Signed-off-by: Lars-Peter Clausen Acked-by: Kevin Cernekee Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 85bcc37..39307ad 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -179,7 +179,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { if (!IS_ERR(priv->mclk)) { ret = clk_prepare_enable(priv->mclk); if (ret) { -- cgit v0.10.2 From 987731bb7c80b170228e6e1acf2e7b91efb51100 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:08 +0200 Subject: ASoC: omap3pandora: Use card DAPM context to access widgets The dapm field of the snd_soc_codec struct will eventually be removed (replaced with the DAPM context from the component embedded inside the CODEC). Replace its usage with the card's DAPM context. The idea is that DAPM is hierarchical and with the card at the root it is possible to access widgets from other contexts through the card context. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 076bec6..732e749 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -154,8 +154,7 @@ static const struct snd_soc_dapm_route omap3pandora_map[] = { static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; /* All TWL4030 output pins are floating */ snd_soc_dapm_nc_pin(dapm, "EARPIECE"); @@ -174,8 +173,7 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; /* Not comnnected */ snd_soc_dapm_nc_pin(dapm, "HSMIC"); -- cgit v0.10.2 From c68c2be5f6ae4a27d548921bf8b32413c5eab8ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:09 +0200 Subject: ASoC: cht_bsw_max98090_ti: Use card DAPM context to access widgets The dapm field of the snd_soc_codec struct will eventually be removed (replaced with the DAPM context from the component embedded inside the CODEC). Replace its usage with the card's DAPM context. The idea is that DAPM is hierarchical and with the card at the root it is possible to access widgets from other contexts through the card context. While we are at it also remove some extra newlines. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d604ee8..afcd6ba 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -104,21 +104,17 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, static int cht_ti_jack_event(struct notifier_block *nb, unsigned long event, void *data) { - struct snd_soc_jack *jack = (struct snd_soc_jack *)data; - struct snd_soc_dai *codec_dai = jack->card->rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dapm_context *dapm = &jack->card->dapm; if (event & SND_JACK_MICROPHONE) { - - snd_soc_dapm_force_enable_pin(&codec->dapm, "SHDN"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "SHDN"); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); + snd_soc_dapm_sync(dapm); } else { - - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); - snd_soc_dapm_disable_pin(&codec->dapm, "SHDN"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin(dapm, "SHDN"); + snd_soc_dapm_sync(dapm); } return 0; -- cgit v0.10.2 From b3c25fb7caa30afa5d5cc6b414a5b4d66bed77a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:10 +0200 Subject: ASoC: dapm_widget_show_codec: Use component instead of CODEC There is nothing snd_soc_codec specific in this function, just use snd_soc_component instead. With this also the last reference of snd_soc_codec form soc-dapm.c. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c9..a6c0ed1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2220,14 +2220,16 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); -static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) +static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, + char *buf) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); struct snd_soc_dapm_widget *w; int count = 0; char *state = "not set"; - list_for_each_entry(w, &codec->component.card->widgets, list) { - if (w->dapm != &codec->dapm) + list_for_each_entry(w, &cmpnt->card->widgets, list) { + if (w->dapm != dapm) continue; /* only display widgets that burnm power */ @@ -2255,7 +2257,7 @@ static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) } } - switch (codec->dapm.bias_level) { + switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_ON: state = "On"; break; @@ -2282,8 +2284,9 @@ static ssize_t dapm_widget_show(struct device *dev, int i, count = 0; for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec = rtd->codec_dais[i]->codec; - count += dapm_widget_show_codec(codec, buf + count); + struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; + + count += dapm_widget_show_component(cmpnt, buf + count); } return count; -- cgit v0.10.2 From 4890140f3888b4a4baef90d84e278858afe45248 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:11 +0200 Subject: ASoC: Remove snd_soc_codec dapm field There are no more direct users of the snd_soc_codec DAPM field left. So we can finally remove it and switch over to directly using the component DAPM context and remove the dapm_ptr indirection. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf..3ccd82a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -792,7 +792,6 @@ struct snd_soc_component { /* Don't use these, use snd_soc_component_get_dapm() */ struct snd_soc_dapm_context dapm; - struct snd_soc_dapm_context *dapm_ptr; const struct snd_kcontrol_new *controls; unsigned int num_controls; @@ -832,9 +831,6 @@ struct snd_soc_codec { /* component */ struct snd_soc_component component; - /* Don't access this directly, use snd_soc_codec_get_dapm() */ - struct snd_soc_dapm_context dapm; - #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_reg; #endif @@ -1277,7 +1273,7 @@ static inline struct snd_soc_component *snd_soc_dapm_to_component( static inline struct snd_soc_codec *snd_soc_dapm_to_codec( struct snd_soc_dapm_context *dapm) { - return container_of(dapm, struct snd_soc_codec, dapm); + return snd_soc_component_to_codec(snd_soc_dapm_to_component(dapm)); } /** @@ -1302,7 +1298,7 @@ static inline struct snd_soc_platform *snd_soc_dapm_to_platform( static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( struct snd_soc_component *component) { - return component->dapm_ptr; + return &component->dapm; } /** @@ -1314,7 +1310,7 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm( struct snd_soc_codec *codec) { - return &codec->dapm; + return snd_soc_component_get_dapm(&codec->component); } /** diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0..3747111 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -654,10 +654,12 @@ int snd_soc_suspend(struct device *dev) /* suspend all CODECs */ list_for_each_entry(codec, &card->codec_dev_list, card_list) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ if (!codec->suspended) { - switch (codec->dapm.bias_level) { + switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* * If the CODEC is capable of idle @@ -665,7 +667,7 @@ int snd_soc_suspend(struct device *dev) * means it's doing something, * otherwise fall through. */ - if (codec->dapm.idle_bias_off) { + if (dapm->idle_bias_off) { dev_dbg(codec->dev, "ASoC: idle_bias_off CODEC on over suspend\n"); break; @@ -2651,10 +2653,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->probe = component->driver->probe; component->remove = component->driver->remove; - if (!component->dapm_ptr) - component->dapm_ptr = &component->dapm; - - dapm = component->dapm_ptr; + dapm = &component->dapm; dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; @@ -3036,6 +3035,7 @@ int snd_soc_register_codec(struct device *dev, struct snd_soc_dai_driver *dai_drv, int num_dai) { + struct snd_soc_dapm_context *dapm; struct snd_soc_codec *codec; struct snd_soc_dai *dai; int ret, i; @@ -3046,7 +3046,6 @@ int snd_soc_register_codec(struct device *dev, if (codec == NULL) return -ENOMEM; - codec->component.dapm_ptr = &codec->dapm; codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, @@ -3076,12 +3075,14 @@ int snd_soc_register_codec(struct device *dev, if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; - codec->dapm.idle_bias_off = codec_drv->idle_bias_off; - codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; + + dapm = snd_soc_codec_get_dapm(codec); + dapm->idle_bias_off = codec_drv->idle_bias_off; + dapm->suspend_bias_off = codec_drv->suspend_bias_off; if (codec_drv->seq_notifier) - codec->dapm.seq_notifier = codec_drv->seq_notifier; + dapm->seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) - codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; + dapm->set_bias_level = snd_soc_codec_set_bias_level; codec->dev = dev; codec->driver = codec_drv; codec->component.val_bytes = codec_drv->reg_word_size; -- cgit v0.10.2 From c5b8540dca22526517f4d96857678466613467d1 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Mon, 6 Jul 2015 10:02:10 +0800 Subject: ASoC: dpcm: Add checks of playback/capture before dpcm_get_be In dpcm_get_be(), it looks for a BE rtd that has the DAI widget according to current stream type. Only playback_widgets are searched in the case of playback stream and vice versa. However, the DAI widget itself can be playback or capture. If the DAI widget is capture, but current stream type is playback, dpcm_get_be() will always fail to find a rtd, print error messages, and continue to the next DAI widget in list. We can just skip this DAI widget to further suppress error messages. This happens in a special case when 2 codecs are inter-connected, and the 1st codec's "capture" widget is used to send data to the 2nd codec during "playback": mtk-rt5650-rt5676 sound: ASoC: can't get playback BE for Sub AIF2 Capture rt5650_rt5676 Playback: ASoC: no BE found for Sub AIF2 Capture Add checks to continue to next DAI widget if current DAI widget's direction does not match the stream type. Signed-off-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 256b9c9..a6d3313 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1306,7 +1306,12 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, switch (list->widgets[i]->id) { case snd_soc_dapm_dai_in: + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; + break; case snd_soc_dapm_dai_out: + if (stream != SNDRV_PCM_STREAM_CAPTURE) + continue; break; default: continue; -- cgit v0.10.2 From 9acc7f08716b98730e1ead7e785fb0f3ad3a2d07 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:50 -0300 Subject: ASoC: max98090: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f05..1697340 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1801,10 +1801,13 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, if (IS_ERR(max98090->mclk)) break; - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { clk_disable_unprepare(max98090->mclk); - else - clk_prepare_enable(max98090->mclk); + } else { + ret = clk_prepare_enable(max98090->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_STANDBY: -- cgit v0.10.2 From 6e78108bda78adbb2d4ef55ec60a388aba975797 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 3 Jul 2015 16:30:30 +0800 Subject: ASoC: core: Don't probe the component which is dummy Dummy dai can be used by multiple sound card. But it only belong to one card's dapm list. If another card use it, there will be dapm_assert_locked warning. [ 20.015782] WARNING: CPU: 1 PID: 661 at sound/soc/soc-dapm.c:124 dapm_assert_locked.isra.36+0x4c/0x58() [ 20.025249] Modules linked in: [ 20.028349] CPU: 1 PID: 661 Comm: aplay Not tainted 4.1.0-rc6-next-20150605-00004-gaee05d8-dirty #92 [ 20.037528] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [ 20.044110] Backtrace: [ 20.046614] [<80012e00>] (dump_backtrace) from [<80012fa0>] (show_stack+0x18/0x1c) [ 20.054229] r6:809e8060 r5:00000000 r4:00000000 r3:00000000 [ 20.060002] [<80012f88>] (show_stack) from [<807a0f74>] (dump_stack+0x80/0x9c) [ 20.067293] [<807a0ef4>] (dump_stack) from [<8002b144>] (warn_slowpath_common+0x7c/0xb4) [ 20.075427] r5:0000007c r4:00000000 [ 20.079065] [<8002b0c8>] (warn_slowpath_common) from [<8002b1a0>] (warn_slowpath_null+0x24/0x2c) [ 20.087898] r8:00000001 r7:88007c28 r6:ed94a680 r5:809e83e4 r4:ed83d6c0 [ 20.094747] [<8002b17c>] (warn_slowpath_null) from [<8058403c>] (dapm_assert_locked.isra.36+0x4c/0x58) [ 20.104101] [<80583ff0>] (dapm_assert_locked.isra.36) from [<805842ec>] (dapm_mark_dirty+0x64/0xa4) [ 20.113165] [<80584288>] (dapm_mark_dirty) from [<805853a8>] (soc_dapm_dai_stream_event.isra.42+0x30/0xc8) [ 20.122863] r8:ed9b5dbc r7:00000000 r6:00000001 r5:00000001 r4:ed83d6c0 [ 20.129706] [<80585378>] (soc_dapm_dai_stream_event.isra.42) from [<80587e28>] (snd_soc_dapm_stream_event+0x78/0xa0) [ 20.140264] r5:ee2ee62c r4:00000001 [ 20.143918] [<80587db0>] (snd_soc_dapm_stream_event) from [<8058957c>] (soc_pcm_prepare+0x138/0x21c) [ 20.153058] r8:ed8d9480 r7:00000000 r6:ed9b0e00 r5:00000001 r4:ee2ee62c r3:00000000 ... This patch is to not probe the dummy component in soc_probe_component. Then there is no widget created for dummy DAI, and also don't need to check the dummy dai in dapm_connect_dai_link_widgets(). Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0..6ce6217 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1102,7 +1102,7 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; - if (component->probed) + if (!strcmp(component->name, "snd-soc-dummy") || component->probed) return 0; component->card = card; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c9..37ab6b9 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3820,11 +3820,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - /* there is no point in connecting BE DAI links with dummies */ - if (snd_soc_dai_is_dummy(codec_dai) || - snd_soc_dai_is_dummy(cpu_dai)) - continue; - /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { source = cpu_dai->playback_widget; -- cgit v0.10.2 From c4a99a4b4f6ef56e9c8182920680b84a7129ca80 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Tue, 7 Jul 2015 14:21:47 -0700 Subject: ASoC: ts3a227e: do not report jack status when there is i2c read err After suspend -> resume the ts3a227e_interrupt sometimes comes before i2c controller resume is called .regmap_read will return incorrect status and report a wrong jack status.This patch will disable irq on suspend and enable irq again on the resume to make sure interrupt is coming after TI resumes. Also We should return if there is read err,the interrupt will come again since it is level triggered and we are not yet clear the interrupt. In addtion,cht_bsw_max98090_ti machine driver registered additional notifier base on jack event which will program the audio codec.there will be codec timeout err if such event occurs prior to i2c controller is resumed. Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 12232d7..ffc6f30 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -23,11 +23,13 @@ #include "ts3a227e.h" struct ts3a227e { + struct device *dev; struct regmap *regmap; struct snd_soc_jack *jack; bool plugged; bool mic_present; unsigned int buttons_held; + int irq; }; /* Button values to be reported on the jack */ @@ -189,16 +191,28 @@ static irqreturn_t ts3a227e_interrupt(int irq, void *data) struct ts3a227e *ts3a227e = (struct ts3a227e *)data; struct regmap *regmap = ts3a227e->regmap; unsigned int int_reg, kp_int_reg, acc_reg, i; + struct device *dev = ts3a227e->dev; + int ret; /* Check for plug/unplug. */ - regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + if (ret) { + dev_err(dev, "failed to clear interrupt ret=%d\n", ret); + return IRQ_NONE; + } + if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); ts3a227e_new_jack_state(ts3a227e, acc_reg); } /* Report any key events. */ - regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + if (ret) { + dev_err(dev, "failed to clear key interrupt ret=%d\n", ret); + return IRQ_NONE; + } + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { if (kp_int_reg & PRESS_MASK(i)) ts3a227e->buttons_held |= (1 << i); @@ -283,6 +297,8 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, ts3a227e); + ts3a227e->dev = dev; + ts3a227e->irq = i2c->irq; ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); if (IS_ERR(ts3a227e->regmap)) @@ -320,6 +336,32 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, return 0; } +#ifdef CONFIG_PM_SLEEP +static int ts3a227e_suspend(struct device *dev) +{ + struct ts3a227e *ts3a227e = dev_get_drvdata(dev); + + dev_dbg(ts3a227e->dev, "suspend disable irq\n"); + disable_irq(ts3a227e->irq); + + return 0; +} + +static int ts3a227e_resume(struct device *dev) +{ + struct ts3a227e *ts3a227e = dev_get_drvdata(dev); + + dev_dbg(ts3a227e->dev, "resume enable irq\n"); + enable_irq(ts3a227e->irq); + + return 0; +} +#endif + +static const struct dev_pm_ops ts3a227e_pm = { + SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume) +}; + static const struct i2c_device_id ts3a227e_i2c_ids[] = { { "ts3a227e", 0 }, { } @@ -336,6 +378,7 @@ static struct i2c_driver ts3a227e_driver = { .driver = { .name = "ts3a227e", .owner = THIS_MODULE, + .pm = &ts3a227e_pm, .of_match_table = of_match_ptr(ts3a227e_of_match), }, .probe = ts3a227e_i2c_probe, -- cgit v0.10.2 From 779ea47399bae5d9418451f5283a3b2e35869627 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:51 -0300 Subject: ASoC: wm8904: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 265a4a5..07dc400 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - clk_prepare_enable(wm8904->mclk); + ret = clk_prepare_enable(wm8904->mclk); + if (ret) + return ret; break; case SND_SOC_BIAS_PREPARE: -- cgit v0.10.2 From cef6daa919c6912c4da629c3cee9c789f90583b1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:52 -0300 Subject: ASoC: wm8731: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index f22935a..628d50c 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -496,8 +496,11 @@ 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); + if (wm8731->mclk) { + ret = clk_prepare_enable(wm8731->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_PREPARE: break; -- cgit v0.10.2 From 402f2a4f808a5d284de724689751dcd018835579 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:53 -0300 Subject: ASoC: max98095: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9a46d3d..66afd2b 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1653,10 +1653,13 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, if (IS_ERR(max98095->mclk)) break; - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { clk_disable_unprepare(max98095->mclk); - else - clk_prepare_enable(max98095->mclk); + } else { + ret = clk_prepare_enable(max98095->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_STANDBY: -- cgit v0.10.2 From 7dd6bd8926f3142a237316035e72676c0c5c026f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:27 +0530 Subject: ASoC: intel: kconfig - Move DW_DMAC_CORE dependency to machines Some HSW and BYT machines depend on the DW_DMAC_CORE so they should have have depends on this symbol rather than common IPC lib as SKL onwards IPC lib is used but we don't depend on DW_DMAC_CORE Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f3060a4..6f9a54a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -29,7 +29,6 @@ config SND_SOC_INTEL_SST tristate "ASoC support for Intel(R) Smart Sound Technology" select SND_SOC_INTEL_SST_ACPI if ACPI depends on (X86 || COMPILE_TEST) - depends on DW_DMAC_CORE help This adds support for Intel(R) Smart Sound Technology (SST). Say Y if you have such a device @@ -48,6 +47,7 @@ config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ I2C_DESIGNWARE_PLATFORM + depends on DW_DMAC_CORE select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -59,6 +59,7 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on DW_DMAC_CORE select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -68,6 +69,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on DW_DMAC_CORE select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -78,6 +80,7 @@ config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM + depends on DW_DMAC_CORE select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help -- cgit v0.10.2 From 13735d1cecec1b3825f6834c74e67f82ab8cfe68 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:28 +0530 Subject: ASoC: intel - kconfig: remove SND_SOC_INTEL_SST prompt The SND_SOC_INTEL_SST is for common IPC lib and this should ideally be not selectable symbol but selected by respective machine driver So remove the prompt and get respective machines select it Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 6f9a54a..32262be 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -26,13 +26,9 @@ config SND_SST_IPC_ACPI depends on ACPI config SND_SOC_INTEL_SST - tristate "ASoC support for Intel(R) Smart Sound Technology" + tristate select SND_SOC_INTEL_SST_ACPI if ACPI depends on (X86 || COMPILE_TEST) - help - This adds support for Intel(R) Smart Sound Technology (SST). - Say Y if you have such a device - If unsure select "N". config SND_SOC_INTEL_SST_ACPI tristate @@ -45,9 +41,9 @@ config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ - I2C_DESIGNWARE_PLATFORM + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -58,8 +54,9 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on X86_INTEL_LPSS && I2C depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -68,8 +65,9 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on X86_INTEL_LPSS && I2C depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -78,9 +76,10 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ + depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help -- cgit v0.10.2 From 9569909f4dda3810be05223e4deb278b794f309b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:30 +0530 Subject: ASoC: intel - atom: statify sst_slot_enum_info Sparse complains that sst_slot_enum_info should be static, so make it static sound/soc/intel/atom/sst-atom-controls.c:135:5: warning: symbol 'sst_slot_enum_info' was not declared. Should it be static? Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 31e9b9e..c95bc52 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv) sizeof(cmd.header) + cmd.header.length); } -int sst_slot_enum_info(struct snd_kcontrol *kcontrol, +static int sst_slot_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct sst_enum *e = (struct sst_enum *)kcontrol->private_value; -- cgit v0.10.2 From 47a7bfc2bc99625e376e59fb01abf779c2d8a7b0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:31 +0530 Subject: ASoC: intel - atom: fix sst_platform_compr_ops declaration Sparse complains that sst_platform_compr_ops should be static, but the declaration of this symbol was not correct so declare the symbol as extern in header file sound/soc/intel/atom/sst-mfld-platform-compress.c:257:22: warning: symbol 'sst_platform_compr_ops' was not declared. Should it be static? Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 641ebe6..683e501 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -33,7 +33,6 @@ struct sst_device *sst; static DEFINE_MUTEX(sst_lock); -extern struct snd_compr_ops sst_platform_compr_ops; int sst_register_dsp(struct sst_device *dev) { diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 2409b23..cb32cc7 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -25,6 +25,7 @@ #include "sst-atom-controls.h" extern struct sst_device *sst; +extern struct snd_compr_ops sst_platform_compr_ops; #define SST_MONO 1 #define SST_STEREO 2 -- cgit v0.10.2 From a5afdc5bf53995385b621361c976b8a29e07f701 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 11:40:22 +0800 Subject: ASoC: rt286: Constify dmi_system_id table dmi_check_system() takes "const struct dmi_system_id *", so make the dmi_system_id table const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 2f39843..491ed16 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1108,7 +1108,7 @@ static const struct acpi_device_id rt286_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); -static struct dmi_system_id force_combo_jack_table[] = { +static const struct dmi_system_id force_combo_jack_table[] = { { .ident = "Intel Wilson Beach", .matches = { @@ -1118,7 +1118,7 @@ static struct dmi_system_id force_combo_jack_table[] = { { } }; -static struct dmi_system_id dmi_dell_dino[] = { +static const struct dmi_system_id dmi_dell_dino[] = { { .ident = "Dell Dino", .matches = { -- cgit v0.10.2 From 030e6ee241f0586308622bcdd273a317976b3169 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:26:44 +0800 Subject: ASoC: wm0010: Remove spurious missing IRQF_ONESHOT This reverts 58d468328646 ("ASoC: wm0010: Add missing IRQF_ONESHOT"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index e1da49f..f2c6ad4 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -953,7 +953,7 @@ static int wm0010_spi_probe(struct spi_device *spi) trigger = IRQF_TRIGGER_FALLING; trigger |= IRQF_ONESHOT; - ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT, + ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger, "wm0010", wm0010); if (ret) { dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n", -- cgit v0.10.2 From efc04ca22303dee1f34d038af3addc13621bed58 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:27:48 +0800 Subject: ASoC: wm5100: Remove spurious IRQF_ONESHOT flag This reverts 3d907cc30d07 ("ASoC: wm5100: Pass the IRQF_ONESHOT flag"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd8..98495dd 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2570,13 +2570,11 @@ static int wm5100_i2c_probe(struct i2c_client *i2c, if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) ret = request_threaded_irq(i2c->irq, NULL, - wm5100_edge_irq, - irq_flags | IRQF_ONESHOT, + wm5100_edge_irq, irq_flags, "wm5100", wm5100); else ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, - irq_flags | IRQF_ONESHOT, - "wm5100", + irq_flags, "wm5100", wm5100); if (ret != 0) { -- cgit v0.10.2 From ca94085139d4874701af4f149bebfb05e105b245 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:29:01 +0800 Subject: ASoC: wm8996: Remove spurious IRQF_ONESHOT flag This reverts ed043aebe6ec ("ASoC: wm8996: Pass the IRQF_ONESHOT flag"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f..370459f 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2647,12 +2647,10 @@ static int wm8996_probe(struct snd_soc_codec *codec) if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) ret = request_threaded_irq(i2c->irq, NULL, wm8996_edge_irq, - irq_flags | IRQF_ONESHOT, - "wm8996", codec); + irq_flags, "wm8996", codec); else ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq, - irq_flags | IRQF_ONESHOT, - "wm8996", codec); + irq_flags, "wm8996", codec); if (ret == 0) { /* Unmask the interrupt */ -- cgit v0.10.2 From 3582f9ae07613302eb2967704ed2cef741db9a8d Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 3 Jul 2015 16:04:03 +0530 Subject: ASoC: Intel: Define SKL ADSP IPC and general purpose registers Signed-off-by: Subhransu S. Prusty Signed-off-by: Kp, Jeeja Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h new file mode 100644 index 0000000..2ac120c --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -0,0 +1,62 @@ +/* + * Skylake SST DSP Support + * + * Copyright (C) 2014-15, 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 version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __SKL_SST_DSP_H__ +#define __SKL_SST_DSP_H__ + +/* Intel HD Audio General DSP Registers */ +#define SKL_ADSP_GEN_BASE 0x0 +#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) +#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08) +#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C) +#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10) +#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14) + +/* Intel HD Audio Inter-Processor Communication Registers */ +#define SKL_ADSP_IPC_BASE 0x40 +#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00) +#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04) +#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08) +#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C) +#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10) + +/* HIPCI */ +#define SKL_ADSP_REG_HIPCI_BUSY BIT(31) + +/* HIPCIE */ +#define SKL_ADSP_REG_HIPCIE_DONE BIT(30) + +/* HIPCCTL */ +#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1) +#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define SKL_ADSP_REG_HIPCT_BUSY BIT(31) + +/* Intel HD Audio SRAM Window 1 */ +#define SKL_ADSP_SRAM1_BASE 0xA000 + +#define SKL_ADSP_MMIO_LEN 0x10000 + +#define SKL_ADSP_W0_STAT_SZ 0x800 + +#define SKL_ADSP_W0_UP_SZ 0x800 + +#define SKL_ADSP_W1_SZ 0x1000 + +#define SKL_ADSPIC_IPC 1 +#define SKL_ADSPIS_IPC 1 + +#endif /*__SKL_SST_DSP_H__*/ -- cgit v0.10.2 From f7c765e604a22dd898ac414d59b5a8edfe428b65 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 3 Jul 2015 16:04:04 +0530 Subject: ASoC: Intel: Reorganize the common dsp structure We will add SKL platform data. So organizing common and platform specific data helps. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 396d545..50af167 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -258,6 +258,8 @@ struct sst_mem_block { */ struct sst_dsp { + /* Shared for all platforms */ + /* runtime */ struct sst_dsp_device *sst_dev; spinlock_t spinlock; /* IPC locking */ @@ -268,10 +270,6 @@ struct sst_dsp { int irq; u32 id; - /* list of free and used ADSP memory blocks */ - struct list_head used_block_list; - struct list_head free_block_list; - /* operations */ struct sst_ops *ops; @@ -284,6 +282,12 @@ struct sst_dsp { /* mailbox */ struct sst_mailbox mailbox; + /* HSW/Byt data */ + + /* list of free and used ADSP memory blocks */ + struct list_head used_block_list; + struct list_head free_block_list; + /* SST FW files loaded and their modules */ struct list_head module_list; struct list_head fw_list; -- cgit v0.10.2 From 1b7c12316982f74a5b8e7704c24cf5524d0723a3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 8 Jul 2015 20:47:43 +0200 Subject: ASoC: Prevent components from being bound to multiple cards A component can only be bound to a single card at a time. Binding it to card while it is already bound to another will result in undefined behavior. As the undefined behavior might only manifest itself later on it is not necessarily always straight forward to find the cause. To prevent this add a check that refuses to bind a component to multiple cards as well as prints a error describing the problem. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6ce6217..96bb71a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1102,9 +1102,19 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; - if (!strcmp(component->name, "snd-soc-dummy") || component->probed) + if (!strcmp(component->name, "snd-soc-dummy")) return 0; + if (component->probed) { + if (component->card != card) { + dev_err(component->dev, + "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", + card->name, component->card->name); + return -ENODEV; + } + return 0; + } + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); -- cgit v0.10.2 From abd31b32dde4683df6fd0439caa314aafd751698 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 8 Jul 2015 20:47:44 +0200 Subject: ASoC: Use card field to indicate whether a component is bound Use the card field of a component to indicate whether it is bound or not. This makes a certain sense given that the field contains the card the component is bound to and a component can only be bound to one card at a time. And it also requires to unset the card field when the component is unbound from the card. This makes the probded flag redundant and it can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf..59635a1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -758,7 +758,6 @@ struct snd_soc_component { unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ unsigned int registered_as_component:1; - unsigned int probed:1; struct list_head list; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 96bb71a..42575b0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -978,7 +978,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) static void soc_remove_component(struct snd_soc_component *component) { - if (!component->probed) + if (!component->card) return; /* This is a HACK and will be removed soon */ @@ -991,7 +991,7 @@ static void soc_remove_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); - component->probed = 0; + component->card = NULL; module_put(component->dev->driver->owner); } @@ -1105,7 +1105,7 @@ static int soc_probe_component(struct snd_soc_card *card, if (!strcmp(component->name, "snd-soc-dummy")) return 0; - if (component->probed) { + if (component->card) { if (component->card != card) { dev_err(component->dev, "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", @@ -1115,13 +1115,13 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } + if (!try_module_get(component->dev->driver->owner)) + return -ENODEV; + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); - if (!try_module_get(component->dev->driver->owner)) - return -ENODEV; - soc_init_component_debugfs(component); if (component->dapm_widgets) { @@ -1165,7 +1165,6 @@ static int soc_probe_component(struct snd_soc_card *card, snd_soc_dapm_add_routes(dapm, component->dapm_routes, component->num_dapm_routes); - component->probed = 1; list_add(&dapm->list, &card->dapm_list); /* This is a HACK and will be removed soon */ @@ -1176,6 +1175,7 @@ static int soc_probe_component(struct snd_soc_card *card, err_probe: soc_cleanup_component_debugfs(component); + component->card = NULL; module_put(component->dev->driver->owner); return ret; @@ -1459,7 +1459,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (component && component->probed) + if (component) soc_remove_component(component); } -- cgit v0.10.2 From f089d4d20fcbcf16a62ef3b4b57f41ecf59a5d83 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:12 +0100 Subject: mfd: wm5110: Add registers for custom write sequence triggers This register will be needed as part of some additional support for the headphone path on wm5110, so this patch adds the register and sets up its regmap config. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94..62a4aa1 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -676,6 +676,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ { 0x00000040, 0x0000 }, /* R64 - Wake control */ { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000042, 0x0000 }, /* R66 - Spare Triggers */ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ @@ -1716,6 +1717,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_PWM_DRIVE_3: case ARIZONA_WAKE_CONTROL: case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SPARE_TRIGGERS: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 3499d36..11affb3 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -39,6 +39,7 @@ #define ARIZONA_PWM_DRIVE_3 0x32 #define ARIZONA_WAKE_CONTROL 0x40 #define ARIZONA_SEQUENCE_CONTROL 0x41 +#define ARIZONA_SPARE_TRIGGERS 0x42 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1 0x61 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2 0x62 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3 0x63 @@ -1431,6 +1432,42 @@ #define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH 1 /* WSEQ_ENA_JD2_RISE */ /* + * R66 (0x42) - Spare Triggers + */ +#define ARIZONA_WS_TRG8 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_MASK 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_SHIFT 7 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_WIDTH 1 /* WS_TRG8 */ +#define ARIZONA_WS_TRG7 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_MASK 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_SHIFT 6 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_WIDTH 1 /* WS_TRG7 */ +#define ARIZONA_WS_TRG6 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_MASK 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_SHIFT 5 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_WIDTH 1 /* WS_TRG6 */ +#define ARIZONA_WS_TRG5 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_MASK 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_SHIFT 4 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_WIDTH 1 /* WS_TRG5 */ +#define ARIZONA_WS_TRG4 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_MASK 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_SHIFT 3 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_WIDTH 1 /* WS_TRG4 */ +#define ARIZONA_WS_TRG3 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_MASK 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_SHIFT 2 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_WIDTH 1 /* WS_TRG3 */ +#define ARIZONA_WS_TRG2 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_MASK 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_SHIFT 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_WIDTH 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG1 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_MASK 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_SHIFT 0 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_WIDTH 1 /* WS_TRG1 */ + +/* * R97 (0x61) - Sample Rate Sequence Select 1 */ #define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR_MASK 0x01FF /* WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR - [8:0] */ -- cgit v0.10.2 From 81207880cef207cd89db863f9aa1d65f22b4f2a2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:13 +0100 Subject: mfd: wm5110: Add register patch for rev E and above Add a register patch for rev E and above that configures the location of some write sequences to assist with the headphone enables. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 62a4aa1..e089242 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -249,6 +249,16 @@ static const struct reg_default wm5110_revd_patch[] = { { 0x80, 0x0 }, }; +/* Add extra headphone write sequence locations */ +static const struct reg_default wm5110_reve_patch[] = { + { 0x80, 0x3 }, + { 0x80, 0x3 }, + { 0x4b, 0x138 }, + { 0x4c, 0x13d }, + { 0x80, 0x0 }, + { 0x80, 0x0 }, +}; + /* We use a function so we can use ARRAY_SIZE() */ int wm5110_patch(struct arizona *arizona) { @@ -266,7 +276,9 @@ int wm5110_patch(struct arizona *arizona) wm5110_revd_patch, ARRAY_SIZE(wm5110_revd_patch)); default: - return 0; + return regmap_register_patch(arizona->regmap, + wm5110_reve_patch, + ARRAY_SIZE(wm5110_reve_patch)); } } EXPORT_SYMBOL_GPL(wm5110_patch); -- cgit v0.10.2 From d1acd31883d78f905a930493ff145ca4a25ad680 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:14 +0100 Subject: ASoC: wm5110: Add special DRE on/off handling for the headphone path For the best performance the headphone path enable/disable must be handled specially for the situations of DRE on and DRE off. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 709fcc6..b5c201b 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -131,6 +131,25 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = { { 0x33fb, 0xfe00 }, }; +static const struct reg_default wm5110_sysclk_reve_patch[] = { + { 0x3270, 0xE410 }, + { 0x3271, 0x3078 }, + { 0x3272, 0xE410 }, + { 0x3273, 0x3070 }, + { 0x3274, 0xE410 }, + { 0x3275, 0x3066 }, + { 0x3276, 0xE410 }, + { 0x3277, 0x3056 }, + { 0x327A, 0xE414 }, + { 0x327B, 0x3078 }, + { 0x327C, 0xE414 }, + { 0x327D, 0x3070 }, + { 0x327E, 0xE414 }, + { 0x327F, 0x3066 }, + { 0x3280, 0xE414 }, + { 0x3281, 0x3056 }, +}; + static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -146,7 +165,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch); break; default: - return 0; + patch = wm5110_sysclk_reve_patch; + patch_size = ARRAY_SIZE(wm5110_sysclk_reve_patch); + break; } switch (event) { @@ -164,6 +185,249 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const struct reg_default wm5110_no_dre_left_enable[] = { + { 0x3024, 0xE410 }, + { 0x3025, 0x0056 }, + { 0x301B, 0x0224 }, + { 0x301F, 0x4263 }, + { 0x3021, 0x5291 }, + { 0x3030, 0xE410 }, + { 0x3031, 0x3066 }, + { 0x3032, 0xE410 }, + { 0x3033, 0x3070 }, + { 0x3034, 0xE410 }, + { 0x3035, 0x3078 }, + { 0x3036, 0xE410 }, + { 0x3037, 0x3080 }, + { 0x3038, 0xE410 }, + { 0x3039, 0x3080 }, +}; + +static const struct reg_default wm5110_dre_left_enable[] = { + { 0x3024, 0x0231 }, + { 0x3025, 0x0B00 }, + { 0x301B, 0x0227 }, + { 0x301F, 0x4266 }, + { 0x3021, 0x5294 }, + { 0x3030, 0xE231 }, + { 0x3031, 0x0266 }, + { 0x3032, 0x8231 }, + { 0x3033, 0x4B15 }, + { 0x3034, 0x8231 }, + { 0x3035, 0x0B15 }, + { 0x3036, 0xE231 }, + { 0x3037, 0x5294 }, + { 0x3038, 0x0231 }, + { 0x3039, 0x0B00 }, +}; + +static const struct reg_default wm5110_no_dre_right_enable[] = { + { 0x3074, 0xE414 }, + { 0x3075, 0x0056 }, + { 0x306B, 0x0224 }, + { 0x306F, 0x4263 }, + { 0x3071, 0x5291 }, + { 0x3080, 0xE414 }, + { 0x3081, 0x3066 }, + { 0x3082, 0xE414 }, + { 0x3083, 0x3070 }, + { 0x3084, 0xE414 }, + { 0x3085, 0x3078 }, + { 0x3086, 0xE414 }, + { 0x3087, 0x3080 }, + { 0x3088, 0xE414 }, + { 0x3089, 0x3080 }, +}; + +static const struct reg_default wm5110_dre_right_enable[] = { + { 0x3074, 0x0231 }, + { 0x3075, 0x0B00 }, + { 0x306B, 0x0227 }, + { 0x306F, 0x4266 }, + { 0x3071, 0x5294 }, + { 0x3080, 0xE231 }, + { 0x3081, 0x0266 }, + { 0x3082, 0x8231 }, + { 0x3083, 0x4B17 }, + { 0x3084, 0x8231 }, + { 0x3085, 0x0B17 }, + { 0x3086, 0xE231 }, + { 0x3087, 0x5294 }, + { 0x3088, 0x0231 }, + { 0x3089, 0x0B00 }, +}; + +static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); + const struct reg_default *wseq; + int nregs; + + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + if (val & ARIZONA_DRE1L_ENA_MASK) { + wseq = wm5110_dre_left_enable; + nregs = ARRAY_SIZE(wm5110_dre_left_enable); + } else { + wseq = wm5110_no_dre_left_enable; + nregs = ARRAY_SIZE(wm5110_no_dre_left_enable); + priv->out_up_delay += 10; + } + break; + case ARIZONA_OUT1R_ENA_SHIFT: + if (val & ARIZONA_DRE1R_ENA_MASK) { + wseq = wm5110_dre_right_enable; + nregs = ARRAY_SIZE(wm5110_dre_right_enable); + } else { + wseq = wm5110_no_dre_right_enable; + nregs = ARRAY_SIZE(wm5110_no_dre_right_enable); + priv->out_up_delay += 10; + } + break; + default: + return 0; + } + + return regmap_multi_reg_write(arizona->regmap, wseq, nregs); +} + +static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); + + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + if (!(val & ARIZONA_DRE1L_ENA_MASK)) { + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG1, ARIZONA_WS_TRG1); + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG1, 0); + priv->out_down_delay += 27; + } + break; + case ARIZONA_OUT1R_ENA_SHIFT: + if (!(val & ARIZONA_DRE1R_ENA_MASK)) { + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG2, ARIZONA_WS_TRG2); + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG2, 0); + priv->out_down_delay += 27; + } + break; + default: + break; + } + + return 0; +} + +static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + + switch (priv->arizona->rev) { + case 0 ... 3: + break; + default: + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wm5110_hp_pre_enable(w); + break; + case SND_SOC_DAPM_PRE_PMD: + wm5110_hp_pre_disable(w); + break; + default: + break; + } + break; + } + + return arizona_hp_ev(w, kcontrol, event); +} + +static int wm5110_clear_pga_volume(struct arizona *arizona, int output) +{ + struct reg_default clear_pga = { + ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 + }; + int ret; + + ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1); + if (ret) + dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n", + clear_pga.reg, ret); + + return ret; +} + +static int wm5110_put_dre(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int ena, dre; + unsigned int mask = (0x1 << mc->shift) | (0x1 << mc->rshift); + unsigned int lnew = (!!ucontrol->value.integer.value[0]) << mc->shift; + unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift; + unsigned int lold, rold; + unsigned int lena, rena; + int ret; + + snd_soc_dapm_mutex_lock(dapm); + + ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &ena); + if (ret) { + dev_err(arizona->dev, "Failed to read output state: %d\n", ret); + goto err; + } + ret = regmap_read(arizona->regmap, ARIZONA_DRE_ENABLE, &dre); + if (ret) { + dev_err(arizona->dev, "Failed to read DRE state: %d\n", ret); + goto err; + } + + lold = dre & (1 << mc->shift); + rold = dre & (1 << mc->rshift); + /* Enables are channel wise swapped from the DRE enables */ + lena = ena & (1 << mc->rshift); + rena = ena & (1 << mc->shift); + + if ((lena && lnew != lold) || (rena && rnew != rold)) { + dev_err(arizona->dev, "Can't change DRE on active outputs\n"); + ret = -EBUSY; + goto err; + } + + ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE, + mask, lnew | rnew); + if (ret) { + dev_err(arizona->dev, "Failed to set DRE: %d\n", ret); + goto err; + } + + /* Force reset of PGA volumes, if turning DRE off */ + if (!lnew && lold) + wm5110_clear_pga_volume(arizona, mc->shift); + + if (!rnew && rold) + wm5110_clear_pga_volume(arizona, mc->rshift); + +err: + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); @@ -409,12 +673,15 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), -SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), -SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0), -SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0), +SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), +SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), +SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -904,11 +1171,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, -- cgit v0.10.2 From 5ed68f0a28f96c5127246d1743dd57b58a090f07 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 9 Jul 2015 11:28:46 +0100 Subject: ASoC: arizona: Use the more idiomatic params_width Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a88202d..c246fbd 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1504,7 +1504,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, else rates = &arizona_48k_bclk_rates[0]; - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (tdm_slots) { arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", -- cgit v0.10.2 From a40e693c7f5ee3a1a7d1f6aef63c5dadbec64e10 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:08 +0530 Subject: ASoC: Intel: Add Skylake HDA platform driver This patch starts to add the Skylake HDA platform driver by defining SoC CPU dais, DMA driver ops and implements ALSA operations Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c new file mode 100644 index 0000000..c171def --- /dev/null +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -0,0 +1,586 @@ +/* + * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Jeeja KP + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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 "skl.h" + +#define HDA_MONO 1 +#define HDA_STEREO 2 + +static struct snd_pcm_hardware azx_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START | + 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, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = AZX_MAX_BUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = AZX_MAX_BUF_SIZE / 2, + .periods_min = 2, + .periods_max = AZX_MAX_FRAG, + .fifo_size = 0, +}; + +static inline +struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) +{ + return substream->runtime->private_data; +} + +static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct hdac_stream *hstream = hdac_stream(stream); + struct hdac_bus *bus = hstream->bus; + + return hbus_to_ebus(bus); +} + +static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus, + struct snd_pcm_substream *substream, + size_t size) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + + hdac_stream(stream)->bufsize = 0; + hdac_stream(stream)->period_bytes = 0; + hdac_stream(stream)->format_val = 0; + + return snd_pcm_lib_malloc_pages(substream, size); +} + +static int skl_substream_free_pages(struct hdac_bus *bus, + struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, + struct snd_pcm_runtime *runtime) +{ + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + /* avoid wrap-around with wall-clock */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, + 20, 178000000); +} + +static int skl_pcm_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct skl_dma_params *dma_params; + int ret; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + ret = pm_runtime_get_sync(dai->dev); + if (ret) + return ret; + + stream = snd_hdac_ext_stream_assign(ebus, substream, + HDAC_EXT_STREAM_TYPE_COUPLED); + if (stream == NULL) + return -EBUSY; + + skl_set_pcm_constrains(ebus, runtime); + + /* + * disable WALLCLOCK 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; /* legacy */ + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; + } + + runtime->private_data = stream; + + dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); + if (!dma_params) + return -ENOMEM; + + dma_params->stream_tag = hdac_stream(stream)->stream_tag; + snd_soc_dai_set_dma_data(dai, substream, dma_params); + + dev_dbg(dai->dev, "stream tag set in dma params=%d\n", + dma_params->stream_tag); + snd_pcm_set_sync(substream); + + return 0; +} + +static int skl_get_format(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct skl_dma_params *dma_params; + int format_val = 0; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + + return format_val; +} + +static int skl_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + unsigned int format_val; + int err; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + if (hdac_stream(stream)->prepared) { + dev_dbg(dai->dev, "already stream is prepared - returning\n"); + return 0; + } + + format_val = skl_get_format(substream, dai); + dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", + hdac_stream(stream)->stream_tag, format_val); + snd_hdac_stream_reset(hdac_stream(stream)); + + err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); + if (err < 0) + return err; + + err = snd_hdac_stream_setup(hdac_stream(stream)); + if (err < 0) + return err; + + hdac_stream(stream)->prepared = 1; + + return err; +} + +static int skl_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + ret = skl_substream_alloc_pages(ebus, substream, + params_buffer_bytes(params)); + if (ret < 0) + return ret; + + dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + + return 0; +} + +static void skl_pcm_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct skl_dma_params *dma_params = NULL; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_COUPLED); + + dma_params = snd_soc_dai_get_dma_data(dai, substream); + /* + * now we should set this to NULL as we are freeing by the + * dma_params + */ + snd_soc_dai_set_dma_data(dai, substream, NULL); + + pm_runtime_mark_last_busy(dai->dev); + pm_runtime_put_autosuspend(dai->dev); + kfree(dma_params); +} + +static int skl_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + snd_hdac_stream_cleanup(hdac_stream(stream)); + hdac_stream(stream)->prepared = 0; + + return skl_substream_free_pages(ebus_to_hbus(ebus), substream); +} + +static struct snd_soc_dai_ops skl_pcm_dai_ops = { + .startup = skl_pcm_open, + .shutdown = skl_pcm_close, + .prepare = skl_pcm_prepare, + .hw_params = skl_pcm_hw_params, + .hw_free = skl_pcm_hw_free, +}; + +static struct snd_soc_dai_driver skl_platform_dai[] = { +{ + .name = "System Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "System Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "System Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "Deepbuffer Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "Deepbuffer Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "LowLatency Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "Low Latency Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +}; + +static int skl_platform_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, + dai_link->cpu_dai_name); + + runtime = substream->runtime; + snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); + + return 0; +} + +static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_ext_stream *stream; + struct snd_pcm_substream *s; + bool start; + int sbits = 0; + unsigned long cookie; + struct hdac_stream *hstr; + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = true; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = false; + break; + + default: + return -EINVAL; + } + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + stream = get_hdac_ext_stream(s); + sbits |= 1 << hdac_stream(stream)->index; + snd_pcm_trigger_done(s, substream); + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + /* first, set SYNC bits of corresponding streams */ + snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + stream = get_hdac_ext_stream(s); + if (start) + snd_hdac_stream_start(hdac_stream(stream), true); + else + snd_hdac_stream_stop(hdac_stream(stream)); + } + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + snd_hdac_stream_sync(hstr, start, sbits); + + spin_lock_irqsave(&bus->reg_lock, cookie); + + /* reset SYNC bits */ + snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); + if (start) + snd_hdac_stream_timecounter_init(hstr, sbits); + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + return 0; +} + +/* calculate runtime delay from LPIB */ +static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *sstream, + unsigned int pos) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_stream *hstream = hdac_stream(sstream); + struct snd_pcm_substream *substream = hstream->substream; + int stream = substream->stream; + unsigned int lpib_pos = snd_hdac_stream_get_pos_lpib(hstream); + int delay; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + + if (delay < 0) { + if (delay >= hstream->delay_negative_threshold) + delay = 0; + else + delay += hstream->bufsize; + } + + if (delay >= hstream->period_bytes) { + dev_info(bus->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, hstream->period_bytes); + delay = 0; + } + + return bytes_to_frames(substream->runtime, delay); +} + +static unsigned int skl_get_position(struct hdac_ext_stream *hstream, + int codec_delay) +{ + struct hdac_stream *hstr = hdac_stream(hstream); + struct snd_pcm_substream *substream = hstr->substream; + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + unsigned int pos; + int delay; + + /* use the position buffer as default */ + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + + if (pos >= hdac_stream(hstream)->bufsize) + pos = 0; + + if (substream->runtime) { + delay = skl_get_delay_from_lpib(ebus, hstream, pos) + + codec_delay; + substream->runtime->delay += delay; + } + + return pos; +} + +static snd_pcm_uframes_t skl_platform_pcm_pointer + (struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + + return bytes_to_frames(substream->runtime, + skl_get_position(hstream, 0)); +} + +static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, + u64 nsec) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->codec_dai; + u64 codec_frames, codec_nsecs; + + if (!codec_dai->driver->ops->delay) + return nsec; + + codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); + codec_nsecs = div_u64(codec_frames * 1000000000LL, + substream->runtime->rate); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return nsec + codec_nsecs; + + return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; +} + +static int skl_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 hdac_ext_stream *sstream = get_hdac_ext_stream(substream); + struct hdac_stream *hstr = hdac_stream(sstream); + u64 nsec; + + if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && + (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { + + snd_pcm_gettime(substream->runtime, system_ts); + + nsec = timecounter_read(&hstr->tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + if (audio_tstamp_config->report_delay) + nsec = skl_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 struct is valid */ + audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ + + } else { + audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; + } + + return 0; +} + +static struct snd_pcm_ops skl_platform_ops = { + .open = skl_platform_open, + .ioctl = snd_pcm_lib_ioctl, + .trigger = skl_platform_pcm_trigger, + .pointer = skl_platform_pcm_pointer, + .get_time_info = skl_get_time_info, + .mmap = snd_pcm_lib_default_mmap, + .page = snd_pcm_sgbuf_ops_page, +}; + +static void skl_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) + +static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->cpu_dai; + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_pcm *pcm = rtd->pcm; + unsigned int size; + int retval = 0; + struct skl *skl = ebus_to_skl(ebus); + + if (dai->driver->playback.channels_min || + dai->driver->capture.channels_min) { + /* buffer pre-allocation */ + size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; + if (size > MAX_PREALLOC_SIZE) + size = MAX_PREALLOC_SIZE; + retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(skl->pci), + size, MAX_PREALLOC_SIZE); + if (retval) { + dev_err(dai->dev, "dma buffer allocationf fail\n"); + return retval; + } + } + + return retval; +} + +static struct snd_soc_platform_driver skl_platform_drv = { + .ops = &skl_platform_ops, + .pcm_new = skl_pcm_new, + .pcm_free = skl_pcm_free, +}; + +static const struct snd_soc_component_driver skl_component = { + .name = "pcm", +}; + +int skl_platform_register(struct device *dev) +{ + int ret; + + ret = snd_soc_register_platform(dev, &skl_platform_drv); + if (ret) { + dev_err(dev, "soc platform registration failed %d\n", ret); + return ret; + } + ret = snd_soc_register_component(dev, &skl_component, + skl_platform_dai, + ARRAY_SIZE(skl_platform_dai)); + if (ret) { + dev_err(dev, "soc component registration failed %d\n", ret); + snd_soc_unregister_platform(dev); + } + + return ret; + +} + +int skl_platform_unregister(struct device *dev) +{ + snd_soc_unregister_component(dev); + snd_soc_unregister_platform(dev); + return 0; +} diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h new file mode 100644 index 0000000..cc0f3e2 --- /dev/null +++ b/sound/soc/intel/skylake/skl.h @@ -0,0 +1,71 @@ +/* + * skl.h - HD Audio skylake defintions. + * + * Copyright (C) 2015 Intel Corp + * Author: Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#ifndef __SOUND_SOC_SKL_H +#define __SOUND_SOC_SKL_H + +#include +#include + +#define SKL_SUSPEND_DELAY 2000 + +/* Vendor Specific Registers */ +#define AZX_REG_VS_EM1 0x1000 +#define AZX_REG_VS_INRC 0x1004 +#define AZX_REG_VS_OUTRC 0x1008 +#define AZX_REG_VS_FIFOTRK 0x100C +#define AZX_REG_VS_FIFOTRK2 0x1010 +#define AZX_REG_VS_EM2 0x1030 +#define AZX_REG_VS_EM3L 0x1038 +#define AZX_REG_VS_EM3U 0x103C +#define AZX_REG_VS_EM4L 0x1040 +#define AZX_REG_VS_EM4U 0x1044 +#define AZX_REG_VS_LTRC 0x1048 +#define AZX_REG_VS_D0I3C 0x104A +#define AZX_REG_VS_PCE 0x104B +#define AZX_REG_VS_L2MAGC 0x1050 +#define AZX_REG_VS_L2LAHPT 0x1054 +#define AZX_REG_VS_SDXDPIB_XBASE 0x1084 +#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20 +#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 +#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 + +struct skl { + struct hdac_ext_bus ebus; + struct pci_dev *pci; + + unsigned int init_failed:1; /* delayed init failed */ + struct platform_device *dmic_dev; +}; + +#define skl_to_ebus(s) (&(s)->ebus) +#define ebus_to_skl(sbus) \ + container_of(sbus, struct skl, sbus) + +/* to pass dai dma data */ +struct skl_dma_params { + u32 format; + u8 stream_tag; +}; + +int skl_platform_unregister(struct device *dev); +int skl_platform_register(struct device *dev); + +#endif /* __SOUND_SOC_SKL_H */ -- cgit v0.10.2 From d8c2dab8381d58376d127c64553e499569f4d22a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:09 +0530 Subject: ASoC: Intel: Add Skylake HDA audio driver This patch follows up by adding the HDA controller operations. This code is mostly derived from Intel HDA PCI driver without legacy bits Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c new file mode 100644 index 0000000..dfbc15c --- /dev/null +++ b/sound/soc/intel/skylake/skl.c @@ -0,0 +1,525 @@ +/* + * skl.c - Implementation of ASoC Intel SKL HD Audio driver + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Jeeja KP + * + * Derived mostly from Intel HDA driver with following copyrights: + * Copyright (c) 2004 Takashi Iwai + * PeiSen Hou + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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 "skl.h" + +/* + * initialize the PCI registers + */ +static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, + unsigned char mask, unsigned char val) +{ + unsigned char data; + + pci_read_config_byte(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_byte(pci, reg, data); +} + +static void skl_init_pci(struct skl *skl) +{ + struct hdac_ext_bus *ebus = &skl->ebus; + + /* + * Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs. + * The PCI register TCSEL is defined in the Intel manuals. + */ + dev_dbg(ebus_to_hbus(ebus)->dev, "Clearing TCSEL\n"); + skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); +} + +/* called from IRQ */ +static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) +{ + snd_pcm_period_elapsed(hstr->substream); +} + +static irqreturn_t skl_interrupt(int irq, void *dev_id) +{ + struct hdac_ext_bus *ebus = dev_id; + struct hdac_bus *bus = ebus_to_hbus(ebus); + u32 status; + + if (!pm_runtime_active(bus->dev)) + return IRQ_NONE; + + spin_lock(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&bus->reg_lock); + return IRQ_NONE; + } + + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } + + spin_unlock(&bus->reg_lock); + + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static irqreturn_t skl_threaded_handler(int irq, void *dev_id) +{ + struct hdac_ext_bus *ebus = dev_id; + struct hdac_bus *bus = ebus_to_hbus(ebus); + u32 status; + + status = snd_hdac_chip_readl(bus, INTSTS); + + snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update); + + return IRQ_HANDLED; +} + +static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + int ret; + + ret = request_threaded_irq(skl->pci->irq, skl_interrupt, + skl_threaded_handler, + IRQF_SHARED, + KBUILD_MODNAME, ebus); + if (ret) { + dev_err(bus->dev, + "unable to grab IRQ %d, disabling device\n", + skl->pci->irq); + return ret; + } + + bus->irq = skl->pci->irq; + pci_intx(skl->pci, 1); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/* + * power management + */ +static int skl_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_enter_link_reset(bus); + + return 0; +} + +static int skl_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl *hda = ebus_to_skl(ebus); + + skl_init_pci(hda); + + snd_hdac_bus_init_chip(bus, 1); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int skl_runtime_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + dev_dbg(bus->dev, "in %s\n", __func__); + + /* enable controller wake up event */ + snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK); + + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_enter_link_reset(bus); + + return 0; +} + +static int skl_runtime_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl *hda = ebus_to_skl(ebus); + int status; + + dev_dbg(bus->dev, "in %s\n", __func__); + + /* Read STATESTS before controller reset */ + status = snd_hdac_chip_readw(bus, STATESTS); + + skl_init_pci(hda); + snd_hdac_bus_init_chip(bus, true); + /* disable controller Wake Up event */ + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops skl_pm = { + SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) + SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) +}; + +/* + * destructor + */ +static int skl_free(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + skl->init_failed = 1; /* to be sure */ + + snd_hdac_ext_stop_streams(ebus); + + if (bus->irq >= 0) + free_irq(bus->irq, (void *)bus); + if (bus->remap_addr) + iounmap(bus->remap_addr); + + snd_hdac_bus_free_stream_pages(bus); + snd_hdac_stream_free_all(ebus); + snd_hdac_link_free_all(ebus); + pci_release_regions(skl->pci); + pci_disable_device(skl->pci); + + snd_hdac_ext_bus_exit(ebus); + + return 0; +} + +static int skl_dmic_device_register(struct skl *skl) +{ + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct platform_device *pdev; + int ret; + + /* SKL has one dmic port, so allocate dmic device for this */ + pdev = platform_device_alloc("dmic-codec", -1); + if (!pdev) { + dev_err(bus->dev, "failed to allocate dmic device\n"); + return -ENOMEM; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(bus->dev, "failed to add dmic device: %d\n", ret); + platform_device_put(pdev); + return ret; + } + skl->dmic_dev = pdev; + + return 0; +} + +static void skl_dmic_device_unregister(struct skl *skl) +{ + if (skl->dmic_dev) + platform_device_unregister(skl->dmic_dev); +} + +/* + * Probe the given codec address + */ +static int probe_codec(struct hdac_ext_bus *ebus, int addr) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res; + + mutex_lock(&bus->cmd_mutex); + snd_hdac_bus_send_cmd(bus, cmd); + snd_hdac_bus_get_response(bus, addr, &res); + mutex_unlock(&bus->cmd_mutex); + if (res == -1) + return -EIO; + dev_dbg(bus->dev, "codec #%d probed OK\n", addr); + + return snd_hdac_ext_bus_device_init(ebus, addr); +} + +/* Codec initialization */ +static int skl_codec_create(struct hdac_ext_bus *ebus) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + int c, max_slots; + + max_slots = HDA_MAX_CODECS; + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { + if ((bus->codec_mask & (1 << c))) { + if (probe_codec(ebus, c) < 0) { + /* + * Some BIOSen give you wrong codec addresses + * that don't exist + */ + dev_warn(bus->dev, + "Codec #%d probe error; disabling it...\n", c); + bus->codec_mask &= ~(1 << c); + /* + * More badly, accessing to a non-existing + * codec often screws up the controller bus, + * and disturbs the further communications. + * Thus if an error occurs during probing, + * better to reset the controller bus to get + * back to the sanity state. + */ + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_init_chip(bus, true); + } + } + } + + return 0; +} + +static const struct hdac_bus_ops bus_core_ops = { + .command = snd_hdac_bus_send_cmd, + .get_response = snd_hdac_bus_get_response, +}; + +/* + * constructor + */ +static int skl_create(struct pci_dev *pci, + const struct hdac_io_ops *io_ops, + struct skl **rskl) +{ + struct skl *skl; + struct hdac_ext_bus *ebus; + + int err; + + *rskl = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL); + if (!skl) { + pci_disable_device(pci); + return -ENOMEM; + } + ebus = &skl->ebus; + snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops); + ebus->bus.use_posbuf = 1; + skl->pci = pci; + + ebus->bus.bdl_pos_adj = 0; + + *rskl = skl; + + return 0; +} + +static int skl_first_init(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct pci_dev *pci = skl->pci; + int err; + unsigned short gcap; + int cp_streams, pb_streams, start_idx; + + err = pci_request_regions(pci, "Skylake HD audio"); + if (err < 0) + return err; + + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (bus->remap_addr == NULL) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + if (skl_acquire_irq(ebus, 0) < 0) + return -EBUSY; + + pci_set_master(pci); + synchronize_irq(bus->irq); + + gcap = snd_hdac_chip_readw(bus, GCAP); + dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); + + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); + } else { + dma_set_mask(bus->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); + } + + /* read number of streams from GCAP register */ + cp_streams = (gcap >> 8) & 0x0f; + pb_streams = (gcap >> 12) & 0x0f; + + if (!pb_streams && !cp_streams) + return -EIO; + + ebus->num_streams = cp_streams + pb_streams; + + /* initialize streams */ + snd_hdac_ext_stream_init_all + (ebus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); + start_idx = cp_streams; + snd_hdac_ext_stream_init_all + (ebus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); + + err = snd_hdac_bus_alloc_stream_pages(bus); + if (err < 0) + return err; + + /* initialize chip */ + skl_init_pci(skl); + + snd_hdac_bus_init_chip(bus, true); + + /* codec detection */ + if (!bus->codec_mask) { + dev_err(bus->dev, "no codecs found!\n"); + return -ENODEV; + } + + return 0; +} + +static int skl_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct skl *skl; + struct hdac_ext_bus *ebus = NULL; + struct hdac_bus *bus = NULL; + int err; + + /* we use ext core ops, so provide NULL for ops here */ + err = skl_create(pci, NULL, &skl); + if (err < 0) + return err; + + ebus = &skl->ebus; + bus = ebus_to_hbus(ebus); + + err = skl_first_init(ebus); + if (err < 0) + goto out_free; + + pci_set_drvdata(skl->pci, ebus); + + /* create device for soc dmic */ + err = skl_dmic_device_register(skl); + if (err < 0) + goto out_free; + + /* register platform dai and controls */ + err = skl_platform_register(bus->dev); + if (err < 0) + goto out_dmic_free; + + /* create codec instances */ + err = skl_codec_create(ebus); + if (err < 0) + goto out_unregister; + + /*configure PM */ + pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY); + pm_runtime_use_autosuspend(bus->dev); + pm_runtime_put_noidle(bus->dev); + pm_runtime_allow(bus->dev); + + return 0; + +out_unregister: + skl_platform_unregister(bus->dev); +out_dmic_free: + skl_dmic_device_unregister(skl); +out_free: + skl->init_failed = 1; + skl_free(ebus); + + return err; +} + +static void skl_remove(struct pci_dev *pci) +{ + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + + if (pci_dev_run_wake(pci)) + pm_runtime_get_noresume(&pci->dev); + pci_dev_put(pci); + skl_platform_unregister(&pci->dev); + skl_dmic_device_unregister(skl); + skl_free(ebus); + dev_set_drvdata(&pci->dev, NULL); +} + +/* PCI IDs */ +static const struct pci_device_id skl_ids[] = { + /* Sunrise Point-LP */ + { PCI_DEVICE(0x8086, 0x9d70), 0}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, skl_ids); + +/* pci_driver definition */ +static struct pci_driver skl_driver = { + .name = KBUILD_MODNAME, + .id_table = skl_ids, + .probe = skl_probe, + .remove = skl_remove, + .driver = { + .pm = &skl_pm, + }, +}; +module_pci_driver(skl_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver"); -- cgit v0.10.2 From eb965e3686f5cea669444d120f3723efa88ed56a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:10 +0530 Subject: ASoC: Intel: Add makefile support for SKL driver This adds makefile and Kconfig to enable Skylake HD audio PCM driver Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 32262be..d8b9943 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -134,3 +134,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with MAX98090 audio codec it also can support TI jack chip as aux device. If unsure select "N". + +config SND_SOC_INTEL_SKYLAKE + tristate + select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 6de5d5c..2b45435 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/ +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ # Machine support obj-$(CONFIG_SND_SOC) += boards/ diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile new file mode 100644 index 0000000..734d17c --- /dev/null +++ b/sound/soc/intel/skylake/Makefile @@ -0,0 +1,3 @@ +snd-soc-skl-objs := skl.o skl-pcm.o + +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o -- cgit v0.10.2 From 0505700104cd98da6d11c01b8063cffdb1b8d7d7 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:11 +0530 Subject: ASoC: Intel: Add support for decoupled mode in skl driver Decoupled mode is where audio link is broken to frontend HDA and backend (hda/i2s/dmic/hdmi) links. This patch adds support for decoupled mode and then adds dais, dai ops for be/fe cpu dais and interrupt handler change to support decoupled mode Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c171def..7d617bf 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -96,6 +96,14 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, 20, 178000000); } +static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) +{ + if (ebus->ppcap) + return HDAC_EXT_STREAM_TYPE_HOST; + else + return HDAC_EXT_STREAM_TYPE_COUPLED; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -111,7 +119,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, return ret; stream = snd_hdac_ext_stream_assign(ebus, substream, - HDAC_EXT_STREAM_TYPE_COUPLED); + skl_get_host_stream_type(ebus)); if (stream == NULL) return -EBUSY; @@ -147,12 +155,23 @@ static int skl_get_format(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct skl_dma_params *dma_params; + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); int format_val = 0; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; + if (ebus->ppcap) { + struct snd_pcm_runtime *runtime = substream->runtime; + + format_val = snd_hdac_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + 32, 0); + } else { + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + } return format_val; } @@ -193,8 +212,9 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - int ret; + int ret, dma_id; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); ret = skl_substream_alloc_pages(ebus, substream, @@ -205,6 +225,9 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); + dma_id = hdac_stream(stream)->stream_tag - 1; + dev_dbg(dai->dev, "dma_id=%d\n", dma_id); + return 0; } @@ -212,10 +235,12 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_COUPLED); + + snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus)); dma_params = snd_soc_dai_get_dma_data(dai, substream); /* @@ -243,6 +268,150 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, return skl_substream_free_pages(ebus_to_hbus(ebus), substream); } +static int skl_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *link_dev; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct skl_dma_params *dma_params; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int dma_id; + + pr_debug("%s\n", __func__); + link_dev = snd_hdac_ext_stream_assign(ebus, substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!link_dev) + return -EBUSY; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + + /* set the stream tag in the codec dai dma params */ + dma_params = (struct skl_dma_params *) + snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params); + dma_id = hdac_stream(link_dev)->stream_tag - 1; + + return 0; +} + +static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + unsigned int format_val = 0; + struct skl_dma_params *dma_params; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_pcm_hw_params *params; + struct snd_interval *channels, *rate; + struct hdac_ext_link *link; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + if (link_dev->link_prepared) { + dev_dbg(dai->dev, "already stream is prepared - returning\n"); + return 0; + } + params = devm_kzalloc(dai->dev, sizeof(*params), GFP_KERNEL); + if (params == NULL) + return -ENOMEM; + + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = substream->runtime->channels; + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->min = rate->max = substream->runtime->rate; + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + substream->runtime->format); + + + dma_params = (struct skl_dma_params *) + snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", + hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); + + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); + link_dev->link_prepared = 1; + + return 0; +} + +static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_link_stream_start(link_dev); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int skl_link_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_link *link; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + link_dev->link_prepared = 0; + + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + return 0; +} + +static int skl_hda_be_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return pm_runtime_get_sync(dai->dev); +} + +static void skl_hda_be_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pm_runtime_mark_last_busy(dai->dev); + pm_runtime_put_autosuspend(dai->dev); +} + static struct snd_soc_dai_ops skl_pcm_dai_ops = { .startup = skl_pcm_open, .shutdown = skl_pcm_close, @@ -251,6 +420,20 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = { .hw_free = skl_pcm_hw_free, }; +static struct snd_soc_dai_ops skl_dmic_dai_ops = { + .startup = skl_hda_be_startup, + .shutdown = skl_hda_be_shutdown, +}; + +static struct snd_soc_dai_ops skl_link_dai_ops = { + .startup = skl_hda_be_startup, + .prepare = skl_link_pcm_prepare, + .hw_params = skl_link_hw_params, + .hw_free = skl_link_hw_free, + .trigger = skl_link_pcm_trigger, + .shutdown = skl_hda_be_shutdown, +}; + static struct snd_soc_dai_driver skl_platform_dai[] = { { .name = "System Pin", @@ -271,6 +454,17 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { + .name = "Reference Pin", + .ops = &skl_pcm_dai_ops, + .capture = { + .stream_name = "Reference Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ .name = "Deepbuffer Pin", .ops = &skl_pcm_dai_ops, .playback = { @@ -292,6 +486,80 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +/* BE CPU Dais */ +{ + .name = "iDisp Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "DMIC01 Pin", + .ops = &skl_dmic_dai_ops, + .capture = { + .stream_name = "DMIC01 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "DMIC23 Pin", + .ops = &skl_dmic_dai_ops, + .capture = { + .stream_name = "DMIC23 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "HD-Codec Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "HD-Codec Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "HD-Codec Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "HD-Codec-SPK Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "HD-Codec-SPK Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "HD-Codec-AMIC Pin", + .ops = &skl_link_dai_ops, + .capture = { + .stream_name = "HD-Codec-AMIC Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, }; static int skl_platform_open(struct snd_pcm_substream *substream) @@ -309,7 +577,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream) return 0; } -static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, +static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct hdac_ext_bus *ebus = get_bus_ctx(substream); @@ -383,6 +651,68 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, return 0; } +static int skl_dsp_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct hdac_ext_stream *stream; + int start; + unsigned long cookie; + struct hdac_stream *hstr; + + dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name); + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + if (start) + snd_hdac_stream_start(hdac_stream(stream), true); + else + snd_hdac_stream_stop(hdac_stream(stream)); + + if (start) + snd_hdac_stream_timecounter_init(hstr, 0); + + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + return 0; +} +static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + + if (ebus->ppcap) + return skl_dsp_trigger(substream, cmd); + else + return skl_pcm_trigger(substream, cmd); +} + /* calculate runtime delay from LPIB */ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, struct hdac_ext_stream *sstream, diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index dfbc15c..348d094 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -380,6 +380,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus) return -ENXIO; } + snd_hdac_ext_bus_parse_capabilities(ebus); + if (skl_acquire_irq(ebus, 0) < 0) return -EBUSY; @@ -453,6 +455,15 @@ static int skl_probe(struct pci_dev *pci, pci_set_drvdata(skl->pci, ebus); + /* check if dsp is there */ + if (ebus->ppcap) { + /* TODO register with dsp IPC */ + dev_dbg(bus->dev, "Register dsp\n"); + } + + if (ebus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(ebus); + /* create device for soc dmic */ err = skl_dmic_device_register(skl); if (err < 0) -- cgit v0.10.2 From 6adcafae6ed20fe380addc8e7c628e529751ade3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 26 Jun 2015 10:59:49 +0800 Subject: ASoC: add rt298 codec driver It is the initial version of ALC298 codec driver. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/include/sound/rt298.h b/include/sound/rt298.h new file mode 100644 index 0000000..7fffeaa --- /dev/null +++ b/include/sound/rt298.h @@ -0,0 +1,20 @@ +/* + * linux/sound/rt286.h -- Platform data for RT286 + * + * Copyright 2013 Realtek Microelectronics + * + * This program is free software; you can 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 __LINUX_SND_RT298_H +#define __LINUX_SND_RT298_H + +struct rt298_platform_data { + bool cbj_en; /*combo jack enable*/ + bool gpio2_en; /*GPIO2 enable*/ + bool suspend_power_off; /* power is off during suspend */ +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..76125a2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -83,6 +83,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C + select SND_SOC_RT298 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C @@ -512,12 +513,18 @@ config SND_SOC_RL6231 config SND_SOC_RL6347A tristate default y if SND_SOC_RT286=y + default y if SND_SOC_RT298=y default m if SND_SOC_RT286=m + default m if SND_SOC_RT298=m config SND_SOC_RT286 tristate depends on I2C +config SND_SOC_RT298 + tristate + depends on I2C + config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..3b58c45 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -79,6 +79,7 @@ snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt286-objs := rt286.o +snd-soc-rt298-objs := rt298.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o @@ -266,6 +267,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o +obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c new file mode 100644 index 0000000..7c4bcb6 --- /dev/null +++ b/sound/soc/codecs/rt298.c @@ -0,0 +1,1274 @@ +/* + * rt298.c -- RT298 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can 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 +#include +#include +#include +#include +#include +#include + +#include "rl6347a.h" +#include "rt298.h" + +#define RT298_VENDOR_ID 0x10ec0298 + +struct rt298_priv { + struct reg_default *index_cache; + int index_cache_size; + struct regmap *regmap; + struct snd_soc_codec *codec; + struct rt298_platform_data pdata; + struct i2c_client *i2c; + struct snd_soc_jack *jack; + struct delayed_work jack_detect_work; + int sys_clk; + int clk_id; + int is_hp_in; +}; + +static struct reg_default rt298_index_def[] = { + { 0x01, 0xaaaa }, + { 0x02, 0x8aaa }, + { 0x03, 0x0002 }, + { 0x04, 0xaf01 }, + { 0x08, 0x000d }, + { 0x09, 0xd810 }, + { 0x0a, 0x0120 }, + { 0x0b, 0x0000 }, + { 0x0d, 0x2800 }, + { 0x0f, 0x0000 }, + { 0x19, 0x0a17 }, + { 0x20, 0x0020 }, + { 0x33, 0x0208 }, + { 0x46, 0x0300 }, + { 0x49, 0x0004 }, + { 0x4f, 0x50e9 }, + { 0x50, 0x2000 }, + { 0x63, 0x2902 }, + { 0x67, 0x1111 }, + { 0x68, 0x1016 }, + { 0x69, 0x273f }, +}; +#define INDEX_CACHE_SIZE ARRAY_SIZE(rt298_index_def) + +static const struct reg_default rt298_reg[] = { + { 0x00170500, 0x00000400 }, + { 0x00220000, 0x00000031 }, + { 0x00239000, 0x0000007f }, + { 0x0023a000, 0x0000007f }, + { 0x00270500, 0x00000400 }, + { 0x00370500, 0x00000400 }, + { 0x00870500, 0x00000400 }, + { 0x00920000, 0x00000031 }, + { 0x00935000, 0x000000c3 }, + { 0x00936000, 0x000000c3 }, + { 0x00970500, 0x00000400 }, + { 0x00b37000, 0x00000097 }, + { 0x00b37200, 0x00000097 }, + { 0x00b37300, 0x00000097 }, + { 0x00c37000, 0x00000000 }, + { 0x00c37100, 0x00000080 }, + { 0x01270500, 0x00000400 }, + { 0x01370500, 0x00000400 }, + { 0x01371f00, 0x411111f0 }, + { 0x01439000, 0x00000080 }, + { 0x0143a000, 0x00000080 }, + { 0x01470700, 0x00000000 }, + { 0x01470500, 0x00000400 }, + { 0x01470c00, 0x00000000 }, + { 0x01470100, 0x00000000 }, + { 0x01837000, 0x00000000 }, + { 0x01870500, 0x00000400 }, + { 0x02050000, 0x00000000 }, + { 0x02139000, 0x00000080 }, + { 0x0213a000, 0x00000080 }, + { 0x02170100, 0x00000000 }, + { 0x02170500, 0x00000400 }, + { 0x02170700, 0x00000000 }, + { 0x02270100, 0x00000000 }, + { 0x02370100, 0x00000000 }, + { 0x01870700, 0x00000020 }, + { 0x00830000, 0x000000c3 }, + { 0x00930000, 0x000000c3 }, + { 0x01270700, 0x00000000 }, +}; + +static bool rt298_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT298_GET_HP_SENSE: + case RT298_GET_MIC1_SENSE: + case RT298_PROC_COEF: + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0): + return true; + default: + return true; + } + + +} + +static bool rt298_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT298_GET_HP_SENSE: + case RT298_GET_MIC1_SENSE: + case RT298_SET_AUDIO_POWER: + case RT298_SET_HPO_POWER: + case RT298_SET_SPK_POWER: + case RT298_SET_DMIC1_POWER: + case RT298_SPK_MUX: + case RT298_HPO_MUX: + case RT298_ADC0_MUX: + case RT298_ADC1_MUX: + case RT298_SET_MIC1: + case RT298_SET_PIN_HPO: + case RT298_SET_PIN_SPK: + case RT298_SET_PIN_DMIC1: + case RT298_SPK_EAPD: + case RT298_SET_AMP_GAIN_HPO: + case RT298_SET_DMIC2_DEFAULT: + case RT298_DACL_GAIN: + case RT298_DACR_GAIN: + case RT298_ADCL_GAIN: + case RT298_ADCR_GAIN: + case RT298_MIC_GAIN: + case RT298_SPOL_GAIN: + case RT298_SPOR_GAIN: + case RT298_HPOL_GAIN: + case RT298_HPOR_GAIN: + case RT298_F_DAC_SWITCH: + case RT298_F_RECMIX_SWITCH: + case RT298_REC_MIC_SWITCH: + case RT298_REC_I2S_SWITCH: + case RT298_REC_LINE_SWITCH: + case RT298_REC_BEEP_SWITCH: + case RT298_DAC_FORMAT: + case RT298_ADC_FORMAT: + case RT298_COEF_INDEX: + case RT298_PROC_COEF: + case RT298_SET_AMP_GAIN_ADC_IN1: + case RT298_SET_AMP_GAIN_ADC_IN2: + case RT298_SET_POWER(RT298_DAC_OUT1): + case RT298_SET_POWER(RT298_DAC_OUT2): + case RT298_SET_POWER(RT298_ADC_IN1): + case RT298_SET_POWER(RT298_ADC_IN2): + case RT298_SET_POWER(RT298_DMIC2): + case RT298_SET_POWER(RT298_MIC1): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0): + return true; + default: + return false; + } +} + +#ifdef CONFIG_PM +static void rt298_index_sync(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + int i; + + for (i = 0; i < INDEX_CACHE_SIZE; i++) { + snd_soc_write(codec, rt298->index_cache[i].reg, + rt298->index_cache[i].def); + } +} +#endif + +static int rt298_support_power_controls[] = { + RT298_DAC_OUT1, + RT298_DAC_OUT2, + RT298_ADC_IN1, + RT298_ADC_IN2, + RT298_MIC1, + RT298_DMIC1, + RT298_DMIC2, + RT298_SPK_OUT, + RT298_HP_OUT, +}; +#define RT298_POWER_REG_LEN ARRAY_SIZE(rt298_support_power_controls) + +static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) +{ + struct snd_soc_dapm_context *dapm; + unsigned int val, buf; + + *hp = false; + *mic = false; + + if (!rt298->codec) + return -EINVAL; + + dapm = snd_soc_codec_get_dapm(rt298->codec); + + if (rt298->pdata.cbj_en) { + regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + if (*hp == rt298->is_hp_in) + return -1; + rt298->is_hp_in = *hp; + if (*hp) { + /* power on HV,VERF */ + regmap_update_bits(rt298->regmap, + RT298_DC_GAIN, 0x200, 0x200); + + snd_soc_dapm_force_enable_pin(dapm, "HV"); + snd_soc_dapm_force_enable_pin(dapm, "VREF"); + /* power LDO1 */ + snd_soc_dapm_force_enable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + + regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24); + msleep(50); + + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xfcc0, 0xd400); + msleep(300); + regmap_read(rt298->regmap, RT298_CBJ_CTRL2, &val); + + if (0x0070 == (val & 0x0070)) { + *mic = true; + } else { + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xfcc0, 0xe400); + msleep(300); + regmap_read(rt298->regmap, + RT298_CBJ_CTRL2, &val); + if (0x0070 == (val & 0x0070)) + *mic = true; + else + *mic = false; + } + regmap_update_bits(rt298->regmap, + RT298_DC_GAIN, 0x200, 0x0); + + } else { + *mic = false; + regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); + } + } else { + regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + regmap_read(rt298->regmap, RT298_GET_MIC1_SENSE, &buf); + *mic = buf & 0x80000000; + } + + snd_soc_dapm_disable_pin(dapm, "HV"); + snd_soc_dapm_disable_pin(dapm, "VREF"); + if (!*hp) + snd_soc_dapm_disable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + + pr_debug("*hp = %d *mic = %d\n", *hp, *mic); + + return 0; +} + +static void rt298_jack_detect_work(struct work_struct *work) +{ + struct rt298_priv *rt298 = + container_of(work, struct rt298_priv, jack_detect_work.work); + int status = 0; + bool hp = false; + bool mic = false; + + if (rt298_jack_detect(rt298, &hp, &mic) < 0) + return; + + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); +} + +int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->jack = jack; + + /* Send an initial empty report */ + snd_soc_jack_report(rt298->jack, 0, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + return 0; +} +EXPORT_SYMBOL_GPL(rt298_mic_detect); + +static int is_mclk_mode(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + if (rt298->clk_id == RT298_SCLK_S_MCLK) + return 1; + else + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt298_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT298_DACL_GAIN, + RT298_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT298_ADCL_GAIN, + RT298_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_SINGLE_TLV("AMIC Volume", RT298_MIC_GAIN, + 0, 0x3, 0, mic_vol_tlv), + SOC_DOUBLE_R("Speaker Playback Switch", RT298_SPOL_GAIN, + RT298_SPOR_GAIN, RT298_MUTE_SFT, 1, 1), +}; + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt298_front_mix[] = { + SOC_DAPM_SINGLE("DAC Switch", RT298_F_DAC_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIX Switch", RT298_F_RECMIX_SWITCH, + RT298_MUTE_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt298_rec_mix[] = { + SOC_DAPM_SINGLE("Mic1 Switch", RT298_REC_MIC_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("I2S Switch", RT298_REC_I2S_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Line1 Switch", RT298_REC_LINE_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Beep Switch", RT298_REC_BEEP_SWITCH, + RT298_MUTE_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new spo_enable_control = + SOC_DAPM_SINGLE("Switch", RT298_SET_PIN_SPK, + RT298_SET_PIN_SFT, 1, 0); + +static const struct snd_kcontrol_new hpol_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOL_GAIN, + RT298_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpor_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOR_GAIN, + RT298_MUTE_SFT, 1, 1); + +/* ADC0 source */ +static const char * const rt298_adc_src[] = { + "Mic", "RECMIX", "Dmic" +}; + +static const int rt298_adc_values[] = { + 0, 4, 5, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt298_adc0_enum, RT298_ADC0_MUX, RT298_ADC_SEL_SFT, + RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values); + +static const struct snd_kcontrol_new rt298_adc0_mux = + SOC_DAPM_ENUM("ADC 0 source", rt298_adc0_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt298_adc1_enum, RT298_ADC1_MUX, RT298_ADC_SEL_SFT, + RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values); + +static const struct snd_kcontrol_new rt298_adc1_mux = + SOC_DAPM_ENUM("ADC 1 source", rt298_adc1_enum); + +static const char * const rt298_dac_src[] = { + "Front", "Surround" +}; +/* HP-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt298_hpo_enum, RT298_HPO_MUX, + 0, rt298_dac_src); + +static const struct snd_kcontrol_new rt298_hpo_mux = +SOC_DAPM_ENUM("HPO source", rt298_hpo_enum); + +/* SPK-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt298_spo_enum, RT298_SPK_MUX, + 0, rt298_dac_src); + +static const struct snd_kcontrol_new rt298_spo_mux = +SOC_DAPM_ENUM("SPO source", rt298_spo_enum); + +static int rt298_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, + RT298_SPK_EAPD, RT298_SET_EAPD_HIGH); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, + RT298_SPK_EAPD, RT298_SET_EAPD_LOW); + break; + + default: + return 0; + } + + return 0; +} + +static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0x20); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int nid; + + nid = (w->reg >> 20) & 0xff; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7000); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7080); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_mic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL3, 0xc000, 0x8000); + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL2, 0xc000, 0x8000); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL3, 0xc000, 0x0000); + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL2, 0xc000, 0x0000); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_vref_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0000); + mdelay(50); + break; + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, + 12, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, + 0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, + 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO2", 1, RT298_POWER_CTRL2, + 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("VREF1", 1, RT298_POWER_CTRL2, + 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LV", 2, RT298_POWER_CTRL1, + 13, 1, NULL, 0), + + + SND_SOC_DAPM_SUPPLY("MCLK MODE", RT298_PLL_CTRL1, + 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM, + 0, 0, rt298_mic1_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC1 Pin"), + SND_SOC_DAPM_INPUT("DMIC2 Pin"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("Beep"), + + /* DMIC */ + SND_SOC_DAPM_PGA_E("DMIC1", RT298_SET_POWER(RT298_DMIC1), 0, 1, + NULL, 0, rt298_set_dmic1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA("DMIC2", RT298_SET_POWER(RT298_DMIC2), 0, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0, + rt298_rec_mix, ARRAY_SIZE(rt298_rec_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT298_SET_POWER(RT298_ADC_IN1), 0, 1, + &rt298_adc0_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT298_SET_POWER(RT298_ADC_IN2), 0, 1, + &rt298_adc1_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DACs */ + SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* Output Mux */ + SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt298_spo_mux), + SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt298_hpo_mux), + + SND_SOC_DAPM_SUPPLY("HP Power", RT298_SET_PIN_HPO, + RT298_SET_PIN_SFT, 0, NULL, 0), + + /* Output Mixer */ + SND_SOC_DAPM_MIXER("Front", RT298_SET_POWER(RT298_DAC_OUT1), 0, 1, + rt298_front_mix, ARRAY_SIZE(rt298_front_mix)), + SND_SOC_DAPM_PGA("Surround", RT298_SET_POWER(RT298_DAC_OUT2), 0, 1, + NULL, 0), + + /* Output Pga */ + SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0, + &spo_enable_control, rt298_spk_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, + &hpol_enable_control), + SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, + &hpor_enable_control), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_OUTPUT("HPO Pin"), + SND_SOC_DAPM_OUTPUT("SPDIF"), +}; + +static const struct snd_soc_dapm_route rt298_dapm_routes[] = { + + {"ADC 0", NULL, "MCLK MODE", is_mclk_mode}, + {"ADC 1", NULL, "MCLK MODE", is_mclk_mode}, + {"Front", NULL, "MCLK MODE", is_mclk_mode}, + {"Surround", NULL, "MCLK MODE", is_mclk_mode}, + + {"HP Power", NULL, "LDO1"}, + {"HP Power", NULL, "LDO2"}, + {"HP Power", NULL, "LV"}, + {"HP Power", NULL, "VREF1"}, + {"HP Power", NULL, "BG_MBIAS"}, + + {"MIC1", NULL, "LDO1"}, + {"MIC1", NULL, "LDO2"}, + {"MIC1", NULL, "HV"}, + {"MIC1", NULL, "LV"}, + {"MIC1", NULL, "VREF"}, + {"MIC1", NULL, "VREF1"}, + {"MIC1", NULL, "BG_MBIAS"}, + {"MIC1", NULL, "MIC1 Input Buffer"}, + + {"SPO", NULL, "LDO1"}, + {"SPO", NULL, "LDO2"}, + {"SPO", NULL, "HV"}, + {"SPO", NULL, "LV"}, + {"SPO", NULL, "VREF"}, + {"SPO", NULL, "VREF1"}, + {"SPO", NULL, "BG_MBIAS"}, + + {"DMIC1", NULL, "DMIC1 Pin"}, + {"DMIC2", NULL, "DMIC2 Pin"}, + {"DMIC1", NULL, "DMIC Receiver"}, + {"DMIC2", NULL, "DMIC Receiver"}, + + {"RECMIX", "Beep Switch", "Beep"}, + {"RECMIX", "Line1 Switch", "LINE1"}, + {"RECMIX", "Mic1 Switch", "MIC1"}, + + {"ADC 0 Mux", "Dmic", "DMIC1"}, + {"ADC 0 Mux", "RECMIX", "RECMIX"}, + {"ADC 0 Mux", "Mic", "MIC1"}, + {"ADC 1 Mux", "Dmic", "DMIC2"}, + {"ADC 1 Mux", "RECMIX", "RECMIX"}, + {"ADC 1 Mux", "Mic", "MIC1"}, + + {"ADC 0", NULL, "ADC 0 Mux"}, + {"ADC 1", NULL, "ADC 1 Mux"}, + + {"AIF1TX", NULL, "ADC 0"}, + {"AIF2TX", NULL, "ADC 1"}, + + {"DAC 0", NULL, "AIF1RX"}, + {"DAC 1", NULL, "AIF2RX"}, + + {"Front", "DAC Switch", "DAC 0"}, + {"Front", "RECMIX Switch", "RECMIX"}, + + {"Surround", NULL, "DAC 1"}, + + {"SPK Mux", "Front", "Front"}, + {"SPK Mux", "Surround", "Surround"}, + + {"HPO Mux", "Front", "Front"}, + {"HPO Mux", "Surround", "Surround"}, + + {"SPO", "Switch", "SPK Mux"}, + {"HPO L", "Switch", "HPO Mux"}, + {"HPO R", "Switch", "HPO Mux"}, + {"HPO L", NULL, "HP Power"}, + {"HPO R", NULL, "HP Power"}, + + {"SPOL", NULL, "SPO"}, + {"SPOR", NULL, "SPO"}, + {"HPO Pin", NULL, "HPO L"}, + {"HPO Pin", NULL, "HPO R"}, +}; + +static int rt298_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 rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + int d_len_code; + + switch (params_rate(params)) { + /* bit 14 0:48K 1:44.1K */ + case 44100: + case 48000: + break; + default: + dev_err(codec->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + switch (rt298->sys_clk) { + case 12288000: + case 24576000: + if (params_rate(params) != 48000) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt298->sys_clk); + return -EINVAL; + } + break; + case 11289600: + case 22579200: + if (params_rate(params) != 44100) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt298->sys_clk); + return -EINVAL; + } + break; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(codec->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + d_len_code = 0; + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 16: + d_len_code = 0; + val |= (0x1 << 4); + break; + case 32: + d_len_code = 2; + val |= (0x4 << 4); + break; + case 20: + d_len_code = 1; + val |= (0x2 << 4); + break; + case 24: + d_len_code = 2; + val |= (0x3 << 4); + break; + case 8: + d_len_code = 3; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x0018, d_len_code << 3); + dev_dbg(codec->dev, "format val = 0x%x\n", val); + + snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x407f, val); + snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x407f, val); + + return 0; +} + +static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x800, 0x800); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x800, 0x0); + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x0); + break; + case SND_SOC_DAIFMT_LEFT_J: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x1 << 8); + break; + case SND_SOC_DAIFMT_DSP_A: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x2 << 8); + break; + case SND_SOC_DAIFMT_DSP_B: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x3 << 8); + break; + default: + return -EINVAL; + } + /* bit 15 Stream Type 0:PCM 1:Non-PCM */ + snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x8000, 0); + snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x8000, 0); + + return 0; +} + +static int rt298_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); + + if (RT298_SCLK_S_MCLK == clk_id) { + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x0100, 0x0); + snd_soc_update_bits(codec, + RT298_PLL_CTRL1, 0x20, 0x20); + } else { + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x0100, 0x0100); + snd_soc_update_bits(codec, + RT298_PLL_CTRL, 0x4, 0x4); + snd_soc_update_bits(codec, + RT298_PLL_CTRL1, 0x20, 0x0); + } + + switch (freq) { + case 19200000: + if (RT298_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x40, 0x40); + break; + case 24000000: + if (RT298_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x40, 0x0); + break; + case 12288000: + case 11289600: + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x8, 0x0); + snd_soc_update_bits(codec, + RT298_CLK_DIV, 0xfc1e, 0x0004); + break; + case 24576000: + case 22579200: + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x8, 0x8); + snd_soc_update_bits(codec, + RT298_CLK_DIV, 0xfc1e, 0x5406); + break; + default: + dev_err(codec->dev, "Unsupported system clock\n"); + return -EINVAL; + } + + rt298->sys_clk = freq; + rt298->clk_id = clk_id; + + return 0; +} + +static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + if (50 == ratio) + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x1000, 0x1000); + else + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x1000, 0x0); + + + return 0; +} + +static int rt298_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == + snd_soc_codec_get_bias_level(codec)) { + snd_soc_write(codec, + RT298_SET_AUDIO_POWER, AC_PWRST_D0); + snd_soc_update_bits(codec, 0x0d, 0x200, 0x200); + snd_soc_update_bits(codec, 0x52, 0x80, 0x0); + mdelay(20); + snd_soc_update_bits(codec, 0x0d, 0x200, 0x0); + snd_soc_update_bits(codec, 0x52, 0x80, 0x80); + } + break; + + case SND_SOC_BIAS_ON: + mdelay(30); + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0400); + + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, + RT298_SET_AUDIO_POWER, AC_PWRST_D3); + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0000); + break; + + default: + break; + } + + return 0; +} + +static irqreturn_t rt298_irq(int irq, void *data) +{ + struct rt298_priv *rt298 = data; + bool hp = false; + bool mic = false; + int ret, status = 0; + + ret = rt298_jack_detect(rt298, &hp, &mic); + + /* Clear IRQ */ + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); + + if (ret == 0) { + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + pm_wakeup_event(&rt298->i2c->dev, 300); + } + + return IRQ_HANDLED; +} + +static int rt298_probe(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->codec = codec; + + if (rt298->i2c->irq) { + regmap_update_bits(rt298->regmap, + RT298_IRQ_CTRL, 0x2, 0x2); + + INIT_DELAYED_WORK(&rt298->jack_detect_work, + rt298_jack_detect_work); + schedule_delayed_work(&rt298->jack_detect_work, + msecs_to_jiffies(1250)); + } + + return 0; +} + +static int rt298_remove(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + cancel_delayed_work_sync(&rt298->jack_detect_work); + + return 0; +} + +#ifdef CONFIG_PM +static int rt298_suspend(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->is_hp_in = -1; + regcache_cache_only(rt298->regmap, true); + regcache_mark_dirty(rt298->regmap); + + return 0; +} + +static int rt298_resume(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt298->regmap, false); + rt298_index_sync(codec); + regcache_sync(rt298->regmap); + + return 0; +} +#else +#define rt298_suspend NULL +#define rt298_resume NULL +#endif + +#define RT298_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT298_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt298_aif_dai_ops = { + .hw_params = rt298_hw_params, + .set_fmt = rt298_set_dai_fmt, + .set_sysclk = rt298_set_dai_sysclk, + .set_bclk_ratio = rt298_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt298_dai[] = { + { + .name = "rt298-aif1", + .id = RT298_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .ops = &rt298_aif_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "rt298-aif2", + .id = RT298_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .ops = &rt298_aif_dai_ops, + .symmetric_rates = 1, + }, + +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt298 = { + .probe = rt298_probe, + .remove = rt298_remove, + .suspend = rt298_suspend, + .resume = rt298_resume, + .set_bias_level = rt298_set_bias_level, + .idle_bias_off = true, + .controls = rt298_snd_controls, + .num_controls = ARRAY_SIZE(rt298_snd_controls), + .dapm_widgets = rt298_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets), + .dapm_routes = rt298_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), +}; + +static const struct regmap_config rt298_regmap = { + .reg_bits = 32, + .val_bits = 32, + .max_register = 0x02370100, + .volatile_reg = rt298_volatile_register, + .readable_reg = rt298_readable_register, + .reg_write = rl6347a_hw_write, + .reg_read = rl6347a_hw_read, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt298_reg, + .num_reg_defaults = ARRAY_SIZE(rt298_reg), +}; + +static const struct i2c_device_id rt298_i2c_id[] = { + {"rt298", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt298_i2c_id); + +static const struct acpi_device_id rt298_acpi_match[] = { + { "INT343A", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt298_acpi_match); + +static int rt298_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt298_priv *rt298; + struct device *dev = &i2c->dev; + const struct acpi_device_id *acpiid; + int i, ret; + + pr_info("%s\n", __func__); + + rt298 = devm_kzalloc(&i2c->dev, sizeof(*rt298), + GFP_KERNEL); + if (NULL == rt298) + return -ENOMEM; + + rt298->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt298_regmap); + if (IS_ERR(rt298->regmap)) { + ret = PTR_ERR(rt298->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt298->regmap, + RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); + if (ret != RT298_VENDOR_ID) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt298\n", ret); + return -ENODEV; + } + + rt298->index_cache = rt298_index_def; + rt298->index_cache_size = INDEX_CACHE_SIZE; + rt298->i2c = i2c; + i2c_set_clientdata(i2c, rt298); + + /* restore codec default */ + for (i = 0; i < INDEX_CACHE_SIZE; i++) + regmap_write(rt298->regmap, rt298->index_cache[i].reg, + rt298->index_cache[i].def); + for (i = 0; i < ARRAY_SIZE(rt298_reg); i++) + regmap_write(rt298->regmap, rt298_reg[i].reg, + rt298_reg[i].def); + + if (pdata) + rt298->pdata = *pdata; + + /* enable jack combo mode on supported devices */ + acpiid = acpi_match_device(dev->driver->acpi_match_table, dev); + if (acpiid) { + rt298->pdata = *(struct rt298_platform_data *) + acpiid->driver_data; + } + + /* VREF Charging */ + regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80); + regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860); + /* Vref2 */ + regmap_update_bits(rt298->regmap, 0x08, 0x20, 0x20); + + regmap_write(rt298->regmap, RT298_SET_AUDIO_POWER, AC_PWRST_D3); + + for (i = 0; i < RT298_POWER_REG_LEN; i++) + regmap_write(rt298->regmap, + RT298_SET_POWER(rt298_support_power_controls[i]), + AC_PWRST_D1); + + if (!rt298->pdata.cbj_en) { + regmap_write(rt298->regmap, RT298_CBJ_CTRL2, 0x0000); + regmap_write(rt298->regmap, RT298_MIC1_DET_CTRL, 0x0816); + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xf000, 0xb000); + } else { + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xf000, 0x5000); + } + + mdelay(10); + + if (!rt298->pdata.gpio2_en) + regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0x4000); + else + regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0); + + mdelay(10); + + regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000); + regmap_update_bits(rt298->regmap, + RT298_WIND_FILTER_CTRL, 0x0082, 0x0082); + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + rt298->is_hp_in = -1; + + if (rt298->i2c->irq) { + ret = request_threaded_irq(rt298->i2c->irq, NULL, rt298_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt298", rt298); + if (ret != 0) { + dev_err(&i2c->dev, + "Failed to reguest IRQ: %d\n", ret); + return ret; + } + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt298, + rt298_dai, ARRAY_SIZE(rt298_dai)); + + return ret; +} + +static int rt298_i2c_remove(struct i2c_client *i2c) +{ + struct rt298_priv *rt298 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt298); + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + + +static struct i2c_driver rt298_i2c_driver = { + .driver = { + .name = "rt298", + .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(rt298_acpi_match), + }, + .probe = rt298_i2c_probe, + .remove = rt298_i2c_remove, + .id_table = rt298_i2c_id, +}; + +module_i2c_driver(rt298_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT298 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h new file mode 100644 index 0000000..31da162 --- /dev/null +++ b/sound/soc/codecs/rt298.h @@ -0,0 +1,206 @@ +/* + * rt298.h -- RT298 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu + * + * This program is free software; you can 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 __RT298_H__ +#define __RT298_H__ + +#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) + +#define RT298_AUDIO_FUNCTION_GROUP 0x01 +#define RT298_DAC_OUT1 0x02 +#define RT298_DAC_OUT2 0x03 +#define RT298_DIG_CVT 0x06 +#define RT298_ADC_IN1 0x09 +#define RT298_ADC_IN2 0x08 +#define RT298_MIXER_IN 0x0b +#define RT298_MIXER_OUT1 0x0c +#define RT298_MIXER_OUT2 0x0d +#define RT298_DMIC1 0x12 +#define RT298_DMIC2 0x13 +#define RT298_SPK_OUT 0x14 +#define RT298_MIC1 0x18 +#define RT298_LINE1 0x1a +#define RT298_BEEP 0x1d +#define RT298_SPDIF 0x1e +#define RT298_VENDOR_REGISTERS 0x20 +#define RT298_HP_OUT 0x21 +#define RT298_MIXER_IN1 0x22 +#define RT298_MIXER_IN2 0x23 + +#define RT298_SET_PIN_SFT 6 +#define RT298_SET_PIN_ENABLE 0x40 +#define RT298_SET_PIN_DISABLE 0 +#define RT298_SET_EAPD_HIGH 0x2 +#define RT298_SET_EAPD_LOW 0 + +#define RT298_MUTE_SFT 7 + +/* Verb commands */ +#define RT298_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) +#define RT298_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) +#define RT298_SET_AUDIO_POWER RT298_SET_POWER(RT298_AUDIO_FUNCTION_GROUP) +#define RT298_SET_HPO_POWER RT298_SET_POWER(RT298_HP_OUT) +#define RT298_SET_SPK_POWER RT298_SET_POWER(RT298_SPK_OUT) +#define RT298_SET_DMIC1_POWER RT298_SET_POWER(RT298_DMIC1) +#define RT298_SPK_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_SPK_OUT, 0) +#define RT298_HPO_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_HP_OUT, 0) +#define RT298_ADC0_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN1, 0) +#define RT298_ADC1_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN2, 0) +#define RT298_SET_MIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_MIC1, 0) +#define RT298_SET_PIN_HPO\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_HP_OUT, 0) +#define RT298_SET_PIN_SPK\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPK_OUT, 0) +#define RT298_SET_PIN_DMIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_DMIC1, 0) +#define RT298_SET_PIN_SPDIF\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPDIF, 0) +#define RT298_SET_PIN_DIG_CVT\ + VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT298_DIG_CVT, 0) +#define RT298_SPK_EAPD\ + VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT298_SPK_OUT, 0) +#define RT298_SET_AMP_GAIN_HPO\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0) +#define RT298_SET_AMP_GAIN_ADC_IN1\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0) +#define RT298_SET_AMP_GAIN_ADC_IN2\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN2, 0) +#define RT298_GET_HP_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_HP_OUT, 0) +#define RT298_GET_MIC1_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_MIC1, 0) +#define RT298_SET_DMIC2_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_DMIC2, 0) +#define RT298_SET_SPDIF_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_SPDIF, 0) +#define RT298_DACL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0xa000) +#define RT298_DACR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0x9000) +#define RT298_ADCL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x6000) +#define RT298_ADCR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x5000) +#define RT298_MIC_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIC1, 0x7000) +#define RT298_SPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0xa000) +#define RT298_SPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0x9000) +#define RT298_HPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0xa000) +#define RT298_HPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0x9000) +#define RT298_F_DAC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7000) +#define RT298_F_RECMIX_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7100) +#define RT298_REC_MIC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7000) +#define RT298_REC_I2S_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7100) +#define RT298_REC_LINE_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7200) +#define RT298_REC_BEEP_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7300) +#define RT298_DAC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_DAC_OUT1, 0) +#define RT298_ADC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_ADC_IN1, 0) +#define RT298_COEF_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0) +#define RT298_PROC_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0) + +/* Index registers */ +#define RT298_A_BIAS_CTRL1 0x01 +#define RT298_A_BIAS_CTRL2 0x02 +#define RT298_POWER_CTRL1 0x03 +#define RT298_A_BIAS_CTRL3 0x04 +#define RT298_POWER_CTRL2 0x08 +#define RT298_I2S_CTRL1 0x09 +#define RT298_I2S_CTRL2 0x0a +#define RT298_CLK_DIV 0x0b +#define RT298_DC_GAIN 0x0d +#define RT298_POWER_CTRL3 0x0f +#define RT298_MIC1_DET_CTRL 0x19 +#define RT298_MISC_CTRL1 0x20 +#define RT298_IRQ_CTRL 0x33 +#define RT298_WIND_FILTER_CTRL 0x46 +#define RT298_PLL_CTRL1 0x49 +#define RT298_CBJ_CTRL1 0x4f +#define RT298_CBJ_CTRL2 0x50 +#define RT298_PLL_CTRL 0x63 +#define RT298_DEPOP_CTRL1 0x66 +#define RT298_DEPOP_CTRL2 0x67 +#define RT298_DEPOP_CTRL3 0x68 +#define RT298_DEPOP_CTRL4 0x69 + +/* SPDIF (0x06) */ +#define RT298_SPDIF_SEL_SFT 0 +#define RT298_SPDIF_SEL_PCM0 0 +#define RT298_SPDIF_SEL_PCM1 1 +#define RT298_SPDIF_SEL_SPOUT 2 +#define RT298_SPDIF_SEL_PP 3 + +/* RECMIX (0x0b) */ +#define RT298_M_REC_BEEP_SFT 0 +#define RT298_M_REC_LINE1_SFT 1 +#define RT298_M_REC_MIC1_SFT 2 +#define RT298_M_REC_I2S_SFT 3 + +/* Front (0x0c) */ +#define RT298_M_FRONT_DAC_SFT 0 +#define RT298_M_FRONT_REC_SFT 1 + +/* SPK-OUT (0x14) */ +#define RT298_M_SPK_MUX_SFT 14 +#define RT298_SPK_SEL_MASK 0x1 +#define RT298_SPK_SEL_SFT 0 +#define RT298_SPK_SEL_F 0 +#define RT298_SPK_SEL_S 1 + +/* HP-OUT (0x21) */ +#define RT298_M_HP_MUX_SFT 14 +#define RT298_HP_SEL_MASK 0x1 +#define RT298_HP_SEL_SFT 0 +#define RT298_HP_SEL_F 0 +#define RT298_HP_SEL_S 1 + +/* ADC (0x22) (0x23) */ +#define RT298_ADC_SEL_MASK 0x7 +#define RT298_ADC_SEL_SFT 0 +#define RT298_ADC_SEL_SURR 0 +#define RT298_ADC_SEL_FRONT 1 +#define RT298_ADC_SEL_DMIC 2 +#define RT298_ADC_SEL_BEEP 4 +#define RT298_ADC_SEL_LINE1 5 +#define RT298_ADC_SEL_I2S 6 +#define RT298_ADC_SEL_MIC1 7 + +#define RT298_SCLK_S_MCLK 0 +#define RT298_SCLK_S_PLL 1 + +enum { + RT298_AIF1, + RT298_AIF2, + RT298_AIFS, +}; + +int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); + +#endif /* __RT298_H__ */ + -- cgit v0.10.2 From 7a2c52b61fd71eddda3385006962630444d15b9e Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:52 +0530 Subject: ASoC: Intel: Add helper to poll register for DSP status This patch adds helper to poll register for DSP status. Signed-off-by: Subhransu S. Prusty Signed-off-by: Kp, Jeeja Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index 64e9421..cc25f4c 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "sst-dsp.h" #include "sst-dsp-priv.h" @@ -222,6 +223,48 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); +int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, + u32 target, u32 timeout, char *operation) +{ + int time, ret; + u32 reg; + bool done = false; + + /* + * we will poll for couple of ms using mdelay, if not successful + * then go to longer sleep using usleep_range + */ + + /* check if set state successful */ + for (time = 0; time < 5; time++) { + if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) { + done = true; + break; + } + mdelay(1); + } + + if (done == false) { + /* sleeping in 10ms steps so adjust timeout value */ + timeout /= 10; + + for (time = 0; time < timeout; time++) { + if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) + break; + + usleep_range(5000, 10000); + } + } + + reg = sst_dsp_shim_read_unlocked(ctx, offset); + dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, + (time < timeout) ? "successful" : "timedout"); + ret = time < timeout ? 0 : -ETIME; + + return ret; +} +EXPORT_SYMBOL_GPL(sst_dsp_register_poll); + void sst_dsp_dump(struct sst_dsp *sst) { if (sst->ops->dump) diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 96aeb25..cc3197b 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -278,6 +278,8 @@ void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); +int sst_dsp_register_poll(struct sst_dsp *dsp, u32 offset, u32 mask, + u32 expected_value, u32 timeout, char *operation); /* Debug */ void sst_dsp_dump(struct sst_dsp *sst); -- cgit v0.10.2 From d15b1ae17c79f682760483b56074e980720f52eb Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:53 +0530 Subject: ASoC: Intel: Add helper to update register bits with attr RWC For SKL IPC, we have some register bits with attribute RWC. So we need to force update them. Add helper to force update this type of registers bits. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index cc25f4c..a627236 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -197,6 +197,22 @@ int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked); +/* This is for registers bits with attribute RWC */ +void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = sst_dsp_shim_read_unlocked(sst, offset); + + old = ret; + new = (old & (~mask)) | (value & mask); + + sst_dsp_shim_write_unlocked(sst, offset, new); +} +EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); + int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, u32 mask, u32 value) { @@ -223,6 +239,18 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); +/* This is for registers bits with attribute RWC */ +void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&sst->spinlock, flags); + sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); + spin_unlock_irqrestore(&sst->spinlock, flags); +} +EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); + int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, u32 target, u32 timeout, char *operation) { diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index cc3197b..1f45f18 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -230,6 +230,8 @@ void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value); u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset); int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, u64 mask, u64 value); +void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value); /* SHIM Read / Write Unlocked for callers already holding sst lock */ void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); @@ -240,6 +242,8 @@ void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value); u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset); int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, u64 mask, u64 value); +void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value); /* Internal generic low-level SST IO functions - can be overidden */ void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); -- cgit v0.10.2 From b81fd26359f04370f3c972652302717498f8790c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:54 +0530 Subject: ASoC: Intel: Add Skylake IPC library This adds base SKL IPC library which uses common SST IPC lib. Here we add definition for IPC types, sending and receiving IPC messages from aDSP, handling interrupt, sending different types of messages etc Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d8b9943..05fde5e6e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -138,3 +138,4 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE + select SND_SOC_INTEL_SST diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 50af167..cd6c7ec 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -303,6 +303,10 @@ struct sst_dsp { /* DMA FW loading */ struct sst_dma *dma; bool fw_use_dma; + + /* SKL data */ + + u32 intr_status; }; /* Size optimised DRAM/IRAM memcpy */ diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 734d17c..18fbe64 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,3 +1,8 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o + +# Skylake IPC Support +snd-soc-skl-ipc-objs := skl-sst-ipc.o + +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c new file mode 100644 index 0000000..94be6cb --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -0,0 +1,760 @@ +/* + * skl-sst-ipc.c - Intel skl IPC Support + * + * Copyright (C) 2014-15, 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 version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include + +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" + + +#define IPC_IXC_STATUS_BITS 24 + +/* Global Message - Generic */ +#define IPC_GLB_TYPE_SHIFT 24 +#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) +#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) + +/* Global Message - Reply */ +#define IPC_GLB_REPLY_STATUS_SHIFT 24 +#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) +#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) + +#define IPC_TIMEOUT_MSECS 3000 + +#define IPC_EMPTY_LIST_SIZE 8 + +#define IPC_MSG_TARGET_SHIFT 30 +#define IPC_MSG_TARGET_MASK 0x1 +#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ + << IPC_MSG_TARGET_SHIFT) + +#define IPC_MSG_DIR_SHIFT 29 +#define IPC_MSG_DIR_MASK 0x1 +#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ + << IPC_MSG_DIR_SHIFT) +/* Global Notification Message */ +#define IPC_GLB_NOTIFY_TYPE_SHIFT 16 +#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF +#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ + & IPC_GLB_NOTIFY_TYPE_MASK) + +#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 +#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F +#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ + & IPC_GLB_NOTIFY_MSG_TYPE_MASK) + +#define IPC_GLB_NOTIFY_RSP_SHIFT 29 +#define IPC_GLB_NOTIFY_RSP_MASK 0x1 +#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ + & IPC_GLB_NOTIFY_RSP_MASK) + +/* Pipeline operations */ + +/* Create pipeline message */ +#define IPC_PPL_MEM_SIZE_SHIFT 0 +#define IPC_PPL_MEM_SIZE_MASK 0x7FF +#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ + << IPC_PPL_MEM_SIZE_SHIFT) + +#define IPC_PPL_TYPE_SHIFT 11 +#define IPC_PPL_TYPE_MASK 0x1F +#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ + << IPC_PPL_TYPE_SHIFT) + +#define IPC_INSTANCE_ID_SHIFT 16 +#define IPC_INSTANCE_ID_MASK 0xFF +#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ + << IPC_INSTANCE_ID_SHIFT) + +/* Set pipeline state message */ +#define IPC_PPL_STATE_SHIFT 0 +#define IPC_PPL_STATE_MASK 0x1F +#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ + << IPC_PPL_STATE_SHIFT) + +/* Module operations primary register */ +#define IPC_MOD_ID_SHIFT 0 +#define IPC_MOD_ID_MASK 0xFFFF +#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ + << IPC_MOD_ID_SHIFT) + +#define IPC_MOD_INSTANCE_ID_SHIFT 16 +#define IPC_MOD_INSTANCE_ID_MASK 0xFF +#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ + << IPC_MOD_INSTANCE_ID_SHIFT) + +/* Init instance message extension register */ +#define IPC_PARAM_BLOCK_SIZE_SHIFT 0 +#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF +#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ + << IPC_PARAM_BLOCK_SIZE_SHIFT) + +#define IPC_PPL_INSTANCE_ID_SHIFT 16 +#define IPC_PPL_INSTANCE_ID_MASK 0xFF +#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ + << IPC_PPL_INSTANCE_ID_SHIFT) + +#define IPC_CORE_ID_SHIFT 24 +#define IPC_CORE_ID_MASK 0x1F +#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ + << IPC_CORE_ID_SHIFT) + +/* Bind/Unbind message extension register */ +#define IPC_DST_MOD_ID_SHIFT 0 +#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ + << IPC_DST_MOD_ID_SHIFT) + +#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 +#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ + << IPC_DST_MOD_INSTANCE_ID_SHIFT) + +#define IPC_DST_QUEUE_SHIFT 24 +#define IPC_DST_QUEUE_MASK 0x7 +#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ + << IPC_DST_QUEUE_SHIFT) + +#define IPC_SRC_QUEUE_SHIFT 27 +#define IPC_SRC_QUEUE_MASK 0x7 +#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ + << IPC_SRC_QUEUE_SHIFT) + +/* Save pipeline messgae extension register */ +#define IPC_DMA_ID_SHIFT 0 +#define IPC_DMA_ID_MASK 0x1F +#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ + << IPC_DMA_ID_SHIFT) +/* Large Config message extension register */ +#define IPC_DATA_OFFSET_SZ_SHIFT 0 +#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF +#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ + << IPC_DATA_OFFSET_SZ_SHIFT) +#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ + << IPC_DATA_OFFSET_SZ_SHIFT) + +#define IPC_LARGE_PARAM_ID_SHIFT 20 +#define IPC_LARGE_PARAM_ID_MASK 0xFF +#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ + << IPC_LARGE_PARAM_ID_SHIFT) + +#define IPC_FINAL_BLOCK_SHIFT 28 +#define IPC_FINAL_BLOCK_MASK 0x1 +#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ + << IPC_FINAL_BLOCK_SHIFT) + +#define IPC_INITIAL_BLOCK_SHIFT 29 +#define IPC_INITIAL_BLOCK_MASK 0x1 +#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ + << IPC_INITIAL_BLOCK_SHIFT) +#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ + << IPC_INITIAL_BLOCK_SHIFT) + +enum skl_ipc_msg_target { + IPC_FW_GEN_MSG = 0, + IPC_MOD_MSG = 1 +}; + +enum skl_ipc_msg_direction { + IPC_MSG_REQUEST = 0, + IPC_MSG_REPLY = 1 +}; + +/* Global Message Types */ +enum skl_ipc_glb_type { + IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ + IPC_GLB_LOAD_MULTIPLE_MODS = 15, + IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, + IPC_GLB_CREATE_PPL = 17, + IPC_GLB_DELETE_PPL = 18, + IPC_GLB_SET_PPL_STATE = 19, + IPC_GLB_GET_PPL_STATE = 20, + IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, + IPC_GLB_SAVE_PPL = 22, + IPC_GLB_RESTORE_PPL = 23, + IPC_GLB_NOTIFY = 26, + IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ +}; + +enum skl_ipc_glb_reply { + IPC_GLB_REPLY_SUCCESS = 0, + + IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, + IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, + + IPC_GLB_REPLY_BUSY = 3, + IPC_GLB_REPLY_PENDING = 4, + IPC_GLB_REPLY_FAILURE = 5, + IPC_GLB_REPLY_INVALID_REQUEST = 6, + + IPC_GLB_REPLY_OUT_OF_MEMORY = 7, + IPC_GLB_REPLY_OUT_OF_MIPS = 8, + + IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, + IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, + + IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, + IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, + IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, + + IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, + IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, + + IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, + IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, + IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, + IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, + + IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, + IPC_GLB_REPLY_PPL_NOT_EXIST = 161, + IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, + IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, + + IPC_MAX_STATUS = ((1<tx_data, tx_data, tx_size); +} + +static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) +{ + u32 hipci; + + hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); + return (hipci & SKL_ADSP_REG_HIPCI_BUSY); +} + +/* Lock to be held by caller */ +static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) +{ + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + + if (msg->tx_size) + sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, + header->extension); + sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, + header->primary | SKL_ADSP_REG_HIPCI_BUSY); +} + +static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, + u64 ipc_header) +{ + struct ipc_message *msg = NULL; + struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); + + if (list_empty(&ipc->rx_list)) { + dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", + header->primary); + goto out; + } + + msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); + +out: + return msg; + +} + +static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, + struct skl_ipc_header header) +{ + struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + + if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { + + case IPC_GLB_NOTIFY_UNDERRUN: + dev_err(ipc->dev, "FW Underrun %x\n", header.primary); + break; + + case IPC_GLB_NOTIFY_RESOURCE_EVENT: + dev_err(ipc->dev, "MCPS Budget Violation: %x\n", + header.primary); + break; + + case IPC_GLB_NOTIFY_FW_READY: + skl->boot_complete = true; + wake_up(&skl->boot_wait); + break; + + default: + dev_err(ipc->dev, "ipc: Unhandled error msg=%x", + header.primary); + break; + } + } + + return 0; +} + +static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, + struct skl_ipc_header header) +{ + struct ipc_message *msg; + u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; + u64 *ipc_header = (u64 *)(&header); + + msg = skl_ipc_reply_get_msg(ipc, *ipc_header); + if (msg == NULL) { + dev_dbg(ipc->dev, "ipc: rx list is empty\n"); + return; + } + + /* first process the header */ + switch (reply) { + case IPC_GLB_REPLY_SUCCESS: + dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); + break; + + case IPC_GLB_REPLY_OUT_OF_MEMORY: + dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); + msg->errno = -ENOMEM; + break; + + case IPC_GLB_REPLY_BUSY: + dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); + msg->errno = -EBUSY; + break; + + default: + dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); + msg->errno = -EINVAL; + break; + } + + list_del(&msg->list); + sst_ipc_tx_msg_reply_complete(ipc, msg); +} + +irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) +{ + struct sst_dsp *dsp = context; + struct skl_sst *skl = sst_dsp_get_thread_context(dsp); + struct sst_generic_ipc *ipc = &skl->ipc; + struct skl_ipc_header header = {0}; + u32 hipcie, hipct, hipcte; + int ipc_irq = 0; + + /* Here we handle IPC interrupts only */ + if (!(dsp->intr_status & SKL_ADSPIS_IPC)) + return IRQ_NONE; + + hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); + hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); + + /* reply message from DSP */ + if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { + sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, 0); + + /* clear DONE bit - tell DSP we have completed the operation */ + sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, + SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); + + ipc_irq = 1; + + /* unmask Done interrupt */ + sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); + } + + /* New message from DSP */ + if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { + hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); + header.primary = hipct; + header.extension = hipcte; + dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", + header.primary); + dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", + header.extension); + + if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { + /* Handle Immediate reply from DSP Core */ + skl_ipc_process_reply(ipc, header); + } else { + dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); + skl_ipc_process_notification(ipc, header); + } + /* clear busy interrupt */ + sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, + SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); + ipc_irq = 1; + } + + if (ipc_irq == 0) + return IRQ_NONE; + + skl_ipc_int_enable(dsp); + + /* continue to send any remaining messages... */ + queue_kthread_work(&ipc->kworker, &ipc->kwork); + + return IRQ_HANDLED; +} + +void skl_ipc_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); +} + +void skl_ipc_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_IPC, 0); +} + +void skl_ipc_op_int_enable(struct sst_dsp *ctx) +{ + /* enable IPC DONE interrupt */ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); + + /* Enable IPC BUSY interrupt */ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); +} + +bool skl_ipc_int_status(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read_unlocked(ctx, + SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; +} + +int skl_ipc_init(struct device *dev, struct skl_sst *skl) +{ + struct sst_generic_ipc *ipc; + int err; + + ipc = &skl->ipc; + ipc->dsp = skl->dsp; + ipc->dev = dev; + + ipc->tx_data_max_size = SKL_ADSP_W1_SZ; + ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; + + err = sst_ipc_init(ipc); + if (err) + return err; + + ipc->ops.tx_msg = skl_ipc_tx_msg; + ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; + ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; + + return 0; +} + +void skl_ipc_free(struct sst_generic_ipc *ipc) +{ + /* Disable IPC DONE interrupt */ + sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, 0); + + /* Disable IPC BUSY interrupt */ + sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_BUSY, 0); +} + +int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, + u16 ppl_mem_size, u8 ppl_type, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + header.primary |= IPC_PPL_TYPE(ppl_type); + header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); + +int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); + +int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, + u8 instance_id, enum skl_ipc_pipeline_state state) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); + header.primary |= IPC_INSTANCE_ID(instance_id); + header.primary |= IPC_PPL_STATE(state); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); + return ret; + } + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); + +int +skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + header.extension = IPC_DMA_ID(dma_id); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); + +int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); + +int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, + u16 module_id, struct skl_ipc_dxstate_info *dx) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); + header.primary |= IPC_MOD_INSTANCE_ID(instance_id); + header.primary |= IPC_MOD_ID(module_id); + + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, + header.primary, header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, + dx, sizeof(dx), NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_dx); + +int skl_ipc_init_instance(struct sst_generic_ipc *ipc, + struct skl_ipc_init_instance_msg *msg, void *param_data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + u32 *buffer = (u32 *)param_data; + /* param_block_size must be in dwords */ + u16 param_block_size = msg->param_data_size / sizeof(u32); + + print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, + 16, 4, buffer, param_block_size, false); + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_CORE_ID(msg->core_id); + header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); + header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); + + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, + header.primary, header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, + msg->param_data_size, NULL, 0); + + if (ret < 0) { + dev_err(ipc->dev, "ipc: init instance failed\n"); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_init_instance); + +int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, + struct skl_ipc_bind_unbind_msg *msg) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(bind_unbind); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DST_MOD_ID(msg->dst_module_id); + header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); + header.extension |= IPC_DST_QUEUE(msg->dst_queue); + header.extension |= IPC_SRC_QUEUE(msg->src_queue); + + dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, + header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: bind/unbind faileden"); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); + +int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret = 0; + size_t sz_remaining, tx_size, data_offset; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); + header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); + header.extension |= IPC_FINAL_BLOCK(0); + header.extension |= IPC_INITIAL_BLOCK(1); + + sz_remaining = msg->param_data_size; + data_offset = 0; + while (sz_remaining != 0) { + tx_size = sz_remaining > SKL_ADSP_W1_SZ + ? SKL_ADSP_W1_SZ : sz_remaining; + if (tx_size == sz_remaining) + header.extension |= IPC_FINAL_BLOCK(1); + + dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, + header.primary, header.extension); + dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", + (unsigned)data_offset, (unsigned)tx_size); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, + ((char *)param) + data_offset, + tx_size, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, + "ipc: set large config fail, err: %d\n", ret); + return ret; + } + sz_remaining -= tx_size; + data_offset = msg->param_data_size - sz_remaining; + + /* clear the fields */ + header.extension &= IPC_INITIAL_BLOCK_CLEAR; + header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; + /* fill the fields */ + header.extension |= IPC_INITIAL_BLOCK(0); + header.extension |= IPC_DATA_OFFSET_SZ(data_offset); + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h new file mode 100644 index 0000000..9f5f672 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -0,0 +1,125 @@ +/* + * Intel SKL IPC Support + * + * Copyright (C) 2014-15, 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 version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __SKL_IPC_H +#define __SKL_IPC_H + +#include +#include +#include "../common/sst-ipc.h" + +struct sst_dsp; +struct skl_sst; +struct sst_generic_ipc; + +enum skl_ipc_pipeline_state { + PPL_INVALID_STATE = 0, + PPL_UNINITIALIZED = 1, + PPL_RESET = 2, + PPL_PAUSED = 3, + PPL_RUNNING = 4, + PPL_ERROR_STOP = 5, + PPL_SAVED = 6, + PPL_RESTORED = 7 +}; + +struct skl_ipc_dxstate_info { + u32 core_mask; + u32 dx_mask; +}; + +struct skl_ipc_header { + u32 primary; + u32 extension; +}; + +struct skl_sst { + struct device *dev; + struct sst_dsp *dsp; + + /* boot */ + wait_queue_head_t boot_wait; + bool boot_complete; + + /* IPC messaging */ + struct sst_generic_ipc ipc; +}; + +struct skl_ipc_init_instance_msg { + u32 module_id; + u32 instance_id; + u16 param_data_size; + u8 ppl_instance_id; + u8 core_id; +}; + +struct skl_ipc_bind_unbind_msg { + u32 module_id; + u32 instance_id; + u32 dst_module_id; + u32 dst_instance_id; + u8 src_queue; + u8 dst_queue; + bool bind; +}; + +struct skl_ipc_large_config_msg { + u32 module_id; + u32 instance_id; + u32 large_param_id; + u32 param_data_size; +}; + +#define SKL_IPC_BOOT_MSECS 3000 + +#define SKL_IPC_D3_MASK 0 +#define SKL_IPC_D0_MASK 3 + +irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); + +int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, + u16 ppl_mem_size, u8 ppl_type, u8 instance_id); + +int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); + +int skl_ipc_set_pipeline_state(struct sst_generic_ipc *sst_ipc, + u8 instance_id, enum skl_ipc_pipeline_state state); + +int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, + u8 instance_id, int dma_id); + +int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); + +int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc, + struct skl_ipc_init_instance_msg *msg, void *param_data); + +int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, + struct skl_ipc_bind_unbind_msg *msg); + +int skl_ipc_set_dx(struct sst_generic_ipc *ipc, + u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); + +int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param); + +void skl_ipc_int_enable(struct sst_dsp *dsp); +void skl_ipc_op_int_enable(struct sst_dsp *ctx); +void skl_ipc_int_disable(struct sst_dsp *dsp); + +bool skl_ipc_int_status(struct sst_dsp *dsp); +void skl_ipc_free(struct sst_generic_ipc *ipc); +int skl_ipc_init(struct device *dev, struct skl_sst *skl); + +#endif /* __SKL_IPC_H */ -- cgit v0.10.2 From e973e31a02c32fc830986e62f82e69934134f5ce Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:55 +0530 Subject: ASoC: Intel: Add DSP init and boot up functionality for SKL This patch adds code to enable, disable and boot DSP core. Also provide some helpers to reset and power up/down the core. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index cd6c7ec..dd79648 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -22,6 +22,8 @@ #include #include +#include "../skylake/skl-sst-dsp.h" + struct sst_mem_block; struct sst_module; struct sst_fw; @@ -306,6 +308,8 @@ struct sst_dsp { /* SKL data */ + struct skl_dsp_fw_ops fw_ops; + int sst_state; u32 intr_status; }; diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 18fbe64..10c1319 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c new file mode 100644 index 0000000..313ca7c --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -0,0 +1,337 @@ +/* + * skl-sst-dsp.c - SKL SST library generic function + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include + +#include "../common/sst-dsp.h" +#include "../common/sst-ipc.h" +#include "../common/sst-dsp-priv.h" +#include "skl-sst-ipc.h" + +/* various timeout values */ +#define SKL_DSP_PU_TO 50 +#define SKL_DSP_PD_TO 50 +#define SKL_DSP_RESET_TO 50 + +void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) +{ + mutex_lock(&ctx->mutex); + ctx->sst_state = state; + mutex_unlock(&ctx->mutex); +} + +static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) +{ + int ret; + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), + SKL_DSP_RESET_TO, + "Set reset"); + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { + dev_err(ctx->dev, "Set reset state failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) +{ + int ret; + + dev_dbg(ctx->dev, "In %s\n", __func__); + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, 0); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, + 0, + SKL_DSP_RESET_TO, + "Unset reset"); + + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { + dev_err(ctx->dev, "Unset reset state failed\n"); + ret = -EIO; + } + + return ret; +} + +static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) +{ + int val; + bool is_enable; + + val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); + + is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && + (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && + !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && + !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); + + dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); + return is_enable; +} + +static int skl_dsp_reset_core(struct sst_dsp *ctx) +{ + /* stall core */ + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); + + /* set reset state */ + return skl_dsp_core_set_reset_state(ctx); +} + +static int skl_dsp_start_core(struct sst_dsp *ctx) +{ + int ret; + + /* unset reset state */ + ret = skl_dsp_core_unset_reset_state(ctx); + if (ret < 0) { + dev_dbg(ctx->dev, "dsp unset reset fails\n"); + return ret; + } + + /* run core */ + dev_dbg(ctx->dev, "run core...\n"); + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); + + if (!is_skl_dsp_core_enable(ctx)) { + skl_dsp_reset_core(ctx); + dev_err(ctx->dev, "DSP core enable failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_power_up(struct sst_dsp *ctx) +{ + int ret; + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CPA_MASK, + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), + SKL_DSP_PU_TO, + "Power up"); + + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) != + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { + dev_err(ctx->dev, "DSP core power up failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_power_down(struct sst_dsp *ctx) +{ + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, 0); + + /* poll with timeout to check if operation successful */ + return sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, + 0, + SKL_DSP_PD_TO, + "Power down"); +} + +static int skl_dsp_enable_core(struct sst_dsp *ctx) +{ + int ret; + + /* power up */ + ret = skl_dsp_core_power_up(ctx); + if (ret < 0) { + dev_dbg(ctx->dev, "dsp core power up failed\n"); + return ret; + } + + return skl_dsp_start_core(ctx); +} + +int skl_dsp_disable_core(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_dsp_reset_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp core reset failed\n"); + return ret; + } + + /* power down core*/ + ret = skl_dsp_core_power_down(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp core power down failed\n"); + return ret; + } + + if (is_skl_dsp_core_enable(ctx)) { + dev_err(ctx->dev, "DSP core disable failed\n"); + ret = -EIO; + } + + return ret; +} + +int skl_dsp_boot(struct sst_dsp *ctx) +{ + int ret; + + if (is_skl_dsp_core_enable(ctx)) { + dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); + ret = skl_dsp_reset_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp reset failed\n"); + return ret; + } + + ret = skl_dsp_start_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp start failed\n"); + return ret; + } + } else { + dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); + ret = skl_dsp_disable_core(ctx); + + if (ret < 0) { + dev_err(ctx->dev, "dsp disable core failes\n"); + return ret; + } + ret = skl_dsp_enable_core(ctx); + } + + return ret; +} + +irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) +{ + struct sst_dsp *ctx = dev_id; + u32 val; + irqreturn_t result = IRQ_NONE; + + spin_lock(&ctx->spinlock); + + val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); + ctx->intr_status = val; + + if (val & SKL_ADSPIS_IPC) { + skl_ipc_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + + spin_unlock(&ctx->spinlock); + + return result; +} + +int skl_dsp_wake(struct sst_dsp *ctx) +{ + return ctx->fw_ops.set_state_D0(ctx); +} +EXPORT_SYMBOL_GPL(skl_dsp_wake); + +int skl_dsp_sleep(struct sst_dsp *ctx) +{ + return ctx->fw_ops.set_state_D3(ctx); +} +EXPORT_SYMBOL_GPL(skl_dsp_sleep); + +struct sst_dsp *skl_dsp_ctx_init(struct device *dev, + struct sst_dsp_device *sst_dev, int irq) +{ + int ret; + struct sst_dsp *sst; + + sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); + if (sst == NULL) + return NULL; + + spin_lock_init(&sst->spinlock); + mutex_init(&sst->mutex); + sst->dev = dev; + sst->sst_dev = sst_dev; + sst->irq = irq; + sst->ops = sst_dev->ops; + sst->thread_context = sst_dev->thread_context; + + /* Initialise SST Audio DSP */ + if (sst->ops->init) { + ret = sst->ops->init(sst, NULL); + if (ret < 0) + return NULL; + } + + /* Register the ISR */ + ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, + sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); + if (ret) { + dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", + sst->irq); + return NULL; + } + + return sst; +} + +void skl_dsp_free(struct sst_dsp *dsp) +{ + skl_ipc_int_disable(dsp); + + free_irq(dsp->irq, dsp); + skl_dsp_disable_core(dsp); +} +EXPORT_SYMBOL_GPL(skl_dsp_free); + +bool is_skl_dsp_running(struct sst_dsp *ctx) +{ + return (ctx->sst_state == SKL_DSP_RUNNING); +} +EXPORT_SYMBOL_GPL(is_skl_dsp_running); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 2ac120c..cdfca9b 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +struct sst_dsp_device; + /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 #define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) @@ -59,4 +61,59 @@ #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1 +/* ADSPCS - Audio DSP Control & Status */ +#define SKL_DSP_CORES 1 +#define SKL_DSP_CORE0_MASK 1 +#define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1) + +/* Core Reset - asserted high */ +#define SKL_ADSPCS_CRST_SHIFT 0 +#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT) +#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK) + +/* Core run/stall - when set to '1' core is stalled */ +#define SKL_ADSPCS_CSTALL_SHIFT 8 +#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \ + SKL_ADSPCS_CSTALL_SHIFT) +#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \ + SKL_ADSPCS_CSTALL_MASK) + +/* Set Power Active - when set to '1' turn cores on */ +#define SKL_ADSPCS_SPA_SHIFT 16 +#define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT) +#define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK) + +/* Current Power Active - power status of cores, set by hardware */ +#define SKL_ADSPCS_CPA_SHIFT 24 +#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT) +#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK) + +#define SST_DSP_POWER_D0 0x0 /* full On */ +#define SST_DSP_POWER_D3 0x3 /* Off */ + +enum skl_dsp_states { + SKL_DSP_RUNNING = 1, + SKL_DSP_RESET, +}; + +struct skl_dsp_fw_ops { + int (*load_fw)(struct sst_dsp *ctx); + /* FW module parser/loader */ + int (*parse_fw)(struct sst_dsp *ctx); + int (*set_state_D0)(struct sst_dsp *ctx); + int (*set_state_D3)(struct sst_dsp *ctx); +}; + +void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); +struct sst_dsp *skl_dsp_ctx_init(struct device *dev, + struct sst_dsp_device *sst_dev, int irq); +int skl_dsp_disable_core(struct sst_dsp *ctx); +bool is_skl_dsp_running(struct sst_dsp *ctx); +irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); +int skl_dsp_wake(struct sst_dsp *ctx); +int skl_dsp_sleep(struct sst_dsp *ctx); +void skl_dsp_free(struct sst_dsp *dsp); + +int skl_dsp_boot(struct sst_dsp *ctx); + #endif /*__SKL_SST_DSP_H__*/ -- cgit v0.10.2 From 7ff0589c7bff4ca31b255ac2028f633f14047762 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:22 +0000 Subject: regmap: add force_write option on _regmap_update_bits() Sometimes we want to write data even though it doesn't change value. Then, force_write option on _regmap_update_bits() helps this purpose. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04..69ec411 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -34,7 +34,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change); + bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val); @@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg); + &page_chg, false); map->work_buf = orig_work_buf; @@ -2327,7 +2327,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read); static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change) + bool *change, bool force_write) { int ret; unsigned int tmp, orig; @@ -2339,7 +2339,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, tmp = orig & ~mask; tmp |= val & mask; - if (tmp != orig) { + if (force_write || (tmp != orig)) { ret = _regmap_write(map, reg, tmp); if (change) *change = true; @@ -2367,7 +2367,7 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->unlock(map->lock_arg); return ret; @@ -2398,7 +2398,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->async = false; @@ -2427,7 +2427,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->unlock(map->lock_arg); return ret; } @@ -2460,7 +2460,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->async = false; -- cgit v0.10.2 From fd4b7286ccc469bf5dde22db6b8fcc455c3c4a66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:39 +0000 Subject: regmap: add regmap_write_bits() regmap_write_bits() is similar to regmap_update_bits(), but regmap_write_bits() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 69ec411..d93bb9a 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2375,6 +2375,29 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_update_bits); /** + * regmap_write_bits: Perform a read/modify/write cycle on the register map + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * Returns zero for success, a negative number on error. + */ +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + map->lock(map->lock_arg); + ret = _regmap_update_bits(map, reg, mask, val, NULL, true); + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_bits); + +/** * regmap_update_bits_async: Perform a read/modify/write cycle on the register * map asynchronously * diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea..e4b9ad4 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -424,6 +424,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, @@ -645,6 +647,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) -- cgit v0.10.2 From e874e6c7edc43436f73cf84157d9221f8b807c36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:55 +0000 Subject: regmap: add regmap_fields_force_write() regmap_fields_force_write() is similar to regmap_fields_write(), but regmap_fields_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d93bb9a..dd63bcb 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_write); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_write_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_force_write); + /** * regmap_fields_update_bits(): Perform a read/modify/write cycle * on the register field diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e4b9ad4..519c962 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -505,6 +505,8 @@ int regmap_field_update_bits(struct regmap_field *field, int regmap_fields_write(struct regmap_field *field, unsigned int id, unsigned int val); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val); int regmap_fields_read(struct regmap_field *field, unsigned int id, unsigned int *val); int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, -- cgit v0.10.2 From 7b47ab47b3938e2274834dbde7915df98fc74368 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:53:11 +0000 Subject: ASoC: rsnd: gen: add rsnd_force_write() rsnd_force_write() is similar to rsnd_write(), but rsnd_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 8c7dc51..48f704b 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -103,6 +103,22 @@ void rsnd_write(struct rsnd_priv *priv, regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); } +void rsnd_force_write(struct rsnd_priv *priv, + struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + + dev_dbg(dev, "w %s[%d] - %4d : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); + + regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); +} + void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data) { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 09fcc54..f729646 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -157,12 +157,16 @@ struct rsnd_dai_stream; rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) #define rsnd_mod_write(m, r, d) \ rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) +#define rsnd_mod_force_write(m, r, d) \ + rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) #define rsnd_mod_bset(m, r, s, d) \ rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); +void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data); void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -- cgit v0.10.2 From d90c6cc242045115c5c4973114cc93e1c20e2ea8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 10 Jul 2015 14:37:25 +0100 Subject: ASoC: arizona: Fix error path in codec probe If we fail to add some DSPs or fail to add the controls we should call wm_adsp2_codec_remove for all the cores we have already added. This patch fixes this up on the wm5102 and wm5110. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 6ddee99..64637d1 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1879,7 +1879,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) ret = snd_soc_add_codec_controls(codec, arizona_adsp2_rate_controls, 1); if (ret) - return ret; + goto err_adsp2_codec_probe; arizona_init_spk(codec); arizona_init_gpio(codec); @@ -1889,6 +1889,11 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) priv->core.arizona->dapm = dapm; return 0; + +err_adsp2_codec_probe: + wm_adsp2_codec_remove(&priv->core.adsp[0], codec); + + return ret; } static int wm5102_codec_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 05aa5bc..2d1168c 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1607,18 +1607,24 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) - return ret; + goto err_adsp2_codec_probe; } ret = snd_soc_add_codec_controls(codec, arizona_adsp2_rate_controls, WM5110_NUM_ADSP); if (ret) - return ret; + goto err_adsp2_codec_probe; snd_soc_dapm_disable_pin(dapm, "HAPTICS"); return 0; + +err_adsp2_codec_probe: + for (--i; i >= 0; --i) + wm_adsp2_codec_remove(&priv->core.adsp[i], codec); + + return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) -- cgit v0.10.2 From 32a726b2e089ec1851965290a610c4ae9cab3303 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:11 +0200 Subject: ASoC: sti-sas: Add sti platform codec Codec part of the sti platform that supports codec IPs. This first version does not support HDMI, but only DAC and SPDIF out. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..46802ef 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -102,6 +102,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_STI_SAS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C @@ -610,6 +611,10 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate +config SND_SOC_STI_SAS + tristate "codec Audio support for STI SAS codec" + depends on SND_SOC_STI + config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..7b4ce1b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta32x-objs := sta32x.o snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o +snd-soc-sti-sas-objs := sti-sas.o snd-soc-tas5086-objs := tas5086.o snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o @@ -289,6 +290,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c new file mode 100644 index 0000000..32db2c2 --- /dev/null +++ b/sound/soc/codecs/sti-sas.c @@ -0,0 +1,627 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* chipID supported */ +#define CHIPID_STIH416 0 +#define CHIPID_STIH407 1 + +/* DAC definitions */ + +/* stih416 DAC registers */ +/* sysconf 2517: Audio-DAC-Control */ +#define STIH416_AUDIO_DAC_CTRL 0x00000814 +/* sysconf 2519: Audio-Gue-Control */ +#define STIH416_AUDIO_GLUE_CTRL 0x0000081C + +#define STIH416_DAC_NOT_STANDBY 0x3 +#define STIH416_DAC_SOFTMUTE 0x4 +#define STIH416_DAC_ANA_NOT_PWR 0x5 +#define STIH416_DAC_NOT_PNDBG 0x6 + +#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) +#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) +#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) +#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) + +/* stih407 DAC registers */ +/* sysconf 5041: Audio-Gue-Control */ +#define STIH407_AUDIO_GLUE_CTRL 0x000000A4 +/* sysconf 5042: Audio-DAC-Control */ +#define STIH407_AUDIO_DAC_CTRL 0x000000A8 + +/* DAC definitions */ +#define STIH407_DAC_SOFTMUTE 0x0 +#define STIH407_DAC_STANDBY_ANA 0x1 +#define STIH407_DAC_STANDBY 0x2 + +#define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE) +#define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA) +#define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY) + +/* SPDIF definitions */ +#define SPDIF_BIPHASE_ENABLE 0x6 +#define SPDIF_BIPHASE_IDLE 0x7 + +#define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE) +#define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE) + +enum { + STI_SAS_DAI_SPDIF_OUT, + STI_SAS_DAI_ANALOG_OUT, +}; + +static const struct reg_default stih416_sas_reg_defaults[] = { + { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, + { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, +}; + +static const struct reg_default stih407_sas_reg_defaults[] = { + { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, + { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, +}; + +struct sti_dac_audio { + struct regmap *regmap; + struct regmap *virt_regmap; + struct regmap_field **field; + struct reset_control *rst; + int mclk; +}; + +struct sti_spdif_audio { + struct regmap *regmap; + struct regmap_field **field; + int mclk; +}; + +/* device data structure */ +struct sti_sas_dev_data { + const int chipid; /* IC version */ + const struct regmap_config *regmap; + const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ + const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ + const int num_dapm_widgets; /* dapms declaration */ + const struct snd_soc_dapm_route *dapm_routes; /* route declaration */ + const int num_dapm_routes; /* route declaration */ +}; + +/* driver data structure */ +struct sti_sas_data { + struct device *dev; + const struct sti_sas_dev_data *dev_data; + struct sti_dac_audio dac; + struct sti_spdif_audio spdif; +}; + +/* Read a register from the sysconf reg bank */ +static int sti_sas_read_reg(void *context, unsigned int reg, + unsigned int *value) +{ + struct sti_sas_data *drvdata = context; + int status; + u32 val; + + status = regmap_read(drvdata->dac.regmap, reg, &val); + *value = (unsigned int)val; + + return status; +} + +/* Read a register from the sysconf reg bank */ +static int sti_sas_write_reg(void *context, unsigned int reg, + unsigned int value) +{ + struct sti_sas_data *drvdata = context; + int status; + + status = regmap_write(drvdata->dac.regmap, reg, value); + + return status; +} + +static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, + struct sti_sas_data *data) +{ + int ret; + /* + * DAC and SPDIF are activated by default + * put them in IDLE to save power + */ + + /* Initialise bi-phase formatter to disabled */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, 0); + + if (!ret) + /* Initialise bi-phase formatter idle value to 0 */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_IDLE_MASK, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to update SPDIF registers"); + return ret; + } + + /* Init DAC configuration */ + switch (data->dev_data->chipid) { + case CHIPID_STIH407: + /* init configuration */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_MASK, + STIH407_DAC_STANDBY_MASK); + + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA_MASK, + STIH407_DAC_STANDBY_ANA_MASK); + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); + break; + case CHIPID_STIH416: + ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_STANDBY_MASK, 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_ANA_NOT_PWR, 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_PNDBG_MASK, + 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, + STIH416_DAC_SOFTMUTE_MASK); + break; + default: + return -EINVAL; + } + + if (ret < 0) { + dev_err(codec->dev, "Failed to update DAC registers"); + return ret; + } + + return ret; +} + +/* + * DAC + */ +static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /* Sanity check only */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(dai->codec->dev, + "%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + return 0; +} + +static int stih416_dac_probe(struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + struct sti_dac_audio *dac = &drvdata->dac; + + /* Get reset control */ + dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); + if (IS_ERR(dac->rst)) { + dev_err(dai->codec->dev, + "%s: ERROR: DAC reset control not defined (%d)!\n", + __func__, (int)dac->rst); + dac->rst = NULL; + return -EFAULT; + } + /* Put the DAC into reset */ + reset_control_assert(dac->rst); + + return 0; +} + +const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { + SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_STANDBY, 0), + SND_SOC_DAPM_OUTPUT("DAC Output"), +}; + +const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { + SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA, 1, NULL, 0), + SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY, 1), + SND_SOC_DAPM_OUTPUT("DAC Output"), +}; + +const struct snd_soc_dapm_route stih416_sas_route[] = { + {"DAC Output", NULL, "DAC bandgap"}, + {"DAC Output", NULL, "DAC standby ana"}, + {"DAC standby ana", NULL, "DAC standby"}, +}; + +const struct snd_soc_dapm_route stih407_sas_route[] = { + {"DAC Output", NULL, "DAC standby ana"}, + {"DAC standby ana", NULL, "DAC standby"}, +}; + +static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, + STIH416_DAC_SOFTMUTE_MASK); + } else { + return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, 0); + } +} + +static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); + } else { + return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + 0); + } +} + +/* + * SPDIF + */ +static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(dai->codec->dev, + "%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + return 0; +} + +/* + * sti_sas_spdif_trigger: + * Trigger function is used to ensure that BiPhase Formater is disabled + * before CPU dai is stopped. + * This is mandatory to avoid that BPF is stalled + */ +static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, + SPDIF_BIPHASE_ENABLE_MASK); + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, + 0); + default: + return -EINVAL; + } +} + +static bool sti_sas_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg == STIH407_AUDIO_GLUE_CTRL) + return true; + + return false; +} + +/* + * CODEC DAIS + */ + +/* + * sti_sas_set_sysclk: + * get MCLK input frequency to check that MCLK-FS ratio is coherent + */ +static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + + if (dir == SND_SOC_CLOCK_OUT) + return 0; + + if (clk_id != 0) + return -EINVAL; + + switch (dai->id) { + case STI_SAS_DAI_SPDIF_OUT: + drvdata->spdif.mclk = freq; + break; + + case STI_SAS_DAI_ANALOG_OUT: + drvdata->dac.mclk = freq; + break; + } + + return 0; +} + +static int sti_sas_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + + switch (dai->id) { + case STI_SAS_DAI_SPDIF_OUT: + if ((drvdata->spdif.mclk / runtime->rate) != 128) { + dev_err(codec->dev, "unexpected mclk-fs ratio"); + return -EINVAL; + } + break; + case STI_SAS_DAI_ANALOG_OUT: + if ((drvdata->dac.mclk / runtime->rate) != 256) { + dev_err(codec->dev, "unexpected mclk-fs ratio"); + return -EINVAL; + } + break; + } + + return 0; +} + +const struct snd_soc_dai_ops stih416_dac_ops = { + .set_fmt = sti_sas_dac_set_fmt, + .mute_stream = stih416_sas_dac_mute, + .prepare = sti_sas_prepare, + .set_sysclk = sti_sas_set_sysclk, +}; + +const struct snd_soc_dai_ops stih407_dac_ops = { + .set_fmt = sti_sas_dac_set_fmt, + .mute_stream = stih407_sas_dac_mute, + .prepare = sti_sas_prepare, + .set_sysclk = sti_sas_set_sysclk, +}; + +const struct regmap_config stih407_sas_regmap = { + .reg_bits = 32, + .val_bits = 32, + + .max_register = STIH407_AUDIO_DAC_CTRL, + .reg_defaults = stih407_sas_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), + .volatile_reg = sti_sas_volatile_register, + .cache_type = REGCACHE_RBTREE, + .reg_read = sti_sas_read_reg, + .reg_write = sti_sas_write_reg, +}; + +const struct regmap_config stih416_sas_regmap = { + .reg_bits = 32, + .val_bits = 32, + + .max_register = STIH416_AUDIO_DAC_CTRL, + .reg_defaults = stih416_sas_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), + .volatile_reg = sti_sas_volatile_register, + .cache_type = REGCACHE_RBTREE, + .reg_read = sti_sas_read_reg, + .reg_write = sti_sas_write_reg, +}; + +const struct sti_sas_dev_data stih416_data = { + .chipid = CHIPID_STIH416, + .regmap = &stih416_sas_regmap, + .dac_ops = &stih416_dac_ops, + .dapm_widgets = stih416_sas_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), + .dapm_routes = stih416_sas_route, + .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), +}; + +const struct sti_sas_dev_data stih407_data = { + .chipid = CHIPID_STIH407, + .regmap = &stih407_sas_regmap, + .dac_ops = &stih407_dac_ops, + .dapm_widgets = stih407_sas_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), + .dapm_routes = stih407_sas_route, + .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), +}; + +static struct snd_soc_dai_driver sti_sas_dai[] = { + { + .name = "sas-dai-spdif-out", + .id = STI_SAS_DAI_SPDIF_OUT, + .playback = { + .stream_name = "spdif_p", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_fmt = sti_sas_spdif_set_fmt, + .trigger = sti_sas_spdif_trigger, + .set_sysclk = sti_sas_set_sysclk, + .prepare = sti_sas_prepare, + } + }, + }, + { + .name = "sas-dai-dac", + .id = STI_SAS_DAI_ANALOG_OUT, + .playback = { + .stream_name = "dac_p", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + }, +}; + +#ifdef CONFIG_PM_SLEEP +static int sti_sas_resume(struct snd_soc_codec *codec) +{ + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + + return sti_sas_init_sas_registers(codec, drvdata); +} +#else +#define sti_sas_resume NULL +#endif + +static int sti_sas_codec_probe(struct snd_soc_codec *codec) +{ + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + int ret; + + ret = sti_sas_init_sas_registers(codec, drvdata); + + return ret; +} + +static struct snd_soc_codec_driver sti_sas_driver = { + .probe = sti_sas_codec_probe, + .resume = sti_sas_resume, +}; + +static const struct of_device_id sti_sas_dev_match[] = { + { + .compatible = "st,stih416-sas-codec", + .data = &stih416_data, + }, + { + .compatible = "st,stih407-sas-codec", + .data = &stih407_data, + }, + {}, +}; + +static int sti_sas_driver_probe(struct platform_device *pdev) +{ + struct device_node *pnode = pdev->dev.of_node; + struct sti_sas_data *drvdata; + + /* Allocate device structure */ + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + /* Populate data structure depending on compatibility */ + if (!of_match_node(sti_sas_dev_match, pnode)->data) { + dev_err(&pdev->dev, "data associated to device is missing"); + return -EINVAL; + } + + drvdata->dev_data = of_match_node(sti_sas_dev_match, pnode)->data; + + /* Initialise device structure */ + drvdata->dev = &pdev->dev; + + /* Request the DAC & SPDIF registers memory region */ + drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, + drvdata->dev_data->regmap); + if (!drvdata->dac.virt_regmap) { + dev_err(&pdev->dev, "audio registers not enabled\n"); + return -EFAULT; + } + + /* Request the syscon region */ + drvdata->dac.regmap = + syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); + if (!drvdata->dac.regmap) { + dev_err(&pdev->dev, "syscon registers not available\n"); + return -EFAULT; + } + drvdata->spdif.regmap = drvdata->dac.regmap; + + /* Set DAC dai probe */ + if (drvdata->dev_data->chipid == CHIPID_STIH416) + sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; + + sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; + + /* Set dapms*/ + sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; + sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; + + sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; + sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; + + /* Store context */ + dev_set_drvdata(&pdev->dev, drvdata); + + return snd_soc_register_codec(&pdev->dev, &sti_sas_driver, + sti_sas_dai, + ARRAY_SIZE(sti_sas_dai)); +} + +static int sti_sas_driver_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +static struct platform_driver sti_sas_platform_driver = { + .driver = { + .name = "sti-sas-codec", + .owner = THIS_MODULE, + .of_match_table = sti_sas_dev_match, + }, + .probe = sti_sas_driver_probe, + .remove = sti_sas_driver_remove, +}; + +module_platform_driver(sti_sas_platform_driver); + +MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms"); +MODULE_AUTHOR("Arnaud.pouliquen@st.com"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 05e85d4e0180dbbce823e19d81388e60ac924be1 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:05 +0200 Subject: ASoC: sti: add binding for ASoC driver Add ASoC driver bindings documentation. Describe the required properties for each of the hardware IPs drivers. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt new file mode 100644 index 0000000..028fa1c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt @@ -0,0 +1,155 @@ +STMicroelectronics sti ASoC cards + +The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas +codec or external codecs. + +sti sound drivers allows to expose sti SoC audio interface through the +generic ASoC simple card. For details about sound card declaration please refer to +Documentation/devicetree/bindings/sound/simple-card.txt. + +1) sti-uniperiph-dai: audio dai device. +--------------------------------------- + +Required properties: + - compatible: "st,sti-uni-player" or "st,sti-uni-reader" + + - st,syscfg: phandle to boot-device system configuration registers + + - clock-names: name of the clocks listed in clocks property in the same order + + - reg: CPU DAI IP Base address and size entries, listed in same + order than the CPU_DAI properties. + + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + + - interrupts: CPU_DAI interrupt line, listed in the same order than the + CPU_DAI properties. + + - dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same + order than the CPU_DAI properties. + + - dma-names: identifier string for each DMA request line in the dmas property. + "tx" for "st,sti-uni-player" compatibility + "rx" for "st,sti-uni-reader" compatibility + + - version: IP version integrated in SOC. + + - dai-name: DAI name that describes the IP. + +Required properties ("st,sti-uni-player" compatibility only): + - clocks: CPU_DAI IP clock source, listed in the same order than the + CPU_DAI properties. + + - uniperiph-id: internal SOC IP instance ID. + + - IP mode: IP working mode depending on associated codec. + "HDMI" connected to HDMI codec IP and IEC HDMI formats. + "SPDIF"connected to SPDIF codec and support SPDIF formats. + "PCM" PCM standard mode for I2S or TDM bus. + +Optional properties: + - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for + external codecs connection. + + - pinctrl-names: should contain only one value - "default". + +Example: + + sti_uni_player2: sti-uni-player@2 { + compatible = "st,sti-uni-player"; + status = "okay"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_PCM_2>; + reg = <0x8D82000 0x158>; + interrupts = ; + dmas = <&fdma0 4 0 1>; + dai-name = "Uni Player #1 (DAC)"; + dma-names = "tx"; + uniperiph-id = <2>; + version = <5>; + mode = "PCM"; + }; + + sti_uni_player3: sti-uni-player@3 { + compatible = "st,sti-uni-player"; + status = "okay"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_SPDIFF>; + reg = <0x8D85000 0x158>; + interrupts = ; + dmas = <&fdma0 7 0 1>; + dma-names = "tx"; + dai-name = "Uni Player #1 (PIO)"; + uniperiph-id = <3>; + version = <5>; + mode = "SPDIF"; + }; + + sti_uni_reader1: sti-uni-reader@1 { + compatible = "st,sti-uni-reader"; + status = "disabled"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + reg = <0x8D84000 0x158>; + interrupts = ; + dmas = <&fdma0 6 0 1>; + dma-names = "rx"; + dai-name = "Uni Reader #1 (HDMI RX)"; + version = <3>; + }; + +2) sti-sas-codec: internal audio codec IPs driver +------------------------------------------------- + +Required properties: + - compatible: "st,sti-sas-codec" . + Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec" + + - st,syscfg: phandle to boot-device system configuration registers. + + - pinctrl-0: SPDIF PIO description. + + - pinctrl-names: should contain only one value - "default". + +Example: + sti_sas_codec: sti-sas-codec { + compatible = "st,stih407-sas-codec"; + #sound-dai-cells = <1>; + st,reg_audio = <&syscfg_core>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif_out >; + }; + +Example of audio card declaration: + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sti audio card"; + status = "okay"; + + simple-audio-card,dai-link@0 { + /* DAC */ + format = "i2s"; + dai-tdm-slot-width = <32>; + cpu { + sound-dai = <&sti_uni_player2>; + }; + + codec { + sound-dai = <&sti_sasg_codec 1>; + }; + }; + simple-audio-card,dai-link@1 { + /* SPDIF */ + format = "left_j"; + cpu { + sound-dai = <&sti_uni_player3>; + }; + + codec { + sound-dai = <&sti_sasg_codec 0>; + }; + }; + }; -- cgit v0.10.2 From e1ecace6a68518a6751987ab2032b0ec1b3bd5fe Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:06 +0200 Subject: ASoC: sti: Add uniperipheral header file Add the Uniperipheral header file for uniperipheral IPs registers definition. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h new file mode 100644 index 0000000..043853e --- /dev/null +++ b/sound/soc/sti/uniperif.h @@ -0,0 +1,1099 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef __SND_ST_AUD_UNIPERIF_H +#define __SND_ST_AUD_UNIPERIF_H + +#include + +/* + * Register access macros + */ + +#define GET_UNIPERIF_REG(ip, offset, shift, mask) \ + ((readl_relaxed(ip->base + offset) >> shift) & mask) +#define SET_UNIPERIF_REG(ip, offset, shift, mask, value) \ + writel_relaxed(((readl_relaxed(ip->base + offset) & \ + ~(mask << shift)) | (((value) & mask) << shift)), ip->base + offset) +#define SET_UNIPERIF_BIT_REG(ip, offset, shift, mask, value) \ + writel_relaxed((((value) & mask) << shift), ip->base + offset) + +/* + * AUD_UNIPERIF_SOFT_RST reg + */ + +#define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 +#define GET_UNIPERIF_SOFT_RST(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + readl_relaxed(ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) : 0) +#define SET_UNIPERIF_SOFT_RST(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) + +/* SOFT_RST */ +#define UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip) 0x0 +#define UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip) 0x1 +#define SET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ + SET_UNIPERIF_BIT_REG(ip, \ + UNIPERIF_SOFT_RST_OFFSET(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip), 1) +#define GET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_SOFT_RST_OFFSET(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) + +/* + * AUD_UNIPERIF_FIFO_DATA reg + */ + +#define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 +#define SET_UNIPERIF_DATA(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) + +/* + * AUD_UNIPERIF_CHANNEL_STA_REGN reg + */ + +#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) +#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) +#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ + writel_relaxed(value, ip->base + \ + UNIPERIF_CHANNEL_STA_REGN(ip, n)) + +#define UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip) 0x0060 +#define GET_UNIPERIF_CHANNEL_STA_REG0(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG0(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip) 0x0064 +#define GET_UNIPERIF_CHANNEL_STA_REG1(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG1(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip) 0x0068 +#define GET_UNIPERIF_CHANNEL_STA_REG2(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG2(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip) 0x006C +#define GET_UNIPERIF_CHANNEL_STA_REG3(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG3(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip) 0x0070 +#define GET_UNIPERIF_CHANNEL_STA_REG4(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG4(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip) 0x0074 +#define GET_UNIPERIF_CHANNEL_STA_REG5(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG5(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) + +/* + * AUD_UNIPERIF_ITS reg + */ + +#define UNIPERIF_ITS_OFFSET(ip) 0x000C +#define GET_UNIPERIF_ITS(ip) \ + readl_relaxed(ip->base + UNIPERIF_ITS_OFFSET(ip)) + +/* MEM_BLK_READ */ +#define UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip) 5 +#define UNIPERIF_ITS_MEM_BLK_READ_MASK(ip) \ + (BIT(UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip))) + +/* FIFO_ERROR */ +#define UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITS_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip))) + +/* DMA_ERROR */ +#define UNIPERIF_ITS_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITS_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_DMA_ERROR_SHIFT(ip))) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip)))) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) + +/* + * AUD_UNIPERIF_ITS_BCLR reg + */ + +/* FIFO_ERROR */ +#define UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITS_BCLR(ip, \ + UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip)) + +#define UNIPERIF_ITS_BCLR_OFFSET(ip) 0x0010 +#define SET_UNIPERIF_ITS_BCLR(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) + +/* + * AUD_UNIPERIF_ITM reg + */ + +#define UNIPERIF_ITM_OFFSET(ip) 0x0018 +#define GET_UNIPERIF_ITM(ip) \ + readl_relaxed(ip->base + UNIPERIF_ITM_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip))) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip)))) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) + +/* + * AUD_UNIPERIF_ITM_BCLR reg + */ + +#define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c +#define SET_UNIPERIF_ITM_BCLR(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITM_BCLR_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITM_BCLR(ip, \ + UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip)) + +/* DMA_ERROR */ +#define UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BCLR_DMA_ERROR(ip) \ + SET_UNIPERIF_ITM_BCLR(ip, \ + UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) + +/* + * AUD_UNIPERIF_ITM_BSET reg + */ + +#define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 +#define SET_UNIPERIF_ITM_BSET(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITM_BSET_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip)) + +/* MEM_BLK_READ */ +#define UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip) 5 +#define UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip)) + +/* DMA_ERROR */ +#define UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_DMA_ERROR(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip)) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip)))) +#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip)) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip)))) +#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip)) + +/* + * UNIPERIF_CONFIG reg + */ + +#define UNIPERIF_CONFIG_OFFSET(ip) 0x0040 +#define GET_UNIPERIF_CONFIG(ip) \ + readl_relaxed(ip->base + UNIPERIF_CONFIG_OFFSET(ip)) +#define SET_UNIPERIF_CONFIG(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CONFIG_OFFSET(ip)) + +/* PARITY_CNTR */ +#define UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip) 0 +#define UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_PARITY_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 1) + +/* CHANNEL_STA_CNTR */ +#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip) 1 +#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 1) + +/* USER_DAT_CNTR */ +#define UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip) 2 +#define UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_USER_DAT_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 0) + +/* VALIDITY_DAT_CNTR */ +#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip) 3 +#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 1) + +/* ONE_BIT_AUD_SUPPORT */ +#define UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip) 4 +#define UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_ONE_BIT_AUD(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip)) +#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 1) + +/* MEMORY_FMT */ +#define UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip) 5 +#define UNIPERIF_CONFIG_MEM_FMT_MASK(ip) 0x1 +#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) 0 +#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) 1 +#define GET_UNIPERIF_CONFIG_MEM_FMT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ + UNIPERIF_CONFIG_MEM_FMT_MASK(ip)) +#define SET_UNIPERIF_CONFIG_MEM_FMT(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ + UNIPERIF_CONFIG_MEM_FMT_MASK(ip), value) +#define SET_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) \ + SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ + VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip)) +#define SET_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) \ + SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ + VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip)) + +/* REPEAT_CHL_STS */ +#define UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip) 6 +#define UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_REPEAT_CHL_STS(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip)) +#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 1) + +/* BACK_STALL_REQ */ +#define UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 7 : -1) +#define UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_BACK_STALL_REQ(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip)) +#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 1) + +/* FDMA_TRIGGER_LIMIT */ +#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip) 8 +#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip) 0x7F +#define GET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip)) +#define SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip), value) + +/* CHL_STS_UPDATE */ +#define UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) +#define UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip)) +#define SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip), 1) + +/* IDLE_MOD */ +#define UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip) 18 +#define UNIPERIF_CONFIG_IDLE_MOD_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_IDLE_MOD(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip)) +#define SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_IDLE_MOD_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 1) + +/* SUBFRAME_SELECTION */ +#define UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip) 19 +#define UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_SUBFRAME_SEL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip)) +#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF0_SUBF1(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 0) + +/* FULL_SW_CONTROL */ +#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip) 20 +#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_SPDIF_SW_CTRL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip)) +#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 0) + +/* MASTER_CLKEDGE */ +#define UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 24 : -1) +#define UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_MSTR_CLKEDGE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip)) +#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_FALLING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_RISING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 0) + +/* + * UNIPERIF_CTRL reg + */ + +#define UNIPERIF_CTRL_OFFSET(ip) 0x0044 +#define GET_UNIPERIF_CTRL(ip) \ + readl_relaxed(ip->base + UNIPERIF_CTRL_OFFSET(ip)) +#define SET_UNIPERIF_CTRL(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CTRL_OFFSET(ip)) + +/* OPERATION */ +#define UNIPERIF_CTRL_OPERATION_SHIFT(ip) 0 +#define UNIPERIF_CTRL_OPERATION_MASK(ip) 0x7 +#define GET_UNIPERIF_CTRL_OPERATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip) 0 +#define SET_UNIPERIF_CTRL_OPERATION_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 1 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 2 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) 3 +#define SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip)) +/* This is the same as above! */ +#define VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) 3 +#define SET_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) 4 +#define SET_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 5 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 7) +#define SET_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip)) + +/* EXIT_STBY_ON_EOBLOCK */ +#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 3) +#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip)) +#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 1) + +/* ROUNDING */ +#define UNIPERIF_CTRL_ROUNDING_SHIFT(ip) 4 +#define UNIPERIF_CTRL_ROUNDING_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_ROUNDING(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip)) +#define SET_UNIPERIF_CTRL_ROUNDING_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_ROUNDING_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip), 1) + +/* DIVIDER */ +#define UNIPERIF_CTRL_DIVIDER_SHIFT(ip) 5 +#define UNIPERIF_CTRL_DIVIDER_MASK(ip) 0xff +#define GET_UNIPERIF_CTRL_DIVIDER(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ + UNIPERIF_CTRL_DIVIDER_MASK(ip)) +#define SET_UNIPERIF_CTRL_DIVIDER(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ + UNIPERIF_CTRL_DIVIDER_MASK(ip), value) + +/* BYTE_SWAP */ +#define UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 13 : -1) +#define UNIPERIF_CTRL_BYTE_SWP_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_BYTE_SWP(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip)) +#define SET_UNIPERIF_CTRL_BYTE_SWP_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_BYTE_SWP_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 1) + +/* ZERO_STUFFING_HW_SW */ +#define UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 14 : -1) +#define UNIPERIF_CTRL_ZERO_STUFF_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_ZERO_STUFF(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip)) +#define SET_UNIPERIF_CTRL_ZERO_STUFF_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_ZERO_STUFF_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 0) + +/* SPDIF_LAT */ +#define UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) +#define UNIPERIF_CTRL_SPDIF_LAT_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_SPDIF_LAT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip)) +#define SET_UNIPERIF_CTRL_SPDIF_LAT_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 0) + +/* EN_SPDIF_FORMATTING */ +#define UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip) 17 +#define UNIPERIF_CTRL_SPDIF_FMT_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_SPDIF_FMT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip)) +#define SET_UNIPERIF_CTRL_SPDIF_FMT_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 0) + +/* READER_OUT_SELECT */ +#define UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 18 : -1) +#define UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_READER_OUT_SEL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip)) +#define SET_UNIPERIF_CTRL_READER_OUT_SEL_IN_MEM(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_READER_OUT_SEL_ON_I2S_LINE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) + +/* UNDERFLOW_REC_WINDOW */ +#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 +#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip) 0xff +#define GET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip)) +#define SET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip), value) + +/* + * UNIPERIF_I2S_FMT a.k.a UNIPERIF_FORMAT reg + */ + +#define UNIPERIF_I2S_FMT_OFFSET(ip) 0x0048 +#define GET_UNIPERIF_I2S_FMT(ip) \ + readl_relaxed(ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) +#define SET_UNIPERIF_I2S_FMT(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) + +/* NBIT */ +#define UNIPERIF_I2S_FMT_NBIT_SHIFT(ip) 0 +#define UNIPERIF_I2S_FMT_NBIT_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_NBIT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NBIT_32(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_NBIT_16(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip), 1) + +/* DATA_SIZE */ +#define UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip) 1 +#define UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip) 0x7 +#define GET_UNIPERIF_I2S_FMT_DATA_SIZE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_18(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 1) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_20(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 2) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 3) +#define SET_UNIPERIF_I2S_FMTL_DATA_SIZE_28(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 4) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 5) + +/* LR_POL */ +#define UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip) 4 +#define UNIPERIF_I2S_FMT_LR_POL_MASK(ip) 0x1 +#define VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) 0x0 +#define VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_LR_POL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ + UNIPERIF_I2S_FMT_LR_POL_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_LR_POL(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ + UNIPERIF_I2S_FMT_LR_POL_MASK(ip), value) +#define SET_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) \ + SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ + VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip)) +#define SET_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) \ + SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ + VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip)) + +/* SCLK_EDGE */ +#define UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip) 5 +#define UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_SCLK_EDGE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 1) + +/* PADDING */ +#define UNIPERIF_I2S_FMT_PADDING_SHIFT(ip) 6 +#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 +#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 +#define VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) 0x0 +#define VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_PADDING(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ + UNIPERIF_I2S_FMT_PADDING_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_PADDING(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ + UNIPERIF_I2S_FMT_PADDING_MASK(ip), value) +#define SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) \ + SET_UNIPERIF_I2S_FMT_PADDING(ip, \ + VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip)) +#define SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) \ + SET_UNIPERIF_I2S_FMT_PADDING(ip, \ + VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip)) + +/* ALIGN */ +#define UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip) 7 +#define UNIPERIF_I2S_FMT_ALIGN_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_ALIGN(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 1) + +/* ORDER */ +#define UNIPERIF_I2S_FMT_ORDER_SHIFT(ip) 8 +#define UNIPERIF_I2S_FMT_ORDER_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_ORDER(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_ORDER_LSB(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_ORDER_MSB(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip), 1) + +/* NUM_CH */ +#define UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip) 9 +#define UNIPERIF_I2S_FMT_NUM_CH_MASK(ip) 0x7 +#define GET_UNIPERIF_I2S_FMT_NUM_CH(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NUM_CH(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_MASK(ip), value) + +/* NO_OF_SAMPLES_TO_READ */ +#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip) 12 +#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip) 0xfffff +#define GET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip), value) + +/* + * UNIPERIF_BIT_CONTROL reg + */ + +#define UNIPERIF_BIT_CONTROL_OFFSET(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0x004c) +#define GET_UNIPERIF_BIT_CONTROL(ip) \ + readl_relaxed(ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) +#define SET_UNIPERIF_BIT_CONTROL(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) + +/* CLR_UNDERFLOW_DURATION */ +#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip) 0 +#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip) 0x1 +#define GET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip)) +#define SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip), 1) + +/* CHL_STS_UPDATE */ +#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip) 1 +#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip) 0x1 +#define GET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip)) +#define SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ + SET_UNIPERIF_BIT_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip), 1) + +/* + * UNIPERIF_STATUS_1 reg + */ + +#define UNIPERIF_STATUS_1_OFFSET(ip) 0x0050 +#define GET_UNIPERIF_STATUS_1(ip) \ + readl_relaxed(ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) +#define SET_UNIPERIF_STATUS_1(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) + +/* UNDERFLOW_DURATION */ +#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) +#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip) 0xff +#define GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_STATUS_1_OFFSET(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip)) +#define SET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_STATUS_1_OFFSET(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) + +/* + * AUD_UNIPERIF_CHANNEL_STA_REGN reg + */ + +#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) +#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) +#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ + writel_relaxed(value, ip->base + \ + UNIPERIF_CHANNEL_STA_REGN(ip, n)) + +/* + * AUD_UNIPERIF_USER_VALIDITY reg + */ + +#define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 +#define GET_UNIPERIF_USER_VALIDITY(ip) \ + readl_relaxed(ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) +#define SET_UNIPERIF_USER_VALIDITY(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) + +/* VALIDITY_LEFT_AND_RIGHT */ +#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip) 0 +#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip) 0x3 +#define GET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_USER_VALIDITY_OFFSET(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip)) +#define SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_USER_VALIDITY_OFFSET(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip), \ + value ? 0x3 : 0) + +/* + * UNIPERIF_DBG_STANDBY_LEFT_SP reg + */ +#define UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip) 0x0150 +#define UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) +#define UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 0xFFFFFF) +#define GET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip)) +#define SET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) -- cgit v0.10.2 From 76c2145ded6b83488dec4afc46a29a57cee90552 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:07 +0200 Subject: ASoC: sti: Add CPU DAI driver for playback Add code to manage Uniperipheral player IP instances. These DAIs are dedicated to playback and support I2S and IEC modes. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index 043853e..a8d9e94 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -10,6 +10,8 @@ #include +#include + /* * Register access macros */ @@ -1097,3 +1099,117 @@ UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) + +/* + * uniperipheral IP capabilities + */ + +#define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ +#define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ + +/* + * Uniperipheral IP revisions + */ +enum uniperif_version { + SND_ST_UNIPERIF_VERSION_UNKNOWN, + /* SASG1 (Orly), Newman */ + SND_ST_UNIPERIF_VERSION_C6AUD0_UNI_1_0, + /* SASC1, SASG2 (Orly2) */ + SND_ST_UNIPERIF_VERSION_UNI_PLR_1_0, + /* SASC1, SASG2 (Orly2), TELSS, Cannes */ + SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + /* TELSS (SASC1) */ + SND_ST_UNIPERIF_VERSION_TDM_PLR_1_0, + /* Cannes/Monaco */ + SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 +}; + +enum uniperif_type { + SND_ST_UNIPERIF_PLAYER_TYPE_NONE, + SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, + SND_ST_UNIPERIF_PLAYER_TYPE_PCM, + SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF +}; + +enum uniperif_state { + UNIPERIF_STATE_STOPPED, + UNIPERIF_STATE_STARTED, + UNIPERIF_STATE_STANDBY, + UNIPERIF_STATE_UNDERFLOW, + UNIPERIF_STATE_OVERFLOW = UNIPERIF_STATE_UNDERFLOW, + UNIPERIF_STATE_XRUN +}; + +enum uniperif_iec958_encoding_mode { + UNIPERIF_IEC958_ENCODING_MODE_PCM, + UNIPERIF_IEC958_ENCODING_MODE_ENCODED +}; + +struct uniperif_info { + int id; /* instance value of the uniperipheral IP */ + enum uniperif_type player_type; + int underflow_enabled; /* Underflow recovery mode */ +}; + +struct uniperif_iec958_settings { + enum uniperif_iec958_encoding_mode encoding_mode; + struct snd_aes_iec958 iec958; +}; + +struct uniperif { + /* System information */ + struct uniperif_info *info; + struct device *dev; + int ver; /* IP version, used by register access macros */ + struct regmap_field *clk_sel; + + /* capabilities */ + const struct snd_pcm_hardware *hw; + + /* Resources */ + struct resource *mem_region; + void *base; + unsigned long fifo_phys_address; + int irq; + + /* Clocks */ + struct clk *clk; + int mclk; + + /* Runtime data */ + enum uniperif_state state; + + struct snd_pcm_substream *substream; + + /* Specific to IEC958 player */ + struct uniperif_iec958_settings stream_settings; + + /*alsa ctrl*/ + struct snd_kcontrol_new *snd_ctrls; + int num_ctrls; + + /* dai properties */ + unsigned int daifmt; + + /* DAI callbacks */ + const struct snd_soc_dai_ops *dai_ops; +}; + +struct sti_uniperiph_dai { + int stream; + struct uniperif *uni; + struct snd_dmaengine_dai_dma_data dma_data; +}; + +struct sti_uniperiph_data { + struct platform_device *pdev; + struct snd_soc_dai_driver *dai; + struct sti_uniperiph_dai dai_data; +}; + +/* uniperiph player*/ +int uni_player_init(struct platform_device *pdev, + struct uniperif *uni_player); +int uni_player_resume(struct uniperif *player); + +#endif diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c new file mode 100644 index 0000000..d66d633 --- /dev/null +++ b/sound/soc/sti/uniperif_player.c @@ -0,0 +1,890 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include + +#include +#include + +#include "uniperif.h" + +/* + * Some hardware-related definitions + */ + +/* sys config registers definitions */ +#define SYS_CFG_AUDIO_GLUE 0xA4 +#define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 + +/* + * Driver specific types. + */ +#define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) +#define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) +#define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) +#define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ + (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ + UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) + +/* + * Note: snd_pcm_hardware is linked to DMA controller but is declared here to + * integrate DAI_CPU capability in term of rate and supported channels + */ +const struct snd_pcm_hardware uni_player_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 192000, + + .channels_min = 2, + .channels_max = 8, + + .periods_min = 2, + .periods_max = 48, + + .period_bytes_min = 128, + .period_bytes_max = 64 * PAGE_SIZE, + .buffer_bytes_max = 256 * PAGE_SIZE +}; + +static inline int reset_player(struct uniperif *player) +{ + int count = 10; + + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { + udelay(5); + count--; + } + } + + if (!count) { + dev_err(player->dev, "Failed to reset uniperif"); + return -EIO; + } + + return 0; +} + +/* + * uni_player_irq_handler + * In case of error audio stream is stopped; stop action is protected via PCM + * stream lock to avoid race condition with trigger callback. + */ +static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct uniperif *player = dev_id; + unsigned int status; + unsigned int tmp; + + if (player->state == UNIPERIF_STATE_STOPPED) { + /* Unexpected IRQ: do nothing */ + return IRQ_NONE; + } + + /* Get interrupt status & clear them immediately */ + status = GET_UNIPERIF_ITS(player); + SET_UNIPERIF_ITS_BCLR(player, status); + + /* Check for fifo error (underrun) */ + if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { + dev_err(player->dev, "FIFO underflow error detected"); + + /* Interrupt is just for information when underflow recovery */ + if (player->info->underflow_enabled) { + /* Update state to underflow */ + player->state = UNIPERIF_STATE_UNDERFLOW; + + } else { + /* Disable interrupt so doesn't continually fire */ + SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + } + + ret = IRQ_HANDLED; + } + + /* Check for dma error (overrun) */ + if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { + dev_err(player->dev, "DMA error detected"); + + /* Disable interrupt so doesn't continually fire */ + SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + + ret = IRQ_HANDLED; + } + + /* Check for underflow recovery done */ + if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { + if (!player->info->underflow_enabled) { + dev_err(player->dev, "unexpected Underflow recovering"); + return -EPERM; + } + /* Read the underflow recovery duration */ + tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); + + /* Clear the underflow recovery duration */ + SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); + + /* Update state to started */ + player->state = UNIPERIF_STATE_STARTED; + + ret = IRQ_HANDLED; + } + + /* Check if underflow recovery failed */ + if (unlikely(status & + UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { + dev_err(player->dev, "Underflow recovery failed"); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static void uni_player_set_channel_status(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int n; + unsigned int status; + + /* + * Some AVRs and TVs require the channel status to contain a correct + * sampling frequency. If no sample rate is already specified, then + * set one. + */ + if (runtime && (player->stream_settings.iec958.status[3] + == IEC958_AES3_CON_FS_NOTID)) { + switch (runtime->rate) { + case 22050: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_22050; + break; + case 44100: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_44100; + break; + case 88200: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_88200; + break; + case 176400: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_176400; + break; + case 24000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_24000; + break; + case 48000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_48000; + break; + case 96000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_96000; + break; + case 192000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_192000; + break; + case 32000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_32000; + break; + default: + /* Mark as sampling frequency not indicated */ + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_NOTID; + break; + } + } + + /* Audio mode: + * Use audio mode status to select PCM or encoded mode + */ + if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO) + player->stream_settings.encoding_mode = + UNIPERIF_IEC958_ENCODING_MODE_ENCODED; + else + player->stream_settings.encoding_mode = + UNIPERIF_IEC958_ENCODING_MODE_PCM; + + if (player->stream_settings.encoding_mode == + UNIPERIF_IEC958_ENCODING_MODE_PCM) + /* Clear user validity bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); + else + /* Set user validity bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1); + + /* Program the new channel status */ + for (n = 0; n < 6; ++n) { + status = + player->stream_settings.iec958.status[0 + (n * 4)] & 0xf; + status |= + player->stream_settings.iec958.status[1 + (n * 4)] << 8; + status |= + player->stream_settings.iec958.status[2 + (n * 4)] << 16; + status |= + player->stream_settings.iec958.status[3 + (n * 4)] << 24; + SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); + } + + /* Update the channel status */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); + else + SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); +} + +static int uni_player_prepare_iec958(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int clk_div; + + clk_div = player->mclk / runtime->rate; + + /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ + if ((clk_div % 128) || (clk_div <= 0)) { + dev_err(player->dev, "%s: invalid clk_div %d", + __func__, clk_div); + return -EINVAL; + } + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* 16/16 memory format */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); + /* 16-bits per sub-frame */ + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + /* Set 16-bit sample precision */ + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); + break; + case SNDRV_PCM_FORMAT_S32_LE: + /* 16/0 memory format */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); + /* 32-bits per sub-frame */ + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + /* Set 24-bit sample precision */ + SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); + break; + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + /* Set parity to be calculated by the hardware */ + SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player); + + /* Set channel status bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player); + + /* Set user data bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player); + + /* Set validity bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player); + + /* Set full software control to disabled */ + SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player); + + SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); + + /* Update the channel status */ + uni_player_set_channel_status(player, runtime); + + /* Clear the user validity user bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); + + /* Disable one-bit audio mode */ + SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); + + /* Enable consecutive frames repetition of Z preamble (not for HBRA) */ + SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player); + + /* Change to SUF0_SUBF1 and left/right channels swap! */ + SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player); + + /* Set data output as MSB first */ + SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); + + if (player->stream_settings.encoding_mode == + UNIPERIF_IEC958_ENCODING_MODE_ENCODED) + SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player); + else + SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player); + + SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); + + /* Set rounding to off */ + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + + /* Set clock divisor */ + SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128); + + /* Set the spdif latency to not wait before starting player */ + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + + /* + * Ensure iec958 formatting is off. It will be enabled in function + * uni_player_start() at the same time as the operation + * mode is set to work around a silicon issue. + */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); + else + SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); + + return 0; +} + +static int uni_player_prepare_pcm(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int output_frame_size, slot_width, clk_div; + + /* Force slot width to 32 in I2S mode (HW constraint) */ + if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == + SND_SOC_DAIFMT_I2S) { + slot_width = 32; + } else { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + slot_width = 16; + break; + default: + slot_width = 32; + break; + } + } + output_frame_size = slot_width * runtime->channels; + + clk_div = player->mclk / runtime->rate; + /* + * For 32 bits subframe clk_div must be a multiple of 128, + * for 16 bits must be a multiple of 64 + */ + if ((slot_width == 32) && (clk_div % 128)) { + dev_err(player->dev, "%s: invalid clk_div", __func__); + return -EINVAL; + } + + if ((slot_width == 16) && (clk_div % 64)) { + dev_err(player->dev, "%s: invalid clk_div", __func__); + return -EINVAL; + } + + /* + * Number of bits per subframe (which is one channel sample) + * on output - Transfer 16 or 32 bits from FIFO + */ + switch (slot_width) { + case 32: + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); + break; + case 16: + SET_UNIPERIF_I2S_FMT_NBIT_16(player); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); + break; + default: + dev_err(player->dev, "subframe format not supported"); + return -EINVAL; + } + + /* Configure data memory format */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* One data word contains two samples */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + /* + * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits + * on the left than zeros (if less than 32 bytes)"... ;-) + */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); + break; + + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + /* Set rounding to off */ + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + + /* Set clock divisor */ + SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size)); + + /* Number of channelsmust be even*/ + if ((runtime->channels % 2) || (runtime->channels < 2) || + (runtime->channels > 10)) { + dev_err(player->dev, "%s: invalid nb of channels", __func__); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); + + /* Set 1-bit audio format to disabled */ + SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); + + SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + + /* No iec958 formatting as outputting to DAC */ + SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); + + return 0; +} + +static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + if (dir == SND_SOC_CLOCK_IN) + return 0; + + if (clk_id != 0) + return -EINVAL; + + player->mclk = freq; + + return clk_set_rate(player->clk, freq); +} + +static int uni_player_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + struct snd_pcm_runtime *runtime = substream->runtime; + int transfer_size, trigger_limit; + int ret; + + /* The player should be stopped */ + if (player->state != UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state %d", __func__, + player->state); + return -EINVAL; + } + + /* Calculate transfer size (in fifo cells and bytes) for frame count */ + transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; + + /* Calculate number of empty cells available before asserting DREQ */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; + } else { + /* + * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 + * FDMA_TRIGGER_LIMIT also controls when the state switches + * from OFF or STANDBY to AUDIO DATA. + */ + trigger_limit = transfer_size; + } + + /* Trigger limit must be an even number */ + if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || + (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { + dev_err(player->dev, "invalid trigger limit %d", trigger_limit); + return -EINVAL; + } + + SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); + + /* Uniperipheral setup depends on player type */ + switch (player->info->player_type) { + case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: + ret = uni_player_prepare_iec958(player, runtime); + break; + case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: + ret = uni_player_prepare_pcm(player, runtime); + break; + case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: + ret = uni_player_prepare_iec958(player, runtime); + break; + default: + dev_err(player->dev, "invalid player type"); + return -EINVAL; + } + + if (ret) + return ret; + + switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); + break; + case SND_SOC_DAIFMT_NB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); + break; + case SND_SOC_DAIFMT_IB_NF: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + break; + case SND_SOC_DAIFMT_IB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + } + + switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); + SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player); + break; + case SND_SOC_DAIFMT_LEFT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); + break; + case SND_SOC_DAIFMT_RIGHT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); + break; + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); + + /* Reset uniperipheral player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + return reset_player(player); +} + +static int uni_player_start(struct uniperif *player) +{ + int ret; + + /* The player should be stopped */ + if (player->state != UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state", __func__); + return -EINVAL; + } + + ret = clk_prepare_enable(player->clk); + if (ret) { + dev_err(player->dev, "%s: Failed to enable clock", __func__); + return ret; + } + + /* Clear any pending interrupts */ + SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player)); + + /* Set the interrupt mask */ + SET_UNIPERIF_ITM_BSET_DMA_ERROR(player); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); + + /* Enable underflow recovery interrupts */ + if (player->info->underflow_enabled) { + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); + } + + /* Reset uniperipheral player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + ret = reset_player(player); + if (ret < 0) + return ret; + + /* + * Does not use IEC61937 features of the uniperipheral hardware. + * Instead it performs IEC61937 in software and inserts it directly + * into the audio data stream. As such, when encoded mode is selected, + * linear pcm mode is still used, but with the differences of the + * channel status bits set for encoded mode and the validity bits set. + */ + SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player); + + /* + * If iec958 formatting is required for hdmi or spdif, then it must be + * enabled after the operation mode is set. If set prior to this, it + * will not take affect and hang the player. + */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) + SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); + + /* Force channel status update (no update if clk disable) */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); + else + SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); + + /* Update state to started */ + player->state = UNIPERIF_STATE_STARTED; + + return 0; +} + +static int uni_player_stop(struct uniperif *player) +{ + int ret; + + /* The player should not be in stopped state */ + if (player->state == UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state", __func__); + return -EINVAL; + } + + /* Turn the player off */ + SET_UNIPERIF_CTRL_OPERATION_OFF(player); + + /* Soft reset the player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + ret = reset_player(player); + if (ret < 0) + return ret; + + /* Disable interrupts */ + SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player)); + + /* Disable clock */ + clk_disable_unprepare(player->clk); + + /* Update state to stopped and return */ + player->state = UNIPERIF_STATE_STOPPED; + + return 0; +} + +int uni_player_resume(struct uniperif *player) +{ + int ret; + + /* Select the frequency synthesizer clock */ + if (player->clk_sel) { + ret = regmap_field_write(player->clk_sel, 1); + if (ret) { + dev_err(player->dev, + "%s: Failed to select freq synth clock", + __func__); + return ret; + } + } + + SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); + + return 0; +} +EXPORT_SYMBOL_GPL(uni_player_resume); + +static int uni_player_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + return uni_player_start(player); + case SNDRV_PCM_TRIGGER_STOP: + return uni_player_stop(player); + case SNDRV_PCM_TRIGGER_RESUME: + return uni_player_resume(player); + default: + return -EINVAL; + } +} + +static void uni_player_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + if (player->state != UNIPERIF_STATE_STOPPED) + /* Stop the player */ + uni_player_stop(player); +} + +static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, + struct uniperif *player) +{ + int bit_offset; + struct device_node *node = pdev->dev.of_node; + struct regmap *regmap; + + bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; + + regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); + + if (regmap) { + struct reg_field regfield = + REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); + + player->clk_sel = regmap_field_alloc(regmap, regfield); + } else { + dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); + return -EINVAL; + } + + return 0; +} + +static int uni_player_parse_dt(struct platform_device *pdev, + struct uniperif *player) +{ + struct uniperif_info *info; + struct device *dev = &pdev->dev; + struct device_node *pnode = pdev->dev.of_node; + const char *mode; + + /* Allocate memory for the info structure */ + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + of_property_read_u32(pnode, "version", &player->ver); + if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { + dev_err(dev, "Unknown uniperipheral version "); + return -EINVAL; + } + /* Underflow recovery is only supported on later ip revisions */ + if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + info->underflow_enabled = 1; + + of_property_read_u32(pnode, "uniperiph-id", &info->id); + + /* Read the device mode property */ + of_property_read_string(pnode, "mode", &mode); + + if (strcasecmp(mode, "hdmi") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; + else if (strcasecmp(mode, "pcm") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; + else if (strcasecmp(mode, "spdif") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; + else + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; + + /* Save the info structure */ + player->info = info; + + /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ + if (uni_player_parse_dt_clk_glue(pdev, player)) + return -EINVAL; + + return 0; +} + +const struct snd_soc_dai_ops uni_player_dai_ops = { + .shutdown = uni_player_shutdown, + .prepare = uni_player_prepare, + .trigger = uni_player_trigger, + .hw_params = sti_uniperiph_dai_hw_params, + .set_fmt = sti_uniperiph_dai_set_fmt, + .set_sysclk = uni_player_set_sysclk +}; + +int uni_player_init(struct platform_device *pdev, + struct uniperif *player) +{ + int ret = 0; + + player->dev = &pdev->dev; + player->state = UNIPERIF_STATE_STOPPED; + player->hw = &uni_player_pcm_hw; + player->dai_ops = &uni_player_dai_ops; + + ret = uni_player_parse_dt(pdev, player); + + if (ret < 0) { + dev_err(player->dev, "Failed to parse DeviceTree"); + return ret; + } + + /* Get uniperif resource */ + player->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(player->clk)) + ret = (int)PTR_ERR(player->clk); + + /* Select the frequency synthesizer clock */ + if (player->clk_sel) { + ret = regmap_field_write(player->clk_sel, 1); + if (ret) { + dev_err(player->dev, + "%s: Failed to select freq synth clock", + __func__); + return ret; + } + } + + ret = devm_request_irq(&pdev->dev, player->irq, + uni_player_irq_handler, IRQF_SHARED, + dev_name(&pdev->dev), player); + if (ret < 0) + return ret; + + /* Ensure that disabled by default */ + SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); + + if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { + /* Set default iec958 status bits */ + + /* Consumer, PCM, copyright, 2ch, mode 0 */ + player->stream_settings.iec958.status[0] = 0x00; + /* Broadcast reception category */ + player->stream_settings.iec958.status[1] = + IEC958_AES1_CON_GENERAL; + /* Do not take into account source or channel number */ + player->stream_settings.iec958.status[2] = + IEC958_AES2_CON_SOURCE_UNSPEC; + /* Sampling frequency not indicated */ + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_NOTID; + /* Max sample word 24-bit, sample word length not indicated */ + player->stream_settings.iec958.status[4] = + IEC958_AES4_CON_MAX_WORDLEN_24 | + IEC958_AES4_CON_WORDLEN_24_20; + } + + return 0; +} +EXPORT_SYMBOL_GPL(uni_player_init); -- cgit v0.10.2 From f15c444e58ed5b5dfc6056249ef8a74d00118be3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:45 +0200 Subject: ASoC: uda134x: Move state struct allocation to bus probe Resource allocations should be done in the bus probe rather than the CODEC probe. Move the allocation of the drivers state struct there. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 913edf2..a89f98a 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -478,8 +478,8 @@ static struct snd_soc_dai_driver uda134x_dai = { static int uda134x_soc_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct uda134x_priv *uda134x; struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); const struct snd_soc_dapm_widget *widgets; unsigned num_widgets; @@ -506,10 +506,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) return -EINVAL; } - uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); - if (uda134x == NULL) - return -ENOMEM; - snd_soc_codec_set_drvdata(codec, uda134x); codec->control_data = pd; @@ -530,7 +526,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) if (ret) { printk(KERN_ERR "%s failed to register dapm controls: %d", __func__, ret); - kfree(uda134x); return ret; } @@ -551,31 +546,19 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) default: printk(KERN_ERR "%s unknown codec type: %d", __func__, pd->model); - kfree(uda134x); return -EINVAL; } if (ret < 0) { printk(KERN_ERR "UDA134X: failed to register controls\n"); - kfree(uda134x); return ret; } return 0; } -/* power down chip */ -static int uda134x_soc_remove(struct snd_soc_codec *codec) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - - kfree(uda134x); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, - .remove = uda134x_soc_remove, .reg_cache_size = sizeof(uda134x_reg), .reg_word_size = sizeof(u8), .reg_cache_default = uda134x_reg, @@ -592,6 +575,14 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { static int uda134x_codec_probe(struct platform_device *pdev) { + struct uda134x_priv *uda134x; + + uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); + if (!uda134x) + return -ENOMEM; + + platform_set_drvdata(pdev, uda134x); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1); } -- cgit v0.10.2 From 82c7b531f3328dbbb7a53d0f1dc53b92846c411c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:46 +0200 Subject: ASoC: uda134x: Explicitly handle in-data addresses The UDA134X family extends the rather limited L3 register set by using part of the register value as additional address bits. These extra address bits are currently stored in the default register cache and rely on them remaining constant. While this works it is rather idiomatic and slightly confusing. Change it so that the additional address bits are explicitly added when writing a register. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index a89f98a..d47da0e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -39,12 +39,11 @@ struct uda134x_priv { struct snd_pcm_substream *slave_substream; }; -/* In-data addresses are hard-coded into the reg-cache values */ static const char uda134x_reg[UDA134X_REGS_NUM] = { /* Extended address registers */ 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, /* Status, data regs */ - 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* @@ -99,12 +98,14 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, case UDA134X_STATUS0: case UDA134X_STATUS1: addr = UDA134X_STATUS_ADDR; + data |= (reg - UDA134X_STATUS0) << 7; break; case UDA134X_DATA000: case UDA134X_DATA001: case UDA134X_DATA010: case UDA134X_DATA011: addr = UDA134X_DATA0_ADDR; + data |= (reg - UDA134X_DATA000) << 6; break; case UDA134X_DATA1: addr = UDA134X_DATA1_ADDR; -- cgit v0.10.2 From f33c340a51e81a2e6af316b1b8b9b769d32ce8b7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:47 +0200 Subject: ASoC: uda134x: Convert to regmap Use regmap rather then the legacy ASoC IO for the uda134x driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index d47da0e..d25a9f3 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -37,13 +37,27 @@ struct uda134x_priv { struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; + + struct regmap *regmap; + struct uda134x_platform_data *pd; }; -static const char uda134x_reg[UDA134X_REGS_NUM] = { - /* Extended address registers */ - 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Status, data regs */ - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +static const struct reg_default uda134x_reg_defaults[] = { + { UDA134X_EA000, 0x04 }, + { UDA134X_EA001, 0x04 }, + { UDA134X_EA010, 0x04 }, + { UDA134X_EA011, 0x00 }, + { UDA134X_EA100, 0x00 }, + { UDA134X_EA101, 0x00 }, + { UDA134X_EA110, 0x00 }, + { UDA134X_EA111, 0x00 }, + { UDA134X_STATUS0, 0x00 }, + { UDA134X_STATUS1, 0x03 }, + { UDA134X_DATA000, 0x00 }, + { UDA134X_DATA001, 0x00 }, + { UDA134X_DATA010, 0x00 }, + { UDA134X_DATA011, 0x00 }, + { UDA134X_DATA1, 0x00 }, }; /* @@ -52,47 +66,36 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = { static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { - u8 *cache = codec->reg_cache; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int ret; - if (reg >= UDA134X_REGS_NUM) + ret = regmap_read(uda134x->regmap, reg, &val); + if (ret) return -1; - return cache[reg]; + + return val; } -/* - * Write the register cache - */ -static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, unsigned int value) +static void uda134x_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) { - u8 *cache = codec->reg_cache; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - if (reg >= UDA134X_REGS_NUM) - return; - cache[reg] = value; + regmap_write(uda134x->regmap, reg, val); } /* * Write to the uda134x registers * */ -static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, +static int uda134x_regmap_write(void *context, unsigned int reg, unsigned int value) { + struct uda134x_platform_data *pd = context; int ret; u8 addr; u8 data = value; - struct uda134x_platform_data *pd = codec->control_data; - - pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); - - if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unknown register: reg: %u", - __func__, reg); - return -EINVAL; - } - - uda134x_write_reg_cache(codec, reg, value); switch (reg) { case UDA134X_STATUS0: @@ -325,10 +328,8 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, static int uda134x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct uda134x_platform_data *pd = codec->control_data; - int i; - u8 *cache = codec->reg_cache; - + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + struct uda134x_platform_data *pd = uda134x->pd; pr_debug("%s bias level %d\n", __func__, level); switch (level) { @@ -338,17 +339,17 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, /* power on */ if (pd->power) { pd->power(1); - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) - codec->driver->write(codec, i, *cache++); + regcache_sync(uda134x->regmap); } break; case SND_SOC_BIAS_STANDBY: break; case SND_SOC_BIAS_OFF: /* power off */ - if (pd->power) + if (pd->power) { pd->power(0); + regcache_mark_dirty(uda134x->regmap); + } break; } return 0; @@ -479,21 +480,14 @@ static struct snd_soc_dai_driver uda134x_dai = { static int uda134x_soc_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + struct uda134x_platform_data *pd = uda134x->pd; const struct snd_soc_dapm_widget *widgets; unsigned num_widgets; - int ret; printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - if (!pd) { - printk(KERN_ERR "UDA134X SoC codec: " - "missing L3 bitbang function\n"); - return -ENODEV; - } - switch (pd->model) { case UDA134X_UDA1340: case UDA134X_UDA1341: @@ -507,9 +501,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) return -EINVAL; } - - codec->control_data = pd; - if (pd->power) pd->power(1); @@ -560,11 +551,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, - .reg_cache_size = sizeof(uda134x_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = uda134x_reg, - .reg_cache_step = 1, - .read = uda134x_read_reg_cache, .set_bias_level = uda134x_set_bias_level, .suspend_bias_off = true, @@ -574,16 +560,39 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), }; +static const struct regmap_config uda134x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = UDA134X_DATA1, + .reg_defaults = uda134x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .reg_write = uda134x_regmap_write, +}; + static int uda134x_codec_probe(struct platform_device *pdev) { + struct uda134x_platform_data *pd = pdev->dev.platform_data; struct uda134x_priv *uda134x; + if (!pd) { + dev_err(&pdev->dev, "Missing L3 bitbang function\n"); + return -ENODEV; + } + uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); if (!uda134x) return -ENOMEM; + uda134x->pd = pd; platform_set_drvdata(pdev, uda134x); + uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, + &uda134x_regmap_config); + if (IS_ERR(uda134x->regmap)) + return PTR_ERR(uda134x->regmap); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1); } diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h index 9faae06..e41ab38 100644 --- a/sound/soc/codecs/uda134x.h +++ b/sound/soc/codecs/uda134x.h @@ -26,8 +26,6 @@ #define UDA134X_DATA011 13 #define UDA134X_DATA1 14 -#define UDA134X_REGS_NUM 15 - #define STATUS0_DAIFMT_MASK (~(7<<1)) #define STATUS0_SYSCLK_MASK (~(3<<4)) -- cgit v0.10.2 From ef3355d22046f4b2c00b0fdf964d6c92fd3f050d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:48 +0200 Subject: ASoC: uda134x: Use regmap_update_bits() were appropriate Instead of doing the read-modify-update cycle by hand when updating a register use regmap_update_bits(). This also means we can now remove uda134x_read_reg_cache() and uda134x_write() since they are unused. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index d25a9f3..e190263 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -61,31 +61,6 @@ static const struct reg_default uda134x_reg_defaults[] = { }; /* - * The codec has no support for reading its registers except for peak level... - */ -static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - int ret; - - ret = regmap_read(uda134x->regmap, reg, &val); - if (ret) - return -1; - - return val; -} - -static void uda134x_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - - regmap_write(uda134x->regmap, reg, val); -} - -/* * Write to the uda134x registers * */ @@ -137,27 +112,28 @@ static int uda134x_regmap_write(void *context, unsigned int reg, static inline void uda134x_reset(struct snd_soc_codec *codec) { - u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + unsigned int mask = 1<<6; + + regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask); msleep(1); - uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); + regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0); } static int uda134x_mute(struct snd_soc_dai *dai, int mute) { - struct snd_soc_codec *codec = dai->codec; - u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec); + unsigned int mask = 1<<2; + unsigned int val; pr_debug("%s mute: %d\n", __func__, mute); if (mute) - mute_reg |= (1<<2); + val = mask; else - mute_reg &= ~(1<<2); - - uda134x_write(codec, UDA134X_DATA010, mute_reg); + val = 0; - return 0; + return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val); } static int uda134x_startup(struct snd_pcm_substream *substream, @@ -209,7 +185,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - u8 hw_params; + unsigned int hw_params = 0; if (substream == uda134x->slave_substream) { pr_debug("%s ignoring hw_params for slave substream\n", @@ -217,10 +193,6 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, return 0; } - hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - hw_params &= STATUS0_SYSCLK_MASK; - hw_params &= STATUS0_DAIFMT_MASK; - pr_debug("%s sysclk: %d, rate:%d\n", __func__, uda134x->sysclk, params_rate(params)); @@ -271,9 +243,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - uda134x_write(codec, UDA134X_STATUS0, hw_params); - - return 0; + return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, + STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params); } static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, -- cgit v0.10.2 From e27d9ee6e709db070145847f9b5f52008f6eab84 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 13 Jul 2015 13:25:34 +0800 Subject: ASoC: sti-sas: Fix checking return value for ERR_PTR Both devm_regmap_init and syscon_regmap_lookup_by_phandle return ERR_PTR on failure. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 32db2c2..4168b88 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -568,17 +568,17 @@ static int sti_sas_driver_probe(struct platform_device *pdev) /* Request the DAC & SPDIF registers memory region */ drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, drvdata->dev_data->regmap); - if (!drvdata->dac.virt_regmap) { + if (IS_ERR(drvdata->dac.virt_regmap)) { dev_err(&pdev->dev, "audio registers not enabled\n"); - return -EFAULT; + return PTR_ERR(drvdata->dac.virt_regmap); } /* Request the syscon region */ drvdata->dac.regmap = syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); - if (!drvdata->dac.regmap) { + if (IS_ERR(drvdata->dac.regmap)) { dev_err(&pdev->dev, "syscon registers not available\n"); - return -EFAULT; + return PTR_ERR(drvdata->dac.regmap); } drvdata->spdif.regmap = drvdata->dac.regmap; -- cgit v0.10.2 From 589bef3296317b5507a9a6e2e14fb30dd40ee764 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 13 Jul 2015 13:26:45 +0800 Subject: ASoC: sti-sas: Staticise local symbols Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 4168b88..6c0bbe8 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -238,7 +238,7 @@ static int stih416_dac_probe(struct snd_soc_dai *dai) return 0; } -const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { +static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, @@ -248,7 +248,7 @@ const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { +static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, STIH407_DAC_STANDBY_ANA, 1, NULL, 0), SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, @@ -256,13 +256,13 @@ const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -const struct snd_soc_dapm_route stih416_sas_route[] = { +static const struct snd_soc_dapm_route stih416_sas_route[] = { {"DAC Output", NULL, "DAC bandgap"}, {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; -const struct snd_soc_dapm_route stih407_sas_route[] = { +static const struct snd_soc_dapm_route stih407_sas_route[] = { {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; @@ -407,21 +407,21 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops stih416_dac_ops = { +static const struct snd_soc_dai_ops stih416_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih416_sas_dac_mute, .prepare = sti_sas_prepare, .set_sysclk = sti_sas_set_sysclk, }; -const struct snd_soc_dai_ops stih407_dac_ops = { +static const struct snd_soc_dai_ops stih407_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih407_sas_dac_mute, .prepare = sti_sas_prepare, .set_sysclk = sti_sas_set_sysclk, }; -const struct regmap_config stih407_sas_regmap = { +static const struct regmap_config stih407_sas_regmap = { .reg_bits = 32, .val_bits = 32, @@ -434,7 +434,7 @@ const struct regmap_config stih407_sas_regmap = { .reg_write = sti_sas_write_reg, }; -const struct regmap_config stih416_sas_regmap = { +static const struct regmap_config stih416_sas_regmap = { .reg_bits = 32, .val_bits = 32, @@ -447,7 +447,7 @@ const struct regmap_config stih416_sas_regmap = { .reg_write = sti_sas_write_reg, }; -const struct sti_sas_dev_data stih416_data = { +static const struct sti_sas_dev_data stih416_data = { .chipid = CHIPID_STIH416, .regmap = &stih416_sas_regmap, .dac_ops = &stih416_dac_ops, @@ -457,7 +457,7 @@ const struct sti_sas_dev_data stih416_data = { .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), }; -const struct sti_sas_dev_data stih407_data = { +static const struct sti_sas_dev_data stih407_data = { .chipid = CHIPID_STIH407, .regmap = &stih407_sas_regmap, .dac_ops = &stih407_dac_ops, -- cgit v0.10.2 From a2f3a8ca5219651292447f0e1124b3412bc3abff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jul 2015 11:53:08 +0100 Subject: ASoC: sti-sas: Remove spurious dependency on SND_SOC_STI Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 46802ef..e208348 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -613,7 +613,6 @@ config SND_SOC_STAC9766 config SND_SOC_STI_SAS tristate "codec Audio support for STI SAS codec" - depends on SND_SOC_STI config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" -- cgit v0.10.2 From 9cae85f5e26fb59e4436e0676a9aceb461f30c63 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sat, 11 Jul 2015 08:18:59 +0800 Subject: ASoC: sti-sas: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/sti-sas.c:616: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 Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 6c0bbe8..adc2c34 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -613,7 +613,6 @@ static int sti_sas_driver_remove(struct platform_device *pdev) static struct platform_driver sti_sas_platform_driver = { .driver = { .name = "sti-sas-codec", - .owner = THIS_MODULE, .of_match_table = sti_sas_dev_match, }, .probe = sti_sas_driver_probe, -- cgit v0.10.2 From 5119222f2e3de2e51a3b3270036d53c55ce68236 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:19 -0700 Subject: ASoC: max98357a: Make 'sdmode-gpios' dts property optional The option is not needed if chip is always on or managed by some other part of system like platform card driver. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt index a7a149a..28645a2 100644 --- a/Documentation/devicetree/bindings/sound/max98357a.txt +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -4,7 +4,11 @@ This node models the Maxim MAX98357A DAC. Required properties: - compatible : "maxim,max98357a" -- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin + +Optional properties: +- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin. + If this option is not specified then driver does not manage + the pin state (e.g. chip is always on). Example: diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 3a2fda0..fa1b793 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -31,6 +31,9 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, { struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); + if (!sdmode) + return 0; + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -60,7 +63,7 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) { struct gpio_desc *sdmode; - sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW); + sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW); if (IS_ERR(sdmode)) { dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", __func__, PTR_ERR(sdmode)); -- cgit v0.10.2 From 508e61953f7b2c5c828412e5b46fa99b8a3fbaa1 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:20 -0700 Subject: ASoC: max98357a: Use DAI input as a dapm widget Spec does not say anything about DAC called SDMode. It makes more sense to use DAI input that created automatically by DAPM and route it to Speaker output. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index fa1b793..b9e1131 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -51,12 +51,11 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, } static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { - SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_OUTPUT("Speaker"), }; static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { - {"Speaker", NULL, "SDMode"}, + {"Speaker", NULL, "HiFi Playback"}, }; static int max98357a_codec_probe(struct snd_soc_codec *codec) -- cgit v0.10.2 From 4ab0c591c1482c90d14c1d11bf4b469c54a31ecc Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:21 -0700 Subject: ASoC: max98357a: Do not print error message on asoc/gpio errors gpiolib/asoc system already prints enough info if there are any problems. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index b9e1131..e88119a 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -63,11 +63,9 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) struct gpio_desc *sdmode; sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW); - if (IS_ERR(sdmode)) { - dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", - __func__, PTR_ERR(sdmode)); + if (IS_ERR(sdmode)) return PTR_ERR(sdmode); - } + snd_soc_codec_set_drvdata(codec, sdmode); return 0; @@ -106,15 +104,8 @@ static struct snd_soc_dai_driver max98357a_dai_driver = { static int max98357a_platform_probe(struct platform_device *pdev) { - int ret; - - ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, + return snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, &max98357a_dai_driver, 1); - if (ret) - dev_err(&pdev->dev, "%s() error registering codec driver: %d\n", - __func__, ret); - - return ret; } static int max98357a_platform_remove(struct platform_device *pdev) -- cgit v0.10.2 From f6d1a814844efc4b326538bd35a8daecd37921ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 19:40:52 +0200 Subject: ASoC: max98925: Remove control_data initialization The control_data field of the snd_soc_codec struct is no longer used by ASoC drivers using standard regmap IO. There is no need to initialize the field to point to the drivers regmap struct, so drop that. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad6642..eddf8bc 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -523,7 +523,6 @@ 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, -- cgit v0.10.2 From f312bc59d21bed7593199a1921468868150954fa Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 14 Jul 2015 14:51:26 +0800 Subject: ASoC: rt5645: Remove irq_jack_detection function irq_jack_detection is only called from rt5645_jack_detect_work: remove the function to simplify the code. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9dfa431..8693a25 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2874,7 +2874,18 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) return rt5645->jack_type; } -static int rt5645_irq_detection(struct rt5645_priv *rt5645); +static int rt5645_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); + pr_debug("val=0x%x\n", val); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); + + return btn_type; +} + static irqreturn_t rt5645_irq(int irq, void *data); int rt5645_set_jack_detect(struct snd_soc_codec *codec, @@ -2905,34 +2916,6 @@ static void rt5645_jack_detect_work(struct work_struct *work) { struct rt5645_priv *rt5645 = container_of(work, struct rt5645_priv, jack_detect_work.work); - - rt5645_irq_detection(rt5645); -} - -static irqreturn_t rt5645_irq(int irq, void *data) -{ - struct rt5645_priv *rt5645 = data; - - queue_delayed_work(system_power_efficient_wq, - &rt5645->jack_detect_work, msecs_to_jiffies(250)); - - return IRQ_HANDLED; -} - -static int rt5645_button_detect(struct snd_soc_codec *codec) -{ - int btn_type, val; - - val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); - pr_debug("val=0x%x\n", val); - btn_type = val & 0xfff0; - snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); - - return btn_type; -} - -static int rt5645_irq_detection(struct rt5645_priv *rt5645) -{ int val, btn_type, gpio_state = 0, report = 0; switch (rt5645->pdata.jd_mode) { @@ -2947,7 +2930,7 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); - return report; + return; case 1: /* 2 port */ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070; break; @@ -3029,8 +3012,16 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) snd_soc_jack_report(rt5645->btn_jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); +} - return report; +static irqreturn_t rt5645_irq(int irq, void *data) +{ + struct rt5645_priv *rt5645 = data; + + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; } static int rt5645_probe(struct snd_soc_codec *codec) -- cgit v0.10.2 From 27bc1dd24488ce2a13e5c59aaf6d3202e519e21e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:30:31 +0900 Subject: ASoC: mediatek: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c index 4d44b58..6311f31 100644 --- a/sound/soc/mediatek/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173-max98090.c @@ -193,7 +193,6 @@ MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match); static struct platform_driver mt8173_max98090_driver = { .driver = { .name = "mt8173-max98090", - .owner = THIS_MODULE, .of_match_table = mt8173_max98090_dt_match, #ifdef CONFIG_PM .pm = &snd_soc_pm_ops, diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 0940553..4fd7dff 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c @@ -258,7 +258,6 @@ MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match); static struct platform_driver mt8173_rt5650_rt5676_driver = { .driver = { .name = "mtk-rt5650-rt5676", - .owner = THIS_MODULE, .of_match_table = mt8173_rt5650_rt5676_dt_match, #ifdef CONFIG_PM .pm = &snd_soc_pm_ops, diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index cc228db..5b74afb 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -1218,7 +1218,6 @@ static const struct dev_pm_ops mtk_afe_pm_ops = { static struct platform_driver mtk_afe_pcm_driver = { .driver = { .name = "mtk-afe-pcm", - .owner = THIS_MODULE, .of_match_table = mtk_afe_pcm_dt_match, .pm = &mtk_afe_pm_ops, }, -- cgit v0.10.2 From 89e0e250f92b0b0233337043ddf76f261916036c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Jul 2015 11:21:03 +0300 Subject: ASoC: fsl: fsl_spdif: signedness bug in fsl_spdif_startup() We need "i" to be signed or it leads to a forever loop in the error handling. Fixes: fa3be9208dcb ('ASoC: fsl: fsl_spdif: Check for clk_prepare_enable() error') Signed-off-by: Dan Carpenter Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e93221..851b833 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -454,7 +454,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); struct platform_device *pdev = spdif_priv->pdev; struct regmap *regmap = spdif_priv->regmap; - u32 scr, mask, i; + u32 scr, mask; + int i; int ret; /* Reset module and interrupts only for first initialization */ -- cgit v0.10.2 From c9ddbac9c89110f77cb0fa07e634aaf1194899aa Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 14 Jul 2015 18:27:46 -0500 Subject: PCI: Restore PCI_MSIX_FLAGS_BIRMASK definition 09a2c73ddfc7 ("PCI: Remove unused PCI_MSIX_FLAGS_BIRMASK definition") removed PCI_MSIX_FLAGS_BIRMASK from an exported header because it was unused in the kernel. But that breaks user programs that were using it (QEMU in particular). Restore the PCI_MSIX_FLAGS_BIRMASK definition. [bhelgaas: changelog] Signed-off-by: Michael S. Tsirkin Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.13+ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index efe3443..413417f 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -319,6 +319,7 @@ #define PCI_MSIX_PBA 8 /* Pending Bit Array offset */ #define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */ #define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */ +#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */ #define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */ /* MSI-X Table entry format */ -- cgit v0.10.2 From 64793047558781330a1d13b159a2bc9385bdf97f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 15:38:14 +0800 Subject: ASoC: Constify snd_soc_dai_ops variables The snd_soc_dai_ops variables are not modified after initialization in these drivers, so make them const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9..c8f4af2 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -919,7 +919,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) -static struct snd_soc_dai_ops cs42l52_ops = { +static const struct snd_soc_dai_ops cs42l52_ops = { .hw_params = cs42l52_pcm_hw_params, .digital_mute = cs42l52_digital_mute, .set_fmt = cs42l52_set_fmt, diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba4..22bc2f3 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -989,7 +989,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops cs42l56_ops = { +static const struct snd_soc_dai_ops cs42l56_ops = { .hw_params = cs42l56_pcm_hw_params, .digital_mute = cs42l56_digital_mute, .set_fmt = cs42l56_set_dai_fmt, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd9028..00dca1f 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1016,25 +1016,25 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) #define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops isabelle_hs_dai_ops = { +static const struct snd_soc_dai_ops isabelle_hs_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_hs_mute, }; -static struct snd_soc_dai_ops isabelle_hf_dai_ops = { +static const struct snd_soc_dai_ops isabelle_hf_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_hf_mute, }; -static struct snd_soc_dai_ops isabelle_line_dai_ops = { +static const struct snd_soc_dai_ops isabelle_line_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_line_mute, }; -static struct snd_soc_dai_ops isabelle_ul_dai_ops = { +static const struct snd_soc_dai_ops isabelle_ul_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0..081d96d 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1291,35 +1291,35 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec, #define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops lm49453_headset_dai_ops = { +static const struct snd_soc_dai_ops lm49453_headset_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_hp_mute, }; -static struct snd_soc_dai_ops lm49453_speaker_dai_ops = { +static const struct snd_soc_dai_ops lm49453_speaker_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ls_mute, }; -static struct snd_soc_dai_ops lm49453_haptic_dai_ops = { +static const struct snd_soc_dai_ops lm49453_haptic_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ha_mute, }; -static struct snd_soc_dai_ops lm49453_ep_dai_ops = { +static const struct snd_soc_dai_ops lm49453_ep_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ep_mute, }; -static struct snd_soc_dai_ops lm49453_lineout_dai_ops = { +static const struct snd_soc_dai_ops lm49453_lineout_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f05..b1b436f 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2383,7 +2383,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect); #define MAX98090_RATES SNDRV_PCM_RATE_8000_96000 #define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops max98090_dai_ops = { +static const struct snd_soc_dai_ops max98090_dai_ops = { .set_sysclk = max98090_dai_set_sysclk, .set_fmt = max98090_dai_set_fmt, .set_tdm_slot = max98090_set_tdm_slot, diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 3a2fda0..c4a211d 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -79,7 +79,7 @@ static struct snd_soc_codec_driver max98357a_codec_driver = { .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), }; -static struct snd_soc_dai_ops max98357a_dai_ops = { +static const struct snd_soc_dai_ops max98357a_dai_ops = { .trigger = max98357a_daiops_trigger, }; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 3d44fc5..3e770cb 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -650,14 +650,14 @@ static int mc13783_remove(struct snd_soc_codec *codec) #define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops mc13783_ops_dac = { +static const struct snd_soc_dai_ops mc13783_ops_dac = { .hw_params = mc13783_pcm_hw_params_dac, .set_fmt = mc13783_set_fmt_async, .set_sysclk = mc13783_set_sysclk_dac, .set_tdm_slot = mc13783_set_tdm_slot_dac, }; -static struct snd_soc_dai_ops mc13783_ops_codec = { +static const struct snd_soc_dai_ops mc13783_ops_codec = { .hw_params = mc13783_pcm_hw_params_codec, .set_fmt = mc13783_set_fmt_async, .set_sysclk = mc13783_set_sysclk_codec, @@ -698,7 +698,7 @@ static struct snd_soc_dai_driver mc13783_dai_async[] = { }, }; -static struct snd_soc_dai_ops mc13783_ops_sync = { +static const struct snd_soc_dai_ops mc13783_ops_sync = { .hw_params = mc13783_pcm_hw_params_sync, .set_fmt = mc13783_set_fmt_sync, .set_sysclk = mc13783_set_sysclk_sync, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..7c59326 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3110,7 +3110,7 @@ static int rt5645_resume(struct snd_soc_codec *codec) #define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5645_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5645_aif_dai_ops = { .hw_params = rt5645_hw_params, .set_fmt = rt5645_set_dai_fmt, .set_sysclk = rt5645_set_dai_sysclk, diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..d583510 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2720,7 +2720,7 @@ static int rt5670_resume(struct snd_soc_codec *codec) #define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5670_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5670_aif_dai_ops = { .hw_params = rt5670_hw_params, .set_fmt = rt5670_set_dai_fmt, .set_sysclk = rt5670_set_dai_sysclk, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..4b584f9 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4863,7 +4863,7 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5677_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5677_aif_dai_ops = { .hw_params = rt5677_hw_params, .set_fmt = rt5677_set_dai_fmt, .set_sysclk = rt5677_set_dai_sysclk, diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 3e72964..a8402d0 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -208,7 +208,7 @@ out: return err; } -static struct snd_soc_dai_ops si476x_dai_ops = { +static const struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, }; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d..d1552c3 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -520,7 +520,7 @@ static const struct dev_pm_ops tas2552_pm = { NULL) }; -static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = { .hw_params = tas2552_hw_params, .prepare = tas2552_prepare, .set_sysclk = tas2552_set_dai_sysclk, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c4c960f..df01fec 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1121,7 +1121,7 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map), }; -static struct snd_soc_dai_ops aic31xx_dai_ops = { +static const struct snd_soc_dai_ops aic31xx_dai_ops = { .hw_params = aic31xx_hw_params, .set_sysclk = aic31xx_set_dai_sysclk, .set_fmt = aic31xx_set_dai_fmt, -- cgit v0.10.2 From a01da00cbccc162a86c78f61ed4ca55dad35440f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 09:51:33 +0800 Subject: ASoC: da732x: Merge da732x_dai1_ops and da732x_dai2_ops da732x_dai1_ops is identical to da732x_dai2_ops, so merge them to da732x_dai_ops. The da732x_dai_ops is not modified after initialization, so make it const. Signed-off-by: Axel Lin Acked-by: Adam Thomson Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2075236..760935a 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1196,13 +1196,7 @@ static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, #define DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops da732x_dai1_ops = { - .hw_params = da732x_hw_params, - .set_fmt = da732x_set_dai_fmt, - .set_sysclk = da732x_set_dai_sysclk, -}; - -static struct snd_soc_dai_ops da732x_dai2_ops = { +static const struct snd_soc_dai_ops da732x_dai_ops = { .hw_params = da732x_hw_params, .set_fmt = da732x_set_dai_fmt, .set_sysclk = da732x_set_dai_sysclk, @@ -1227,7 +1221,7 @@ static struct snd_soc_dai_driver da732x_dai[] = { .rates = DA732X_RATES, .formats = DA732X_FORMATS, }, - .ops = &da732x_dai1_ops, + .ops = &da732x_dai_ops, }, { .name = "DA732X_AIFB", @@ -1247,7 +1241,7 @@ static struct snd_soc_dai_driver da732x_dai[] = { .rates = DA732X_RATES, .formats = DA732X_FORMATS, }, - .ops = &da732x_dai2_ops, + .ops = &da732x_dai_ops, }, }; -- cgit v0.10.2 From 8e2175d42e435b7957bfaa921fc27cb40e923372 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 13:50:49 +0800 Subject: ASoC: sirf-audio-codec: Staticise local symbols Also make sirf_audio_codec_dai_ops const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 29cb442..6bfd25c 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, return 0; } -struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { +static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { .trigger = sirf_audio_codec_trigger, }; -struct snd_soc_dai_driver sirf_audio_codec_dai = { +static struct snd_soc_dai_driver sirf_audio_codec_dai = { .name = "sirf-audio-codec", .playback = { .stream_name = "Playback", -- cgit v0.10.2 From 1c07a4de5baad76585f7ffb86b5b0bc34c33e8a6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 13:21:44 +0900 Subject: ASoC: drivers: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index a431602..6c96860 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1534,7 +1534,6 @@ MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id); static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", - .owner = THIS_MODULE, }, .probe = adau1373_i2c_probe, .remove = adau1373_i2c_remove, diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index ff7f846..de53c0d 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -915,7 +915,6 @@ MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); static struct i2c_driver adau1701_i2c_driver = { .driver = { .name = "adau1701", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(adau1701_dt_ids), }, .probe = adau1701_i2c_probe, diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 862796d..348ccb1 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids); static struct i2c_driver adau1761_i2c_driver = { .driver = { .name = "adau1761", - .owner = THIS_MODULE, }, .probe = adau1761_i2c_probe, .remove = adau1761_i2c_remove, diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 2ce4362..0e32bba 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -45,7 +45,6 @@ MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids); static struct i2c_driver adau1781_i2c_driver = { .driver = { .name = "adau1781", - .owner = THIS_MODULE, }, .probe = adau1781_i2c_probe, .remove = adau1781_i2c_remove, diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index 9700e8c..21e7394 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -46,7 +46,6 @@ MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); static struct i2c_driver adau1977_i2c_driver = { .driver = { .name = "adau1977", - .owner = THIS_MODULE, }, .probe = adau1977_i2c_probe, .remove = adau1977_i2c_remove, diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c index 66d9fce..52881fa 100644 --- a/sound/soc/codecs/adav803.c +++ b/sound/soc/codecs/adav803.c @@ -36,7 +36,6 @@ static int adav803_remove(struct i2c_client *client) static struct i2c_driver adav803_driver = { .driver = { .name = "adav803", - .owner = THIS_MODULE, }, .probe = adav803_probe, .remove = adav803_remove, diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 8670861..54428c6 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -444,7 +444,6 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); static struct i2c_driver ak4535_i2c_driver = { .driver = { .name = "ak4535", - .owner = THIS_MODULE, }, .probe = ak4535_i2c_probe, .remove = ak4535_i2c_remove, diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 2d0ff45..b14176f 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -609,7 +609,6 @@ MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id); static struct i2c_driver ak4641_i2c_driver = { .driver = { .name = "ak4641", - .owner = THIS_MODULE, }, .probe = ak4641_i2c_probe, .remove = ak4641_i2c_remove, diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7c0f6552..66352f7 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -626,7 +626,6 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); static struct i2c_driver ak4642_i2c_driver = { .driver = { .name = "ak4642-codec", - .owner = THIS_MODULE, .of_match_table = ak4642_of_match, }, .probe = ak4642_i2c_probe, diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 0e59063..c73a9f6 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -663,7 +663,6 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); static struct i2c_driver ak4671_i2c_driver = { .driver = { .name = "ak4671-codec", - .owner = THIS_MODULE, }, .probe = ak4671_i2c_probe, .remove = ak4671_i2c_remove, diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 0fc24e0..cf99c4e 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -1085,7 +1085,6 @@ MODULE_DEVICE_TABLE(of, alc5623_of_match); static struct i2c_driver alc5623_i2c_driver = { .driver = { .name = "alc562x-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(alc5623_of_match), }, .probe = alc5623_i2c_probe, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 607a63b..9277ac6 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1183,7 +1183,6 @@ MODULE_DEVICE_TABLE(of, alc5632_of_match); static struct i2c_driver alc5632_i2c_driver = { .driver = { .name = "alc5632", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(alc5632_of_match), }, .probe = alc5632_i2c_probe, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025..76564dc 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -607,7 +607,6 @@ MODULE_DEVICE_TABLE(i2c, cs35l32_id); static struct i2c_driver cs35l32_i2c_driver = { .driver = { .name = "cs35l32", - .owner = THIS_MODULE, .pm = &cs35l32_runtime_pm, .of_match_table = cs35l32_of_match, }, diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d7ec4756..d1a77c7 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -658,7 +658,6 @@ MODULE_DEVICE_TABLE(i2c, cs4265_id); static struct i2c_driver cs4265_i2c_driver = { .driver = { .name = "cs4265", - .owner = THIS_MODULE, .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e6d4ff9..e07807d 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -751,7 +751,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); static struct i2c_driver cs4270_i2c_driver = { .driver = { .name = "cs4270", - .owner = THIS_MODULE, .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c index b264da0..dcb3223 100644 --- a/sound/soc/codecs/cs4271-i2c.c +++ b/sound/soc/codecs/cs4271-i2c.c @@ -48,7 +48,6 @@ MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); static struct i2c_driver cs4271_i2c_driver = { .driver = { .name = "cs4271", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(cs4271_dt_ids), }, .probe = cs4271_i2c_probe, diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index c40428f..9bad478 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -45,7 +45,6 @@ static int cs42l51_i2c_remove(struct i2c_client *i2c) static struct i2c_driver cs42l51_i2c_driver = { .driver = { .name = "cs42l51", - .owner = THIS_MODULE, .of_match_table = cs42l51_of_match, }, .probe = cs42l51_i2c_probe, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9..b82d8e5 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1285,7 +1285,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l52_id); static struct i2c_driver cs42l52_i2c_driver = { .driver = { .name = "cs42l52", - .owner = THIS_MODULE, .of_match_table = cs42l52_of_match, }, .id_table = cs42l52_id, diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba4..4ae7933 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1408,7 +1408,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l56_id); static struct i2c_driver cs42l56_i2c_driver = { .driver = { .name = "cs42l56", - .owner = THIS_MODULE, .of_match_table = cs42l56_of_match, }, .id_table = cs42l56_id, diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index b7853b9..7cb1d70 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1491,7 +1491,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l73_id); static struct i2c_driver cs42l73_i2c_driver = { .driver = { .name = "cs42l73", - .owner = THIS_MODULE, .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 5a71c9e..800c1d5 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); static struct i2c_driver cs42xx8_i2c_driver = { .driver = { .name = "cs42xx8", - .owner = THIS_MODULE, .pm = &cs42xx8_pm, .of_match_table = cs42xx8_of_match, }, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5..9c7b41a 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1259,7 +1259,6 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id); static struct i2c_driver da7210_i2c_driver = { .driver = { .name = "da7210", - .owner = THIS_MODULE, }, .probe = da7210_i2c_probe, .remove = da7210_i2c_remove, diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 238e48a..f635401 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1585,7 +1585,6 @@ MODULE_DEVICE_TABLE(i2c, da7213_i2c_id); static struct i2c_driver da7213_i2c_driver = { .driver = { .name = "da7213", - .owner = THIS_MODULE, }, .probe = da7213_i2c_probe, .remove = da7213_remove, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2075236..5446d04 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1572,7 +1572,6 @@ MODULE_DEVICE_TABLE(i2c, da732x_i2c_id); static struct i2c_driver da732x_i2c_driver = { .driver = { .name = "da7320", - .owner = THIS_MODULE, }, .probe = da732x_i2c_probe, .remove = da732x_i2c_remove, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446..7d5baa6 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1538,7 +1538,6 @@ static const struct of_device_id da9055_of_match[] = { static struct i2c_driver da9055_i2c_driver = { .driver = { .name = "da9055-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(da9055_of_match), }, .probe = da9055_i2c_probe, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd9028..58a43b1 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1149,7 +1149,6 @@ MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id); static struct i2c_driver isabelle_i2c_driver = { .driver = { .name = "isabelle", - .owner = THIS_MODULE, }, .probe = isabelle_i2c_probe, .remove = isabelle_i2c_remove, diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 99ffc49..558de10 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -142,7 +142,6 @@ MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); static struct i2c_driver lm4857_i2c_driver = { .driver = { .name = "lm4857", - .owner = THIS_MODULE, }, .probe = lm4857_i2c_probe, .id_table = lm4857_i2c_id, diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0..9b2e383 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1460,7 +1460,6 @@ MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id); static struct i2c_driver lm49453_i2c_driver = { .driver = { .name = "lm49453", - .owner = THIS_MODULE, }, .probe = lm49453_i2c_probe, .remove = lm49453_i2c_remove, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index e1c196a..1526aef 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(i2c, max9768_i2c_id); static struct i2c_driver max9768_i2c_driver = { .driver = { .name = "max9768", - .owner = THIS_MODULE, }, .probe = max9768_i2c_probe, .remove = max9768_i2c_remove, diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index d0f4534..99c2daa 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2011,7 +2011,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); static struct i2c_driver max98088_i2c_driver = { .driver = { .name = "max98088", - .owner = THIS_MODULE, }, .probe = max98088_i2c_probe, .remove = max98088_i2c_remove, diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f05..c9db085 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2714,7 +2714,6 @@ MODULE_DEVICE_TABLE(acpi, max98090_acpi_match); static struct i2c_driver max98090_i2c_driver = { .driver = { .name = "max98090", - .owner = THIS_MODULE, .pm = &max98090_pm, .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9a46d3d..ea45c35 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2431,7 +2431,6 @@ MODULE_DEVICE_TABLE(of, max98095_of_match); static struct i2c_driver max98095_i2c_driver = { .driver = { .name = "max98095", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max98095_of_match), }, .probe = max98095_i2c_probe, diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 481d58f1..7c99052 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -352,7 +352,6 @@ MODULE_DEVICE_TABLE(i2c, max9850_i2c_id); static struct i2c_driver max9850_i2c_driver = { .driver = { .name = "max9850", - .owner = THIS_MODULE, }, .probe = max9850_i2c_probe, .remove = max9850_i2c_remove, diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 29549cd..7692623 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -174,7 +174,6 @@ MODULE_DEVICE_TABLE(i2c, max9877_i2c_id); static struct i2c_driver max9877_i2c_driver = { .driver = { .name = "max9877", - .owner = THIS_MODULE, }, .probe = max9877_i2c_probe, .remove = max9877_i2c_remove, diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad6642..ce551ee 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -639,7 +639,6 @@ 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, }, diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index b74118e..bda2bd7 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -597,7 +597,6 @@ MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id); static struct i2c_driver ml26124_i2c_driver = { .driver = { .name = "ml26124", - .owner = THIS_MODULE, }, .probe = ml26124_i2c_probe, .remove = ml26124_i2c_remove, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 477e13d..b2c990f 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -330,7 +330,6 @@ static int pcm1681_i2c_remove(struct i2c_client *client) static struct i2c_driver pcm1681_i2c_driver = { .driver = { .name = "pcm1681", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcm1681_dt_ids), }, .id_table = pcm1681_i2c_id, diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index dcdfac0..dbff416 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -67,7 +67,6 @@ static struct i2c_driver pcm512x_i2c_driver = { .id_table = pcm512x_i2c_id, .driver = { .name = "pcm512x", - .owner = THIS_MODULE, .of_match_table = pcm512x_of_match, .pm = &pcm512x_pm_ops, }, diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e26..83029e4 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1259,7 +1259,6 @@ static int rt286_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt286_i2c_driver = { .driver = { .name = "rt286", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt286_acpi_match), }, .probe = rt286_i2c_probe, diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 7c4bcb6..75e5679 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1259,7 +1259,6 @@ static int rt298_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt298_i2c_driver = { .driver = { .name = "rt298", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt298_acpi_match), }, .probe = rt298_i2c_probe, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 058167c..d877102 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1725,7 +1725,6 @@ static int rt5631_i2c_remove(struct i2c_client *client) static struct i2c_driver rt5631_i2c_driver = { .driver = { .name = "rt5631", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, .probe = rt5631_i2c_probe, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..4a780ef 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2242,7 +2242,6 @@ static int rt5640_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5640_i2c_driver = { .driver = { .name = "rt5640", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5640_acpi_match), .of_match_table = of_match_ptr(rt5640_of_match), }, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..23a7e8d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3459,7 +3459,6 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, .probe = rt5645_i2c_probe, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..8721210 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1806,7 +1806,6 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5651_i2c_driver = { .driver = { .name = "rt5651", - .owner = THIS_MODULE, }, .probe = rt5651_i2c_probe, .remove = rt5651_i2c_remove, diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..8f9ab2b 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -3043,7 +3043,6 @@ static int rt5670_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5670_i2c_driver = { .driver = { .name = "rt5670", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, .probe = rt5670_i2c_probe, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..03afec7 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5273,7 +5273,6 @@ static int rt5677_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", - .owner = THIS_MODULE, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e673f6c..f3e6467 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1601,7 +1601,6 @@ MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids); static struct i2c_driver sgtl5000_i2c_driver = { .driver = { .name = "sgtl5000", - .owner = THIS_MODULE, .of_match_table = sgtl5000_dt_ids, }, .probe = sgtl5000_i2c_probe, diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index f30de76..5d94d6c 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -815,7 +815,6 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); static struct i2c_driver ssm2518_driver = { .driver = { .name = "ssm2518", - .owner = THIS_MODULE, }, .probe = ssm2518_i2c_probe, .remove = ssm2518_i2c_remove, diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index 0d9779d..173ba85 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -52,7 +52,6 @@ MODULE_DEVICE_TABLE(of, ssm2602_of_match); static struct i2c_driver ssm2602_i2c_driver = { .driver = { .name = "ssm2602", - .owner = THIS_MODULE, .of_match_table = ssm2602_of_match, }, .probe = ssm2602_i2c_probe, diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 938d2cb..f3f1f68 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -453,7 +453,6 @@ MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); static struct i2c_driver ssm4567_driver = { .driver = { .name = "ssm4567", - .owner = THIS_MODULE, }, .probe = ssm4567_i2c_probe, .remove = ssm4567_i2c_remove, diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 60eff36..a9844b2 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); static struct i2c_driver sta32x_i2c_driver = { .driver = { .name = "sta32x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st32x_dt_ids), }, .probe = sta32x_i2c_probe, diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index bd819a3..33a4612 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1264,7 +1264,6 @@ MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); static struct i2c_driver sta350_i2c_driver = { .driver = { .name = "sta350", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st350_dt_ids), }, .probe = sta350_i2c_probe, diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 4f70378..3430f44 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -379,7 +379,6 @@ MODULE_DEVICE_TABLE(i2c, sta529_i2c_id); static struct i2c_driver sta529_i2c_driver = { .driver = { .name = "sta529", - .owner = THIS_MODULE, }, .probe = sta529_i2c_probe, .remove = sta529_i2c_remove, diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d..083b6b3 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -769,7 +769,6 @@ MODULE_DEVICE_TABLE(of, tas2552_of_match); static struct i2c_driver tas2552_i2c_driver = { .driver = { .name = "tas2552", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tas2552_of_match), .pm = &tas2552_pm, }, diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 32942be..0a49fc8 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -994,7 +994,6 @@ static int tas5086_i2c_remove(struct i2c_client *i2c) static struct i2c_driver tas5086_i2c_driver = { .driver = { .name = "tas5086", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tas5086_dt_ids), }, .id_table = tas5086_i2c_id, diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index aab0af6..86d05f0 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -314,7 +314,6 @@ MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id); static struct i2c_driver tfa9879_i2c_driver = { .driver = { .name = "tfa9879", - .owner = THIS_MODULE, }, .probe = tfa9879_i2c_probe, .remove = tfa9879_i2c_remove, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c4c960f..48dd9b2 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1283,7 +1283,6 @@ MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tlv320aic31xx_of_match), }, .probe = aic31xx_i2c_probe, diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index ad6cb90..f2d3191 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -871,7 +871,6 @@ MODULE_DEVICE_TABLE(of, aic32x4_of_id); static struct i2c_driver aic32x4_i2c_driver = { .driver = { .name = "tlv320aic32x4", - .owner = THIS_MODULE, .of_match_table = aic32x4_of_id, }, .probe = aic32x4_i2c_probe, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a7cf19b..125a935 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1825,7 +1825,6 @@ MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); static struct i2c_driver aic3x_i2c_driver = { .driver = { .name = "tlv320aic3x-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tlv320aic3x_of_match), }, .probe = aic3x_i2c_probe, diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index d67a311..781398fb 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1585,7 +1585,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id); static struct i2c_driver tlv320dac33_i2c_driver = { .driver = { .name = "tlv320dac33-codec", - .owner = THIS_MODULE, }, .probe = dac33_i2c_probe, .remove = dac33_i2c_remove, diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fac9e0..265c4c3 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -488,7 +488,6 @@ MODULE_DEVICE_TABLE(of, tpa6130a2_of_match); static struct i2c_driver tpa6130a2_i2c_driver = { .driver = { .name = "tpa6130a2", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tpa6130a2_of_match), }, .probe = tpa6130a2_probe, diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index ffc6f30..4356843 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -377,7 +377,6 @@ MODULE_DEVICE_TABLE(of, ts3a227e_of_match); static struct i2c_driver ts3a227e_driver = { .driver = { .name = "ts3a227e", - .owner = THIS_MODULE, .pm = &ts3a227e_pm, .of_match_table = of_match_ptr(ts3a227e_of_match), }, diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 6e159f5..5cafb16 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -810,7 +810,6 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); static struct i2c_driver uda1380_i2c_driver = { .driver = { .name = "uda1380-codec", - .owner = THIS_MODULE, }, .probe = uda1380_i2c_probe, .remove = uda1380_i2c_remove, diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 048f005..ec45c5b 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -251,7 +251,6 @@ MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id); static struct i2c_driver wm1250_ev1_i2c_driver = { .driver = { .name = "wm1250-ev1", - .owner = THIS_MODULE, }, .probe = wm1250_ev1_probe, .remove = wm1250_ev1_remove, diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 21d5402..786abd0 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -942,7 +942,6 @@ MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id); static struct i2c_driver wm2000_i2c_driver = { .driver = { .name = "wm2000", - .owner = THIS_MODULE, }, .probe = wm2000_i2c_probe, .remove = wm2000_i2c_remove, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c830832..d4fa224 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2495,7 +2495,6 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id); static struct i2c_driver wm2200_i2c_driver = { .driver = { .name = "wm2200", - .owner = THIS_MODULE, .pm = &wm2200_pm, }, .probe = wm2200_i2c_probe, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd8..b9594d6 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2722,7 +2722,6 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id); static struct i2c_driver wm5100_i2c_driver = { .driver = { .name = "wm5100", - .owner = THIS_MODULE, .pm = &wm5100_pm, }, .probe = wm5100_i2c_probe, diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index dac5beb..3cff5a6 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -690,7 +690,6 @@ MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); static struct i2c_driver wm8510_i2c_driver = { .driver = { .name = "wm8510", - .owner = THIS_MODULE, .of_match_table = wm8510_of_match, }, .probe = wm8510_i2c_probe, diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 43ea8ae..5f8fde5 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -534,7 +534,6 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); static struct i2c_driver wm8523_i2c_driver = { .driver = { .name = "wm8523", - .owner = THIS_MODULE, .of_match_table = wm8523_of_match, }, .probe = wm8523_i2c_probe, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 759a792..abf6035 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -978,7 +978,6 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "wm8580", - .owner = THIS_MODULE, .of_match_table = wm8580_of_match, }, .probe = wm8580_i2c_probe, diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index cc8251f..44b9e0a 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -478,7 +478,6 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); static struct i2c_driver wm8711_i2c_driver = { .driver = { .name = "wm8711", - .owner = THIS_MODULE, .of_match_table = wm8711_of_match, }, .probe = wm8711_i2c_probe, diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index f1a173e..cd7b024 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); static struct i2c_driver wm8728_i2c_driver = { .driver = { .name = "wm8728", - .owner = THIS_MODULE, .of_match_table = wm8728_of_match, }, .probe = wm8728_i2c_probe, diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 915ea11..4846842 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -789,7 +789,6 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); static struct i2c_driver wm8731_i2c_driver = { .driver = { .name = "wm8731", - .owner = THIS_MODULE, .of_match_table = wm8731_of_match, }, .probe = wm8731_i2c_probe, diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 6ad606f..b54a7b7 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -657,7 +657,6 @@ MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id); static struct i2c_driver wm8737_i2c_driver = { .driver = { .name = "wm8737", - .owner = THIS_MODULE, .of_match_table = wm8737_of_match, }, .probe = wm8737_i2c_probe, diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index b346237..430fa7d 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -633,7 +633,6 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); static struct i2c_driver wm8741_i2c_driver = { .driver = { .name = "wm8741", - .owner = THIS_MODULE, .of_match_table = wm8741_of_match, }, .probe = wm8741_i2c_probe, diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 56d89b0..873933a 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -826,7 +826,6 @@ MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); static struct i2c_driver wm8750_i2c_driver = { .driver = { .name = "wm8750", - .owner = THIS_MODULE, .of_match_table = wm8750_of_match, }, .probe = wm8750_i2c_probe, diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index feb2997a..b5e50ff 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1609,7 +1609,6 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); static struct i2c_driver wm8753_i2c_driver = { .driver = { .name = "wm8753", - .owner = THIS_MODULE, .of_match_table = wm8753_of_match, }, .probe = wm8753_i2c_probe, diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ece9b44..592866d 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -536,7 +536,6 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id); static struct i2c_driver wm8776_i2c_driver = { .driver = { .name = "wm8776", - .owner = THIS_MODULE, .of_match_table = wm8776_of_match, }, .probe = wm8776_i2c_probe, diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index 6596f5f..f27464c 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(of, wm8804_of_match); static struct i2c_driver wm8804_i2c_driver = { .driver = { .name = "wm8804", - .owner = THIS_MODULE, .pm = &wm8804_pm, .of_match_table = wm8804_of_match, }, diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index f3759ec..98900aa 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1312,7 +1312,6 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "wm8900", - .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, .remove = wm8900_i2c_remove, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b5322c1..b011253 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2193,7 +2193,6 @@ MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id); static struct i2c_driver wm8903_i2c_driver = { .driver = { .name = "wm8903", - .owner = THIS_MODULE, .of_match_table = wm8903_of_match, }, .probe = wm8903_i2c_probe, diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 265a4a5..145f5f9 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2292,7 +2292,6 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); static struct i2c_driver wm8904_i2c_driver = { .driver = { .name = "wm8904", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(wm8904_of_match), }, .probe = wm8904_i2c_probe, diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 98ef0ba..f6f9395 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -787,7 +787,6 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); static struct i2c_driver wm8940_i2c_driver = { .driver = { .name = "wm8940", - .owner = THIS_MODULE, }, .probe = wm8940_i2c_probe, .remove = wm8940_i2c_remove, diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 2d591c2..12e4435 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1009,7 +1009,6 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id); static struct i2c_driver wm8955_i2c_driver = { .driver = { .name = "wm8955", - .owner = THIS_MODULE, }, .probe = wm8955_i2c_probe, .remove = wm8955_i2c_remove, diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 94c5c46..1ed0720 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1216,7 +1216,6 @@ MODULE_DEVICE_TABLE(of, wm8960_of_match); static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", - .owner = THIS_MODULE, .of_match_table = wm8960_of_match, }, .probe = wm8960_i2c_probe, diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a057662..20a0103 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -982,7 +982,6 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id); static struct i2c_driver wm8961_i2c_driver = { .driver = { .name = "wm8961", - .owner = THIS_MODULE, }, .probe = wm8961_i2c_probe, .remove = wm8961_i2c_remove, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd..40c4617 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3878,7 +3878,6 @@ MODULE_DEVICE_TABLE(of, wm8962_of_match); static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", - .owner = THIS_MODULE, .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b51184c..2cdde32 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -710,7 +710,6 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id); static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", - .owner = THIS_MODULE, }, .probe = wm8971_i2c_probe, .remove = wm8971_i2c_remove, diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 33b16a7..0a60677 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -634,7 +634,6 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); static struct i2c_driver wm8974_i2c_driver = { .driver = { .name = "wm8974", - .owner = THIS_MODULE, }, .probe = wm8974_i2c_probe, .remove = wm8974_i2c_remove, diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index cfc8cdf..d36d600 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1072,7 +1072,6 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); static struct i2c_driver wm8978_i2c_driver = { .driver = { .name = "wm8978", - .owner = THIS_MODULE, }, .probe = wm8978_i2c_probe, .remove = wm8978_i2c_remove, diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2fdd2c6..f6861cc 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -1133,7 +1133,6 @@ MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id); static struct i2c_driver wm8983_i2c_driver = { .driver = { .name = "wm8983", - .owner = THIS_MODULE, }, .probe = wm8983_i2c_probe, .remove = wm8983_i2c_remove, diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 8a85f50..9c3c151 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id); static struct i2c_driver wm8985_i2c_driver = { .driver = { .name = "wm8985", - .owner = THIS_MODULE, }, .probe = wm8985_i2c_probe, .remove = wm8985_i2c_remove, diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index f13a995..c88ce99 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -919,7 +919,6 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); static struct i2c_driver wm8988_i2c_driver = { .driver = { .name = "wm8988", - .owner = THIS_MODULE, }, .probe = wm8988_i2c_probe, .remove = wm8988_i2c_remove, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 1993fd2..83d72d8 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1356,7 +1356,6 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", - .owner = THIS_MODULE, }, .probe = wm8990_i2c_probe, .remove = wm8990_i2c_remove, diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 44a6777..709d16e 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1363,7 +1363,6 @@ MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id); static struct i2c_driver wm8991_i2c_driver = { .driver = { .name = "wm8991", - .owner = THIS_MODULE, }, .probe = wm8991_i2c_probe, .remove = wm8991_i2c_remove, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db86..3f4dfb9 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1742,7 +1742,6 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id); static struct i2c_driver wm8993_i2c_driver = { .driver = { .name = "wm8993", - .owner = THIS_MODULE, }, .probe = wm8993_i2c_probe, .remove = wm8993_i2c_remove, diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 505b65f..eda52a9 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2298,7 +2298,6 @@ MODULE_DEVICE_TABLE(i2c, wm8995_i2c_id); static struct i2c_driver wm8995_i2c_driver = { .driver = { .name = "wm8995", - .owner = THIS_MODULE, }, .probe = wm8995_i2c_probe, .remove = wm8995_i2c_remove, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f..29b6688 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -3100,7 +3100,6 @@ MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id); static struct i2c_driver wm8996_i2c_driver = { .driver = { .name = "wm8996", - .owner = THIS_MODULE, }, .probe = wm8996_i2c_probe, .remove = wm8996_i2c_remove, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 8a8b1c0..011516e 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1378,7 +1378,6 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); static struct i2c_driver wm9081_i2c_driver = { .driver = { .name = "wm9081", - .owner = THIS_MODULE, }, .probe = wm9081_i2c_probe, .remove = wm9081_i2c_remove, diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 13d23fc..12baf72 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -636,7 +636,6 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id); static struct i2c_driver wm9090_i2c_driver = { .driver = { .name = "wm9090", - .owner = THIS_MODULE, }, .probe = wm9090_i2c_probe, .remove = wm9090_i2c_remove, -- cgit v0.10.2 From 231b86b1d81a75e5212329e2c42faefddcaa9208 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 23:02:38 +0900 Subject: ASoC: Fix warning while make xmldocs caused by soc-core.c This patch fix following warning while make xmldocs. Warning(.//sound/soc/soc-core.c:2148): No description found for parameter 'ratio' Add missing ":" Signed-off-by: Masanari Iida Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0..68e5414 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2127,7 +2127,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); /** * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. * @dai: DAI - * @ratio Ratio of BCLK to Sample rate. + * @ratio: Ratio of BCLK to Sample rate. * * Configures the DAI for a preset BCLK to sample rate ratio. */ -- cgit v0.10.2 From 7d1442b4c4142d94a83451d4e7a11db8aee132ab Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 23:02:39 +0900 Subject: ASoC: Fix warning caused by a typo in comments of snd_soc_add_platform() This patch fix following warnings. Warning(.//sound/soc/soc-core.c:2855): No description found for parameter 'platform_drv' Warning(.//sound/soc/soc-core.c:2855): Excess function parameter 'platform_driver' description in 'snd_soc_add_platform' Signed-off-by: Masanari Iida Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 68e5414..90d6335 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2838,7 +2838,7 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform * @platform: The platform to add - * @platform_driver: The driver for the platform + * @platform_drv: The driver for the platform */ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv) -- cgit v0.10.2 From be9ae230924083772ea74ea6958c846f79df5253 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:59:34 +0200 Subject: ASoC: fsi: Remove obsolete sh_fsi2 platform_device_id entry Since the removal of the r8a7740 legacy board code in commit 1fa59bda21c7fa36 ("ARM: shmobile: Remove legacy board code for Armadillo-800 EVA"), all former users of the "sh_fsi2" platform device name are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 142c066..0215c78 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1911,7 +1911,6 @@ MODULE_DEVICE_TABLE(of, fsi_of_match); static const struct platform_device_id fsi_id_table[] = { { "sh_fsi", (kernel_ulong_t)&fsi1_core }, - { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, {}, }; MODULE_DEVICE_TABLE(platform, fsi_id_table); -- cgit v0.10.2 From 601b9d9c7bd04f81a96896c9859cd37bd6a78d51 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 10:43:20 +0200 Subject: ASoC: sti-sas: fix x86 compilation issue. Fixes for compilation warnings and errors reported by Kbuild test robot for x86_64 and i386. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index adc2c34..160d61a 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -227,8 +227,8 @@ static int stih416_dac_probe(struct snd_soc_dai *dai) dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); if (IS_ERR(dac->rst)) { dev_err(dai->codec->dev, - "%s: ERROR: DAC reset control not defined (%d)!\n", - __func__, (int)dac->rst); + "%s: ERROR: DAC reset control not defined !\n", + __func__); dac->rst = NULL; return -EFAULT; } @@ -547,6 +547,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev) { struct device_node *pnode = pdev->dev.of_node; struct sti_sas_data *drvdata; + const struct of_device_id *of_id; /* Allocate device structure */ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), @@ -555,12 +556,13 @@ static int sti_sas_driver_probe(struct platform_device *pdev) return -ENOMEM; /* Populate data structure depending on compatibility */ - if (!of_match_node(sti_sas_dev_match, pnode)->data) { + of_id = of_match_node(sti_sas_dev_match, pnode); + if (!of_id->data) { dev_err(&pdev->dev, "data associated to device is missing"); return -EINVAL; } - drvdata->dev_data = of_match_node(sti_sas_dev_match, pnode)->data; + drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data; /* Initialise device structure */ drvdata->dev = &pdev->dev; -- cgit v0.10.2 From 5efe58c44312a7f8a1f3ec77c2b88f6d22b74880 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 16 Jul 2015 10:01:33 +0800 Subject: ASoC: rt298: remove meanless pr_info This line doesn't include any information. So, remove it. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 7c4bcb6..6ff68a3 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1144,8 +1144,6 @@ static int rt298_i2c_probe(struct i2c_client *i2c, const struct acpi_device_id *acpiid; int i, ret; - pr_info("%s\n", __func__); - rt298 = devm_kzalloc(&i2c->dev, sizeof(*rt298), GFP_KERNEL); if (NULL == rt298) -- cgit v0.10.2 From b14c917409f47dbfdff93e69effd6740f6a809f7 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 16 Jul 2015 13:42:33 +0800 Subject: ASoC: rt5645: Update dapm pins when the card is not instantiated yet This makes sure the dapm state is consistent when the card is instantiated. However, if the card is not instantiated yet, we still update the registers manually in the "jack in" case, so that we can immediately report if a mic is present or not. Disabling "Mic Det Power" after detection, and on jack out, can wait until the card gets instantiated. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 8693a25..33d1aff 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2805,12 +2805,11 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (jack_insert) { regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); - if (codec->component.card->instantiated) { - /* for jack type detect */ - snd_soc_dapm_force_enable_pin(dapm, "LDO2"); - snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else { + /* for jack type detect */ + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + if (!dapm->card->instantiated) { /* Power up necessary bits for JD if dapm is not ready yet */ regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1, @@ -2841,12 +2840,8 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) rt5645_enable_push_button_irq(codec, true); } } else { - if (codec->component.card->instantiated) { - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else - regmap_update_bits(rt5645->regmap, - RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); rt5645->jack_type = SND_JACK_HEADPHONE; } @@ -2855,19 +2850,10 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); else { - if (codec->component.card->instantiated) { - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(dapm, "LDO2"); - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else { - if (rt5645->pdata.jd_mode == 0) - regmap_update_bits(rt5645->regmap, - RT5645_PWR_MIXER, - RT5645_PWR_LDO2, 0); - regmap_update_bits(rt5645->regmap, - RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); - } + if (rt5645->pdata.jd_mode == 0) + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } } -- cgit v0.10.2 From a4e3c5fa955ce0934774f3f3684377dbf2c20eca Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 16 Jul 2015 13:42:34 +0800 Subject: ASoC: rt5645: Simplify rt5645_enable_push_button_irq LDO2/Mic Det Power pins are already enabled/disabled in rt5645_jack_detect (the jack out code path previously did not disable those if button function is enabled: modify it to make it so). Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 33d1aff..11a2bfc 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2766,13 +2766,9 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { - snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC L power"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC R power"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Det Power"); - snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_mutex_unlock(dapm); + snd_soc_dapm_force_enable_pin(dapm, "ADC L power"); + snd_soc_dapm_force_enable_pin(dapm, "ADC R power"); + snd_soc_dapm_sync(dapm); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); @@ -2785,14 +2781,9 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); - snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_disable_pin_unlocked(dapm, "ADC L power"); - snd_soc_dapm_disable_pin_unlocked(dapm, "ADC R power"); - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Det Power"); - snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_mutex_unlock(dapm); + snd_soc_dapm_disable_pin(dapm, "ADC L power"); + snd_soc_dapm_disable_pin(dapm, "ADC R power"); + snd_soc_dapm_sync(dapm); } } @@ -2847,14 +2838,14 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } else { /* jack out */ rt5645->jack_type = 0; + if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); - else { - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(dapm, "LDO2"); - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } + + if (rt5645->pdata.jd_mode == 0) + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } return rt5645->jack_type; -- cgit v0.10.2 From df2e268226e2e3d79980a5dddfd683126f79ddb4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:49 +0200 Subject: ASoC: max9877: Make driver global regmap struct local Use a stack local variable to handle function local state rather than a global static variable. The later has a potential for race conditions if the probe function runs for two devices concurrently. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index e1df06f..b469e1c 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -20,8 +20,6 @@ #include "max9877.h" -static struct regmap *regmap; - static const struct reg_default max9877_regs[] = { { 0, 0x40 }, { 1, 0x00 }, @@ -145,6 +143,7 @@ static const struct regmap_config max9877_regmap = { static int max9877_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct regmap *regmap; int i; regmap = devm_regmap_init_i2c(client, &max9877_regmap); -- cgit v0.10.2 From 623436af42ef2b37fee8f6058a85f4664bd32c74 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:50 +0200 Subject: ASoC: max9877: Convert to component The driver does not use any CODEC specific constructs anymore. Convert it to snd_soc_component. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index b469e1c..fb448dd 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -121,7 +121,7 @@ static const struct snd_soc_dapm_route max9877_dapm_routes[] = { { "HPR", NULL, "SHDN" }, }; -static const struct snd_soc_codec_driver max9877_codec = { +static const struct snd_soc_component_driver max9877_component_driver = { .controls = max9877_controls, .num_controls = ARRAY_SIZE(max9877_controls), @@ -154,14 +154,8 @@ static int max9877_i2c_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); - return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0); -} - -static int max9877_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; + return devm_snd_soc_register_component(&client->dev, + &max9877_component_driver, NULL, 0); } static const struct i2c_device_id max9877_i2c_id[] = { @@ -175,7 +169,6 @@ static struct i2c_driver max9877_i2c_driver = { .name = "max9877", }, .probe = max9877_i2c_probe, - .remove = max9877_i2c_remove, .id_table = max9877_i2c_id, }; -- cgit v0.10.2 From d79cca1a994f6f4f1cf3d92909f2a73df6b84874 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:51 +0200 Subject: ASoC: max9768: Use managed gpio request Makes the code a bit shorter and simpler. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 1526aef..d70a820 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -183,11 +183,13 @@ static int max9768_i2c_probe(struct i2c_client *client, if (pdata) { /* Mute on powerup to avoid clicks */ - err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute"); + err = devm_gpio_request_one(&client->dev, pdata->mute_gpio, + GPIOF_INIT_HIGH, "MAX9768 Mute"); max9768->mute_gpio = err ?: pdata->mute_gpio; /* Activate chip by releasing shutdown, enables I2C */ - err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown"); + err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio, + GPIOF_INIT_HIGH, "MAX9768 Shutdown"); max9768->shdn_gpio = err ?: pdata->shdn_gpio; max9768->flags = pdata->flags; @@ -199,37 +201,17 @@ static int max9768_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, max9768); max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config); - if (IS_ERR(max9768->regmap)) { - err = PTR_ERR(max9768->regmap); - goto err_gpio_free; - } - - err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0); - if (err) - goto err_gpio_free; - - return 0; + if (IS_ERR(max9768->regmap)) + return PTR_ERR(max9768->regmap); - err_gpio_free: - if (gpio_is_valid(max9768->shdn_gpio)) - gpio_free(max9768->shdn_gpio); - if (gpio_is_valid(max9768->mute_gpio)) - gpio_free(max9768->mute_gpio); - - return err; + return snd_soc_register_codec(&client->dev, &max9768_codec_driver, + NULL, 0); } static int max9768_i2c_remove(struct i2c_client *client) { - struct max9768 *max9768 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - if (gpio_is_valid(max9768->shdn_gpio)) - gpio_free(max9768->shdn_gpio); - if (gpio_is_valid(max9768->mute_gpio)) - gpio_free(max9768->mute_gpio); - return 0; } -- cgit v0.10.2 From 04b5cbd80af899c6a4d51835b069b96ae8864e5a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:52 +0200 Subject: ASoC: max9768: Convert to component The driver does not use any CODEC specific constructs anymore. Convert it to snd_soc_component. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index d70a820..4c300f3 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -43,8 +43,8 @@ static struct reg_default max9768_default_regs[] = { static int max9768_get_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct max9768 *max9768 = snd_soc_component_get_drvdata(c); int val = gpio_get_value_cansleep(max9768->mute_gpio); ucontrol->value.integer.value[0] = !val; @@ -55,8 +55,8 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol, static int max9768_set_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct max9768 *max9768 = snd_soc_component_get_drvdata(c); gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); @@ -130,19 +130,20 @@ static const struct snd_soc_dapm_route max9768_dapm_routes[] = { { "OUT-", NULL, "IN" }, }; -static int max9768_probe(struct snd_soc_codec *codec) +static int max9768_probe(struct snd_soc_component *component) { - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct max9768 *max9768 = snd_soc_component_get_drvdata(component); int ret; if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) { - ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM); + ret = regmap_write(max9768->regmap, MAX9768_CTRL, + MAX9768_CTRL_PWM); if (ret) return ret; } if (gpio_is_valid(max9768->mute_gpio)) { - ret = snd_soc_add_codec_controls(codec, max9768_mute, + ret = snd_soc_add_component_controls(component, max9768_mute, ARRAY_SIZE(max9768_mute)); if (ret) return ret; @@ -151,7 +152,7 @@ static int max9768_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver max9768_codec_driver = { +static struct snd_soc_component_driver max9768_component_driver = { .probe = max9768_probe, .controls = max9768_volume, .num_controls = ARRAY_SIZE(max9768_volume), @@ -204,15 +205,8 @@ static int max9768_i2c_probe(struct i2c_client *client, if (IS_ERR(max9768->regmap)) return PTR_ERR(max9768->regmap); - return snd_soc_register_codec(&client->dev, &max9768_codec_driver, - NULL, 0); -} - -static int max9768_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; + return devm_snd_soc_register_component(&client->dev, + &max9768_component_driver, NULL, 0); } static const struct i2c_device_id max9768_i2c_id[] = { @@ -226,7 +220,6 @@ static struct i2c_driver max9768_i2c_driver = { .name = "max9768", }, .probe = max9768_i2c_probe, - .remove = max9768_i2c_remove, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); -- cgit v0.10.2 From ed6c75f23383ba4e0fbc935c0b6ab165bc9ff65e Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:02 +0200 Subject: ASoC: sti: minor corrections for uniplayer Minor corrections after code review. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d66d633..d12d050 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -475,6 +475,7 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + int ret; if (dir == SND_SOC_CLOCK_IN) return 0; @@ -482,9 +483,11 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, if (clk_id != 0) return -EINVAL; - player->mclk = freq; + ret = clk_set_rate(player->clk, freq); + if (!ret) + player->mclk = freq; - return clk_set_rate(player->clk, freq); + return ret; } static int uni_player_prepare(struct snd_pcm_substream *substream, @@ -562,6 +565,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, case SND_SOC_DAIFMT_IB_IF: SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + break; } switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -840,7 +844,7 @@ int uni_player_init(struct platform_device *pdev, /* Get uniperif resource */ player->clk = of_clk_get(pdev->dev.of_node, 0); if (IS_ERR(player->clk)) - ret = (int)PTR_ERR(player->clk); + ret = PTR_ERR(player->clk); /* Select the frequency synthesizer clock */ if (player->clk_sel) { -- cgit v0.10.2 From c3a0003aaf0dc2ffd006a3bb5abc1f5b639552a7 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:03 +0200 Subject: ASoC: sti: Add CPU DAI driver for capture Add code to manage Uniperipheral reader IP instances. These DAIs are dedicated to capture and support I2S and IEC modes. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index a8d9e94..f396958 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1212,4 +1212,7 @@ int uni_player_init(struct platform_device *pdev, struct uniperif *uni_player); int uni_player_resume(struct uniperif *player); +/* uniperiph reader */ +int uni_reader_init(struct platform_device *pdev, + struct uniperif *uni_reader); #endif diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c new file mode 100644 index 0000000..7d83827 --- /dev/null +++ b/sound/soc/sti/uniperif_reader.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include + +#include + +#include "uniperif.h" + +/* + * Note: snd_pcm_hardware is linked to DMA controller but is declared here to + * integrate unireader capability in term of rate and supported channels + */ +const struct snd_pcm_hardware uni_reader_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 96000, + + .channels_min = 2, + .channels_max = 8, + + .periods_min = 2, + .periods_max = 48, + + .period_bytes_min = 128, + .period_bytes_max = 64 * PAGE_SIZE, + .buffer_bytes_max = 256 * PAGE_SIZE +}; + +/* + * uni_reader_irq_handler + * In case of error audio stream is stopped; stop action is protected via PCM + * stream lock to avoid race condition with trigger callback. + */ +static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct uniperif *reader = dev_id; + unsigned int status; + + if (reader->state == UNIPERIF_STATE_STOPPED) { + /* Unexpected IRQ: do nothing */ + dev_warn(reader->dev, "unexpected IRQ "); + return IRQ_HANDLED; + } + + /* Get interrupt status & clear them immediately */ + status = GET_UNIPERIF_ITS(reader); + SET_UNIPERIF_ITS_BCLR(reader, status); + + /* Check for fifo overflow error */ + if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { + dev_err(reader->dev, "FIFO error detected"); + + snd_pcm_stream_lock(reader->substream); + snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(reader->substream); + + return IRQ_HANDLED; + } + + return ret; +} + +static int uni_reader_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + struct snd_pcm_runtime *runtime = substream->runtime; + int transfer_size, trigger_limit; + int slot_width; + int count = 10; + + /* The reader should be stopped */ + if (reader->state != UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state %d", __func__, + reader->state); + return -EINVAL; + } + + /* Calculate transfer size (in fifo cells and bytes) for frame count */ + transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; + + /* Calculate number of empty cells available before asserting DREQ */ + if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; + else + /* + * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 + * FDMA_TRIGGER_LIMIT also controls when the state switches + * from OFF or STANDBY to AUDIO DATA. + */ + trigger_limit = transfer_size; + + /* Trigger limit must be an even number */ + if ((!trigger_limit % 2) || + (trigger_limit != 1 && transfer_size % 2) || + (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { + dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); + return -EINVAL; + } + + SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); + + switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + case SND_SOC_DAIFMT_NB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); + break; + default: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); + } + + /* Force slot width to 32 in I2S mode */ + if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_I2S) { + slot_width = 32; + } else { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + slot_width = 16; + break; + default: + slot_width = 32; + break; + } + } + + /* Number of bits per subframe (i.e one channel sample) on input. */ + switch (slot_width) { + case 32: + SET_UNIPERIF_I2S_FMT_NBIT_32(reader); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); + break; + case 16: + SET_UNIPERIF_I2S_FMT_NBIT_16(reader); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); + break; + default: + dev_err(reader->dev, "subframe format not supported"); + return -EINVAL; + } + + /* Configure data memory format */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* One data word contains two samples */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(reader); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + /* + * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits + * on the MSB then zeros (if less than 32 bytes)"... + */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); + break; + + default: + dev_err(reader->dev, "format not supported"); + return -EINVAL; + } + + switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(reader); + break; + case SND_SOC_DAIFMT_LEFT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); + break; + case SND_SOC_DAIFMT_RIGHT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); + break; + default: + dev_err(reader->dev, "format not supported"); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); + + /* Data clocking (changing) on the rising edge */ + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); + + /* Number of channels must be even */ + + if ((runtime->channels % 2) || (runtime->channels < 2) || + (runtime->channels > 10)) { + dev_err(reader->dev, "%s: invalid nb of channels", __func__); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); + + /* Clear any pending interrupts */ + SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); + + SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(reader, 0); + + /* Set the interrupt mask */ + SET_UNIPERIF_ITM_BSET_DMA_ERROR(reader); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); + SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader); + + /* Enable underflow recovery interrupts */ + if (reader->info->underflow_enabled) { + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader); + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader); + } + + /* Reset uniperipheral reader */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); + + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { + udelay(5); + count--; + } + if (!count) { + dev_err(reader->dev, "Failed to reset uniperif"); + return -EIO; + } + + return 0; +} + +static int uni_reader_start(struct uniperif *reader) +{ + /* The reader should be stopped */ + if (reader->state != UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state", __func__); + return -EINVAL; + } + + /* Enable reader interrupts (and clear possible stalled ones) */ + SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(reader); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); + + /* Launch the reader */ + SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(reader); + + /* Update state to started */ + reader->state = UNIPERIF_STATE_STARTED; + return 0; +} + +static int uni_reader_stop(struct uniperif *reader) +{ + /* The reader should not be in stopped state */ + if (reader->state == UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state", __func__); + return -EINVAL; + } + + /* Turn the reader off */ + SET_UNIPERIF_CTRL_OPERATION_OFF(reader); + + /* Disable interrupts */ + SET_UNIPERIF_ITM_BCLR(reader, GET_UNIPERIF_ITM(reader)); + + /* Update state to stopped and return */ + reader->state = UNIPERIF_STATE_STOPPED; + + return 0; +} + +static int uni_reader_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + return uni_reader_start(reader); + case SNDRV_PCM_TRIGGER_STOP: + return uni_reader_stop(reader); + default: + return -EINVAL; + } +} + +static void uni_reader_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + + if (reader->state != UNIPERIF_STATE_STOPPED) { + /* Stop the reader */ + uni_reader_stop(reader); + } +} + +static int uni_reader_parse_dt(struct platform_device *pdev, + struct uniperif *reader) +{ + struct uniperif_info *info; + struct device_node *node = pdev->dev.of_node; + + /* Allocate memory for the info structure */ + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + of_property_read_u32(node, "version", &reader->ver); + + /* Save the info structure */ + reader->info = info; + + return 0; +} + +const struct snd_soc_dai_ops uni_reader_dai_ops = { + .shutdown = uni_reader_shutdown, + .prepare = uni_reader_prepare, + .trigger = uni_reader_trigger, + .hw_params = sti_uniperiph_dai_hw_params, + .set_fmt = sti_uniperiph_dai_set_fmt, +}; + +int uni_reader_init(struct platform_device *pdev, + struct uniperif *reader) +{ + int ret = 0; + + reader->dev = &pdev->dev; + reader->state = UNIPERIF_STATE_STOPPED; + reader->hw = &uni_reader_pcm_hw; + reader->dai_ops = &uni_reader_dai_ops; + + dev_err(reader->dev, "%s: enter\n", __func__); + ret = uni_reader_parse_dt(pdev, reader); + if (ret < 0) { + dev_err(reader->dev, "Failed to parse DeviceTree"); + return ret; + } + + ret = devm_request_irq(&pdev->dev, reader->irq, + uni_reader_irq_handler, IRQF_SHARED, + dev_name(&pdev->dev), reader); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ"); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL_GPL(uni_reader_init); -- cgit v0.10.2 From f3bd847eb0a7744b1a86f6b585149434cc6f57ff Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:04 +0200 Subject: ASoC: sti: Add uniperipheral dai driver ASoc uniperipheral dai driver that manages uniperipheral DAIs and registers associated generic dma engine platform. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c new file mode 100644 index 0000000..749e6b2 --- /dev/null +++ b/sound/soc/sti/sti_uniperif.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include "uniperif.h" + +/* + * sti_uniperiph_dai_create_ctrl + * This function is used to create Ctrl associated to DAI but also pcm device. + * Request is done by front end to associate ctrl with pcm device id + */ +int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + struct snd_kcontrol_new *ctrl; + int i; + + if (!uni->num_ctrls) + return 0; + + for (i = 0; i < uni->num_ctrls; i++) { + /* + * Several Control can have same name. Controls are indexed on + * Uniperipheral instance ID + */ + ctrl = &uni->snd_ctrls[i]; + ctrl->index = uni->info->id; + ctrl->device = uni->info->id; + } + + return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); +} + +/* + * DAI + */ +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + int transfer_size; + + transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; + + dma_data = snd_soc_dai_get_dma_data(dai, substream); + dma_data->maxburst = transfer_size; + + return 0; +} + +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + + priv->dai_data.uni->daifmt = fmt; + + return 0; +} + +static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + /* The uniperipheral should be in stopped state */ + if (uni->state != UNIPERIF_STATE_STOPPED) { + dev_err(uni->dev, "%s: invalid uni state( %d)", + __func__, (int)uni->state); + return -EBUSY; + } + + /* Pinctrl: switch pinstate to sleep */ + ret = pinctrl_pm_select_sleep_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { + ret = uni_player_resume(uni); + if (ret) + return ret; + } + + /* pinctrl: switch pinstate to default */ + ret = pinctrl_pm_select_default_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + + /* DMA settings*/ + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) + snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); + else + snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); + + dai_data->dma_data.addr = dai_data->uni->fifo_phys_address; + dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + return sti_uniperiph_dai_create_ctrl(dai); +} + +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .probe = sti_uniperiph_dai_probe, + .suspend = sti_uniperiph_dai_suspend, + .resume = sti_uniperiph_dai_resume +}; + +static const struct snd_soc_component_driver sti_uniperiph_dai_component = { + .name = "sti_cpu_dai", +}; + +static int sti_uniperiph_cpu_dai_of(struct device_node *node, + struct sti_uniperiph_data *priv) +{ + const char *str; + int ret; + struct device *dev = &priv->pdev->dev; + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + struct snd_soc_dai_driver *dai = priv->dai; + struct snd_soc_pcm_stream *stream; + struct uniperif *uni; + + uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); + if (!uni) + return -ENOMEM; + + *dai = sti_uniperiph_dai_template; + ret = of_property_read_string(node, "dai-name", &str); + if (ret < 0) { + dev_err(dev, "%s: dai name missing.\n", __func__); + return -EINVAL; + } + dai->name = str; + + /* Get resources */ + uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); + + if (!uni->mem_region) { + dev_err(dev, "Failed to get memory resource"); + return -ENODEV; + } + + uni->base = devm_ioremap_resource(dev, uni->mem_region); + + if (IS_ERR(uni->base)) + return PTR_ERR(uni->base); + + uni->fifo_phys_address = uni->mem_region->start + + UNIPERIF_FIFO_DATA_OFFSET(uni); + + uni->irq = platform_get_irq(priv->pdev, 0); + if (!uni->irq < 0) { + dev_err(dev, "Failed to get IRQ resource"); + return -ENXIO; + } + + dai_data->uni = uni; + + if (of_device_is_compatible(node, "st,sti-uni-player")) { + uni_player_init(priv->pdev, uni); + stream = &dai->playback; + } else { + uni_reader_init(priv->pdev, uni); + stream = &dai->capture; + } + dai->ops = uni->dai_ops; + + stream->stream_name = dai->name; + stream->channels_min = uni->hw->channels_min; + stream->channels_max = uni->hw->channels_max; + stream->rates = uni->hw->rates; + stream->formats = uni->hw->formats; + + return 0; +} + +static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, +}; + +static int sti_uniperiph_probe(struct platform_device *pdev) +{ + struct sti_uniperiph_data *priv; + struct device_node *node = pdev->dev.of_node; + int ret; + + /* Allocate the private data and the CPU_DAI array */ + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL); + if (!priv->dai) + return -ENOMEM; + + priv->pdev = pdev; + + ret = sti_uniperiph_cpu_dai_of(node, priv); + + dev_set_drvdata(&pdev->dev, priv); + + ret = snd_soc_register_component(&pdev->dev, + &sti_uniperiph_dai_component, + priv->dai, 1); + if (ret < 0) + return ret; + + return devm_snd_dmaengine_pcm_register(&pdev->dev, + &dmaengine_pcm_config, 0); +} + +static const struct of_device_id snd_soc_sti_match[] = { + { .compatible = "st,sti-uni-player", }, + { .compatible = "st,sti-uni-reader", }, + {}, +}; + +static struct platform_driver sti_uniperiph_driver = { + .driver = { + .name = "sti-uniperiph-dai", + .of_match_table = snd_soc_sti_match, + }, + .probe = sti_uniperiph_probe, +}; +module_platform_driver(sti_uniperiph_driver); + +MODULE_DESCRIPTION("uniperipheral DAI driver"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f396958..f1e583d 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1215,4 +1215,13 @@ int uni_player_resume(struct uniperif *player); /* uniperiph reader */ int uni_reader_init(struct platform_device *pdev, struct uniperif *uni_reader); + +/* common */ +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt); + +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + #endif -- cgit v0.10.2 From 1e6babb417f76bd6d1a4d1d633e5c46435acbfe7 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:05 +0200 Subject: ASoC: Add ability to build sti drivers Define the platform and codec drivers, and how to build them. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 2ae9619..467ee1a 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -54,6 +54,7 @@ source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" +source "sound/soc/sti/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" source "sound/soc/ux500/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index e189903..19fd711 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ +obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ obj-$(CONFIG_SND_SOC) += ux500/ diff --git a/sound/soc/sti/Kconfig b/sound/soc/sti/Kconfig new file mode 100644 index 0000000..64a6900 --- /dev/null +++ b/sound/soc/sti/Kconfig @@ -0,0 +1,11 @@ +# +# STM SoC audio configuration +# +menuconfig SND_SOC_STI + tristate "SoC Audio support for STI System-On-Chip" + depends on SND_SOC + depends on ARCH_STI || COMPILE_TEST + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to enable ASoC-support for + any of the STI platforms (e.g. STIH416). diff --git a/sound/soc/sti/Makefile b/sound/soc/sti/Makefile new file mode 100644 index 0000000..4b188d2 --- /dev/null +++ b/sound/soc/sti/Makefile @@ -0,0 +1,4 @@ +# STI platform support +snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o + +obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o -- cgit v0.10.2 From fa050796b35c80ac948c4d24c95262daa905e2ef Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:06 +0200 Subject: ASoC: sti: Add clock adjustement control Add capability to adjust player clock, for clocks drift management. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f1e583d..ee462f7 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1175,6 +1175,7 @@ struct uniperif { /* Clocks */ struct clk *clk; int mclk; + int clk_adj; /* Runtime data */ enum uniperif_state state; @@ -1183,6 +1184,7 @@ struct uniperif { /* Specific to IEC958 player */ struct uniperif_iec958_settings stream_settings; + struct mutex ctrl_lock; /* For resource updated by stream and controls*/ /*alsa ctrl*/ struct snd_kcontrol_new *snd_ctrls; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d12d050..d990d2c 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -36,6 +36,9 @@ (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) +#define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 +#define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 + /* * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate DAI_CPU capability in term of rate and supported channels @@ -172,6 +175,70 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) return ret; } +int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) +{ + int rate_adjusted, rate_achieved, delta, ret; + int adjustment = player->clk_adj; + + /* + * a + * F = f + --------- * f = f + d + * 1000000 + * + * a + * d = --------- * f + * 1000000 + * + * where: + * f - nominal rate + * a - adjustment in ppm (parts per milion) + * F - rate to be set in synthesizer + * d - delta (difference) between f and F + */ + if (adjustment < 0) { + /* div64_64 operates on unsigned values... */ + delta = -1; + adjustment = -adjustment; + } else { + delta = 1; + } + /* 500000 ppm is 0.5, which is used to round up values */ + delta *= (int)div64_u64((uint64_t)rate * + (uint64_t)adjustment + 500000, 1000000); + rate_adjusted = rate + delta; + + /* Adjusted rate should never be == 0 */ + if (!rate_adjusted) + return -EINVAL; + + ret = clk_set_rate(player->clk, rate_adjusted); + if (ret < 0) + return ret; + + rate_achieved = clk_get_rate(player->clk); + if (!rate_achieved) + /* If value is 0 means that clock or parent not valid */ + return -EINVAL; + + /* + * Using ALSA's adjustment control, we can modify the rate to be up + * to twice as much as requested, but no more + */ + delta = rate_achieved - rate; + if (delta < 0) { + /* div64_64 operates on unsigned values... */ + delta = -delta; + adjustment = -1; + } else { + adjustment = 1; + } + /* Frequency/2 is added to round up result */ + adjustment *= (int)div64_u64((uint64_t)delta * 1000000 + rate / 2, + rate); + player->clk_adj = adjustment; + return 0; +} + static void uni_player_set_channel_status(struct uniperif *player, struct snd_pcm_runtime *runtime) { @@ -470,6 +537,78 @@ static int uni_player_prepare_pcm(struct uniperif *player, return 0; } +/* + * uniperif rate adjustement control + */ +static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = UNIPERIF_PLAYER_CLK_ADJ_MIN; + uinfo->value.integer.max = UNIPERIF_PLAYER_CLK_ADJ_MAX; + uinfo->value.integer.step = 1; + + return 0; +} + +static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + ucontrol->value.integer.value[0] = player->clk_adj; + + return 0; +} + +static int snd_sti_clk_adjustment_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + int ret = 0; + + if ((ucontrol->value.integer.value[0] < UNIPERIF_PLAYER_CLK_ADJ_MIN) || + (ucontrol->value.integer.value[0] > UNIPERIF_PLAYER_CLK_ADJ_MAX)) + return -EINVAL; + + mutex_lock(&player->ctrl_lock); + player->clk_adj = ucontrol->value.integer.value[0]; + + if (player->mclk) + ret = uni_player_clk_set_rate(player, player->mclk); + mutex_unlock(&player->ctrl_lock); + + return ret; +} + +static struct snd_kcontrol_new uni_player_clk_adj_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Playback Oversampling Freq. Adjustment", + .info = snd_sti_clk_adjustment_info, + .get = snd_sti_clk_adjustment_get, + .put = snd_sti_clk_adjustment_put, +}; + +static struct snd_kcontrol_new *snd_sti_ctl[] = { + &uni_player_clk_adj_ctl, +}; + +static int uni_player_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + player->clk_adj = 0; + + return 0; +} + static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { @@ -483,9 +622,11 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, if (clk_id != 0) return -EINVAL; - ret = clk_set_rate(player->clk, freq); + mutex_lock(&player->ctrl_lock); + ret = uni_player_clk_set_rate(player, freq); if (!ret) player->mclk = freq; + mutex_unlock(&player->ctrl_lock); return ret; } @@ -816,6 +957,7 @@ static int uni_player_parse_dt(struct platform_device *pdev, } const struct snd_soc_dai_ops uni_player_dai_ops = { + .startup = uni_player_startup, .shutdown = uni_player_shutdown, .prepare = uni_player_prepare, .trigger = uni_player_trigger, @@ -863,6 +1005,8 @@ int uni_player_init(struct platform_device *pdev, if (ret < 0) return ret; + mutex_init(&player->ctrl_lock); + /* Ensure that disabled by default */ SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); SET_UNIPERIF_CTRL_ROUNDING_OFF(player); @@ -889,6 +1033,9 @@ int uni_player_init(struct platform_device *pdev, IEC958_AES4_CON_WORDLEN_24_20; } + player->num_ctrls = ARRAY_SIZE(snd_sti_ctl); + player->snd_ctrls = snd_sti_ctl[0]; + return 0; } EXPORT_SYMBOL_GPL(uni_player_init); -- cgit v0.10.2 From b662680252fa6e3bc53ad087078dd1fe7496449c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:39 +0530 Subject: ASoC: Intel: Skylake: Add dsp loader ops The ops is initialized during the dsp registration and used for the allocating dma buffers. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index cdfca9b..c2d2878 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +#include + struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -104,6 +106,13 @@ struct skl_dsp_fw_ops { int (*set_state_D3)(struct sst_dsp *ctx); }; +struct skl_dsp_loader_ops { + int (*alloc_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab, size_t size); + int (*free_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab); +}; + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); -- cgit v0.10.2 From e30903877fde33192b80100b7f63f2af97b2bd86 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:40 +0530 Subject: ASoC: Intel: Skylake: Add code loader DMA registers Skylake has a DMA controller for loading DSP code and modules to memory. Add the register defines for this DMA Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h new file mode 100644 index 0000000..34c366f --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -0,0 +1,191 @@ +/* + * Intel Code Loader DMA support + * + * Copyright (C) 2015, 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 version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef SKL_SST_CLDMA_H_ +#define SKL_SST_CLDMA_H_ + +#define FW_CL_STREAM_NUMBER 0x1 + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +#define SKL_ADSPIC_CL_DMA 0x2 +#define SKL_ADSPIS_CL_DMA 0x2 +#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ +#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ + +/* Intel HD Audio Code Loader DMA Registers */ + +#define HDA_ADSP_LOADER_BASE 0x80 + +/* Stream Registers */ +#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) +#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) +#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) +#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) +#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) +#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) +#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) +#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) +#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) +#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) +#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) + +/* CL: Software Position Based FIFO Capability Registers */ +#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) +#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) +#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) + +/* CL: Stream Descriptor x Control */ + +/* Stream Reset */ +#define CL_SD_CTL_SRST_SHIFT 0 +#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) +#define CL_SD_CTL_SRST(x) \ + ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) + +/* Stream Run */ +#define CL_SD_CTL_RUN_SHIFT 1 +#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) +#define CL_SD_CTL_RUN(x) \ + ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) + +/* Interrupt On Completion Enable */ +#define CL_SD_CTL_IOCE_SHIFT 2 +#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) +#define CL_SD_CTL_IOCE(x) \ + ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) + +/* FIFO Error Interrupt Enable */ +#define CL_SD_CTL_FEIE_SHIFT 3 +#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) +#define CL_SD_CTL_FEIE(x) \ + ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) + +/* Descriptor Error Interrupt Enable */ +#define CL_SD_CTL_DEIE_SHIFT 4 +#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) +#define CL_SD_CTL_DEIE(x) \ + ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) + +/* FIFO Limit Change */ +#define CL_SD_CTL_FIFOLC_SHIFT 5 +#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) +#define CL_SD_CTL_FIFOLC(x) \ + ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) + +/* Stripe Control */ +#define CL_SD_CTL_STRIPE_SHIFT 16 +#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) +#define CL_SD_CTL_STRIPE(x) \ + ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) + +/* Traffic Priority */ +#define CL_SD_CTL_TP_SHIFT 18 +#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) +#define CL_SD_CTL_TP(x) \ + ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) + +/* Bidirectional Direction Control */ +#define CL_SD_CTL_DIR_SHIFT 19 +#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) +#define CL_SD_CTL_DIR(x) \ + ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) + +/* Stream Number */ +#define CL_SD_CTL_STRM_SHIFT 20 +#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) +#define CL_SD_CTL_STRM(x) \ + ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) + +/* CL: Stream Descriptor x Status */ + +/* Buffer Completion Interrupt Status */ +#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) + +/* FIFO Error */ +#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) + +/* Descriptor Error */ +#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) + +/* FIFO Ready */ +#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) + + +/* CL: Stream Descriptor x Last Valid Index */ +#define CL_SD_LVI_SHIFT 0 +#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) +#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) + +/* CL: Stream Descriptor x FIFO Eviction Watermark */ +#define CL_SD_FIFOW_SHIFT 0 +#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) +#define CL_SD_FIFOW(x) \ + ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) + +/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ + +/* Protect Bits */ +#define CL_SD_BDLPLBA_PROT_SHIFT 0 +#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) +#define CL_SD_BDLPLBA_PROT(x) \ + ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) + +/* Buffer Descriptor List Lower Base Address */ +#define CL_SD_BDLPLBA_SHIFT 7 +#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) +#define CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define CL_SD_BDLPUBA_SHIFT 0 +#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) +#define CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) + +/* + * Code Loader - Software Position Based FIFO + * Capability Registers x Software Position Based FIFO Header + */ + +/* Next Capability Pointer */ +#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 +#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) +#define CL_SPBFIFO_SPBFCH_PTR(x) \ + ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) + +/* Capability Identifier */ +#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 +#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) +#define CL_SPBFIFO_SPBFCH_ID(x) \ + ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) + +/* Capability Version */ +#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 +#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) +#define CL_SPBFIFO_SPBFCH_VER(x) \ + ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) + +/* Software Position in Buffer Enable */ +#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) +#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +#endif /* SKL_SST_CLDMA_H_ */ -- cgit v0.10.2 From 914426c8657c1e934b015ffa32e7bfd0cb34f47f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:41 +0530 Subject: ASoC: Intel: Skylake: add code loader DMA operations This patch starts adding code loader DMA handling internal operations for setting up bdle, controller, spb, cleanup routines and buffer filling Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c new file mode 100644 index 0000000..44019ee --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -0,0 +1,194 @@ +/* + * skl-sst-cldma.c - Code Loader DMA handler + * + * Copyright (C) 2015, Intel Corporation. + * Author: Subhransu S. Prusty + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static void skl_cldma_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); +} + +void skl_cldma_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); +} + +/* Code loader helper APIs */ +static void skl_cldma_setup_bdle(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + + ctx->cl_dev.frags = 0; + while (size > 0) { + phys_addr_t addr = virt_to_phys(dmab_data->area + + (ctx->cl_dev.frags * ctx->cl_dev.bufsize)); + + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + + bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize); + + size -= ctx->cl_dev.bufsize; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + + bdl += 4; + ctx->cl_dev.frags++; + } +} + +/* + * Setup controller + * Configure the registers to update the dma buffer address and + * enable interrupts. + * Note: Using the channel 1 for transfer + */ +static void skl_cldma_setup_controller(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, unsigned int max_size, + u32 count) +{ + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, + CL_SD_BDLPLBA(dmab_bdl->addr)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, + CL_SD_BDLPUBA(dmab_bdl->addr)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); +} + +static void skl_cldma_setup_spb(struct sst_dsp *ctx, + unsigned int size, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); + else + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); +} + +static void skl_cldma_cleanup(struct sst_dsp *ctx) +{ + skl_cldma_cleanup_spb(ctx); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + +static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +{ + int ret = 0; + + if (!wait_event_timeout(ctx->cl_dev.wait_queue, + ctx->cl_dev.wait_condition, + msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { + dev_err(ctx->dev, "%s: Wait timeout\n", __func__); + ret = -EIO; + goto cleanup; + } + + dev_dbg(ctx->dev, "%s: Event wake\n", __func__); + if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { + dev_err(ctx->dev, "%s: DMA Error\n", __func__); + ret = -EIO; + } + +cleanup: + ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; + return ret; +} + +static void skl_cldma_stop(struct sst_dsp *ctx) +{ + ctx->cl_dev.ops.cl_trigger(ctx, false); +} + +static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, + const void *curr_pos, bool intr_enable, bool trigger) +{ + dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); + dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", + ctx->cl_dev.dma_buffer_offset, trigger); + dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size); + + if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) + ctx->cl_dev.dma_buffer_offset = 0; + else + ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; + + ctx->cl_dev.wait_condition = false; + + if (intr_enable) + skl_cldma_int_enable(ctx); + + ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); + if (trigger) + ctx->cl_dev.ops.cl_trigger(ctx, true); +} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 34c366f..99e4c86 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -188,4 +188,64 @@ #define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) +/* SST IPC SKL defines */ +#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +enum skl_cl_dma_wake_states { + SKL_CL_DMA_STATUS_NONE = 0, + SKL_CL_DMA_BUF_COMPLETE, + SKL_CL_DMA_ERR, /* TODO: Expand the error states */ +}; + +struct sst_dsp; + +struct skl_cl_dev_ops { + void (*cl_setup_bdle)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc); + void (*cl_setup_controller)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 page_count); + void (*cl_setup_spb)(struct sst_dsp *ctx, + unsigned int size, bool enable); + void (*cl_cleanup_spb)(struct sst_dsp *ctx); + void (*cl_trigger)(struct sst_dsp *ctx, bool enable); + void (*cl_cleanup_controller)(struct sst_dsp *ctx); + int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, + const void *bin, u32 size); + void (*cl_stop_dma)(struct sst_dsp *ctx); +}; + +/** + * skl_cl_dev - holds information for code loader dma transfer + * + * @dmab_data: buffer pointer + * @dmab_bdl: buffer descriptor list + * @bufsize: ring buffer size + * @frags: Last valid buffer descriptor index in the BDL + * @curr_spib_pos: Current position in ring buffer + * @dma_buffer_offset: dma buffer offset + * @ops: operations supported on CL dma + * @wait_queue: wait queue to wake for wake event + * @wake_status: DMA wake status + * @wait_condition: condition to wait on wait queue + * @cl_dma_lock: for synchronized access to cldma + */ +struct skl_cl_dev { + struct snd_dma_buffer dmab_data; + struct snd_dma_buffer dmab_bdl; + + unsigned int bufsize; + unsigned int frags; + + unsigned int curr_spib_pos; + unsigned int dma_buffer_offset; + struct skl_cl_dev_ops ops; + + wait_queue_head_t wait_queue; + int wake_status; + bool wait_condition; +}; + #endif /* SKL_SST_CLDMA_H_ */ -- cgit v0.10.2 From 3e40a78461739d86fe1084c515ec227507ba993d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:42 +0530 Subject: ASoC: Intel: Skylake: Add code loader DMA APIs This patch adds the last piece of code loader DMA APIs by adding the code loader DMA APIs for the driver to use Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index dd79648..cbd568e 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -308,8 +308,11 @@ struct sst_dsp { /* SKL data */ + /* To allocate CL dma buffers */ + struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; int sst_state; + struct skl_cl_dev cl_dev; u32 intr_status; }; diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 10c1319..eff3e17 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44019ee..44748ba 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -192,3 +192,136 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, if (trigger) ctx->cl_dev.ops.cl_trigger(ctx, true); } + +/* + * The CL dma doesn't have any way to update the transfer status until a BDL + * buffer is fully transferred + * + * So Copying is divided in two parts. + * 1. Interrupt on buffer done where the size to be transferred is more than + * ring buffer size. + * 2. Polling on fw register to identify if data left to transferred doesn't + * fill the ring buffer. Caller takes care of polling the required status + * register to identify the transfer status. + */ +static int +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +{ + int ret = 0; + bool start = true; + unsigned int excess_bytes; + u32 size; + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + + if (total_size <= 0) + return -EINVAL; + + dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); + + while (bytes_left) { + if (bytes_left > ctx->cl_dev.bufsize) { + + /* + * dma transfers only till the write pointer as + * updated in spib + */ + if (ctx->cl_dev.curr_spib_pos == 0) + ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; + + size = ctx->cl_dev.bufsize; + skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); + + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } + + } else { + skl_cldma_int_disable(ctx); + + if ((ctx->cl_dev.curr_spib_pos + bytes_left) + <= ctx->cl_dev.bufsize) { + ctx->cl_dev.curr_spib_pos += bytes_left; + } else { + excess_bytes = bytes_left - + (ctx->cl_dev.bufsize - + ctx->cl_dev.curr_spib_pos); + ctx->cl_dev.curr_spib_pos = excess_bytes; + } + + size = bytes_left; + skl_cldma_fill_buffer(ctx, size, + curr_pos, false, start); + } + bytes_left -= size; + curr_pos = curr_pos + size; + } + + return ret; +} + +void skl_cldma_process_intr(struct sst_dsp *ctx) +{ + u8 cl_dma_intr_status; + + cl_dma_intr_status = + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); + + if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) + ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; + else + ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; + + ctx->cl_dev.wait_condition = true; + wake_up(&ctx->cl_dev.wait_queue); +} + +int skl_cldma_prepare(struct sst_dsp *ctx) +{ + int ret; + u32 *bdl; + + ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; + + /* Allocate cl ops */ + ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; + ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; + ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; + ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; + ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; + ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; + ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; + + /* Allocate buffer*/ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); + return ret; + } + /* Setup Code loader BDL */ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_bdl, PAGE_SIZE); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + return ret; + } + bdl = (u32 *)ctx->cl_dev.dmab_bdl.area; + + /* Allocate BDLs */ + ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, + &bdl, ctx->cl_dev.bufsize, 1); + ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, + ctx->cl_dev.bufsize, ctx->cl_dev.frags); + + ctx->cl_dev.curr_spib_pos = 0; + ctx->cl_dev.dma_buffer_offset = 0; + init_waitqueue_head(&ctx->cl_dev.wait_queue); + + return ret; +} diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index c2d2878..e8ce136 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,7 +17,9 @@ #define __SKL_SST_DSP_H__ #include +#include "skl-sst-cldma.h" +struct sst_dsp; struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -113,6 +115,10 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); }; +void skl_cldma_process_intr(struct sst_dsp *ctx); +void skl_cldma_int_disable(struct sst_dsp *ctx); +int skl_cldma_prepare(struct sst_dsp *ctx); + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); -- cgit v0.10.2 From 6cb0033380ec6297589e68bfcf19aeda7ba95e99 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:43 +0530 Subject: ASoC: Intel: Skylake: Process code loader DMA interrupt The code loader DMA interrupt is received by main interrupt handler which dispatches it to cldma routines Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 313ca7c..94875b0 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -267,6 +267,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) result = IRQ_WAKE_THREAD; } + if (val & SKL_ADSPIS_CL_DMA) { + skl_cldma_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + spin_unlock(&ctx->spinlock); return result; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 94be6cb..bd5ac41 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -375,6 +375,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) u32 hipcie, hipct, hipcte; int ipc_irq = 0; + if (dsp->intr_status & SKL_ADSPIS_CL_DMA) + skl_cldma_process_intr(dsp); + /* Here we handle IPC interrupts only */ if (!(dsp->intr_status & SKL_ADSPIS_IPC)) return IRQ_NONE; -- cgit v0.10.2 From a750ba5f5a564732ed2be87de836a5a74f9cc586 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:44 +0530 Subject: ASoC: Intel: Skylake: Add SKL DSP initialization This adds the dsp and ipc initialization for the Skylake platform. It also requests firmware and uses code loader dma to load it. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index eff3e17..1fccb37 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,7 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index e8ce136..6bfcef4 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,10 +16,12 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +#include #include #include "skl-sst-cldma.h" struct sst_dsp; +struct skl_sst; struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -62,6 +64,11 @@ struct sst_dsp_device; #define SKL_ADSP_W1_SZ 0x1000 +#define SKL_FW_STS_MASK 0xf + +#define SKL_FW_INIT 0x1 +#define SKL_FW_RFW_START 0xf + #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1 @@ -106,6 +113,7 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); + unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); }; struct skl_dsp_loader_ops { @@ -130,5 +138,8 @@ int skl_dsp_sleep(struct sst_dsp *ctx); void skl_dsp_free(struct sst_dsp *dsp); int skl_dsp_boot(struct sst_dsp *ctx); +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index bd5ac41..c0d0928 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -496,6 +496,8 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) /* Disable IPC BUSY interrupt */ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_BUSY, 0); + + sst_ipc_fini(ipc); } int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c new file mode 100644 index 0000000..c18ea51 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst.c @@ -0,0 +1,280 @@ +/* + * skl-sst.c - HDA DSP library functions for SKL platform + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" +#include "skl-sst-ipc.h" + +#define SKL_BASEFW_TIMEOUT 300 +#define SKL_INIT_TIMEOUT 1000 + +/* Intel HD Audio SRAM Window 0*/ +#define SKL_ADSP_SRAM0_BASE 0x8000 + +/* Firmware status window */ +#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE +#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) + +#define SKL_INSTANCE_ID 0 +#define SKL_BASE_FW_MODULE_ID 0 + +static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) +{ + u32 cur_sts; + + cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; + + return (cur_sts == status); +} + +static int skl_transfer_firmware(struct sst_dsp *ctx, + const void *basefw, u32 base_fw_size) +{ + int ret = 0; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + if (ret < 0) + return ret; + + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_FW_STATUS, + SKL_FW_STS_MASK, + SKL_FW_RFW_START, + SKL_BASEFW_TIMEOUT, + "Firmware boot"); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_base_firmware(struct sst_dsp *ctx) +{ + int ret = 0, i; + const struct firmware *fw = NULL; + struct skl_sst *skl = ctx->thread_context; + u32 reg; + + ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + skl_dsp_disable_core(ctx); + return -EIO; + } + + /* enable Interrupt */ + skl_ipc_int_enable(ctx); + skl_ipc_op_int_enable(ctx); + + /* check ROM Status */ + for (i = SKL_INIT_TIMEOUT; i > 0; --i) { + if (skl_check_fw_status(ctx, SKL_FW_INIT)) { + dev_dbg(ctx->dev, + "ROM loaded, we can continue with FW loading\n"); + break; + } + mdelay(1); + } + if (!i) { + reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); + dev_err(ctx->dev, + "Timeout waiting for ROM init done, reg:0x%x\n", reg); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + ret = skl_transfer_firmware(ctx, fw->data, fw->size); + if (ret < 0) { + dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); + goto skl_load_base_firmware_failed; + } else { + ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0) { + dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + } + release_firmware(fw); + + return 0; + +skl_load_base_firmware_failed: + skl_dsp_disable_core(ctx); + release_firmware(fw); + return ret; +} + +static int skl_set_dsp_D0(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_load_base_firmware(ctx); + if (ret < 0) { + dev_err(ctx->dev, "unable to load firmware\n"); + return ret; + } + + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + + return ret; +} + +static int skl_set_dsp_D3(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_dxstate_info dx; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + mutex_lock(&ctx->mutex); + if (!is_skl_dsp_running(ctx)) { + mutex_unlock(&ctx->mutex); + return 0; + } + mutex_unlock(&ctx->mutex); + + dx.core_mask = SKL_DSP_CORE0_MASK; + dx.dx_mask = SKL_IPC_D3_MASK; + ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); + return ret; + } + + ret = skl_dsp_disable_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); + ret = -EIO; + } + skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); + + return ret; +} + +static unsigned int skl_get_errorcode(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); +} + +static struct skl_dsp_fw_ops skl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, +}; + +static struct sst_ops skl_ops = { + .irq_handler = skl_dsp_sst_interrupt, + .write = sst_shim32_write, + .read = sst_shim32_read, + .ram_read = sst_memcpy_fromio_32, + .ram_write = sst_memcpy_toio_32, + .free = skl_dsp_free, +}; + +static struct sst_dsp_device skl_dev = { + .thread = skl_dsp_irq_thread_handler, + .ops = &skl_ops, +}; + +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) +{ + struct skl_sst *skl; + struct sst_dsp *sst; + int ret; + + skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); + if (skl == NULL) + return -ENOMEM; + + skl->dev = dev; + skl_dev.thread_context = skl; + + skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); + if (!skl->dsp) { + dev_err(skl->dev, "%s: no device\n", __func__); + return -ENODEV; + } + + sst = skl->dsp; + + sst->addr.lpe = mmio_base; + sst->addr.shim = mmio_base; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), + SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + + sst->dsp_ops = dsp_ops; + sst->fw_ops = skl_fw_ops; + + ret = skl_ipc_init(dev, skl); + if (ret) + return ret; + + skl->boot_complete = false; + init_waitqueue_head(&skl->boot_wait); + + ret = skl_dsp_boot(sst); + if (ret < 0) { + dev_err(skl->dev, "Boot dsp core failed ret: %d", ret); + goto free_ipc; + } + + ret = skl_cldma_prepare(sst); + if (ret < 0) { + dev_err(dev, "CL dma prepare failed : %d", ret); + goto free_ipc; + } + + + ret = sst->fw_ops.load_fw(sst); + if (ret < 0) { + dev_err(dev, "Load base fw failed : %d", ret); + return ret; + } + + if (dsp) + *dsp = skl; + + return 0; + +free_ipc: + skl_ipc_free(&skl->ipc); + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +{ + skl_ipc_free(&ctx->ipc); + ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); + ctx->dsp->ops->free(ctx->dsp); +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake IPC driver"); -- cgit v0.10.2 From 28f3b6f113186ff69bdc5e63126ae7fd5e35a138 Mon Sep 17 00:00:00 2001 From: Omair M Abdullah Date: Fri, 10 Jul 2015 22:18:45 +0530 Subject: ASoC: Intel: Skylake: Print error code in IPC for SKL Signed-off-by: Omair M Abdullah Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index c0d0928..937a0a3 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -362,6 +362,12 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, break; } + if (reply != IPC_GLB_REPLY_SUCCESS) { + dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); + dev_err(ipc->dev, "FW Error Code: %u\n", + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + } + list_del(&msg->list); sst_ipc_tx_msg_reply_complete(ipc, msg); } -- cgit v0.10.2 From e40da86a37f64c73b810bc7a63d77c44dc61accb Mon Sep 17 00:00:00 2001 From: Tim Howe Date: Thu, 16 Jul 2015 14:51:40 -0500 Subject: ASoC: cs4349: Add support for Cirrus Logic CS4349 Signed-off-by: Tim Howe Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/cs4349.txt b/Documentation/devicetree/bindings/sound/cs4349.txt new file mode 100644 index 0000000..54c117b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4349.txt @@ -0,0 +1,19 @@ +CS4349 audio CODEC + +Required properties: + + - compatible : "cirrus,cs4349" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. + +Example: + +codec: cs4349@48 { + compatible = "cirrus,cs4349"; + reg = <0x48>; + reset-gpios = <&gpio 54 0>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..6a759d1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -53,6 +53,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_I2C if I2C select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C + select SND_SOC_CS4349 if I2C select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI select SND_SOC_DA7213 if I2C @@ -403,6 +404,11 @@ config SND_SOC_CS42XX8_I2C select SND_SOC_CS42XX8 select REGMAP_I2C +# Cirrus Logic CS4349 HiFi DAC +config SND_SOC_CS4349 + tristate "Cirrus Logic CS4349 CODEC" + depends on I2C + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..f19e8d2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -45,6 +45,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o +snd-soc-cs4349-objs := cs4349.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o @@ -232,6 +233,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o +obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c new file mode 100644 index 0000000..a8df8a74 --- /dev/null +++ b/sound/soc/codecs/cs4349.c @@ -0,0 +1,401 @@ +/* + * cs4349.c -- CS4349 ALSA Soc Audio driver + * + * Copyright 2015 Cirrus Logic, Inc. + * + * Authors: Tim Howe + * + * This program is free software; you can 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 +#include +#include +#include +#include +#include +#include "cs4349.h" + + +static const struct reg_default cs4349_reg_defaults[] = { + { 2, 0x00 }, /* r02 - Mode Control */ + { 3, 0x09 }, /* r03 - Volume, Mixing and Inversion Control */ + { 4, 0x81 }, /* r04 - Mute Control */ + { 5, 0x00 }, /* r05 - Channel A Volume Control */ + { 6, 0x00 }, /* r06 - Channel B Volume Control */ + { 7, 0xB1 }, /* r07 - Ramp and Filter Control */ + { 8, 0x1C }, /* r08 - Misc. Control */ +}; + +/* Private data for the CS4349 */ +struct cs4349_private { + struct regmap *regmap; + struct cs4349_platform_data pdata; + struct gpio_desc *reset_gpio; + unsigned int mode; + int rate; +}; + +static bool cs4349_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4349_CHIPID: + case CS4349_MODE: + case CS4349_VMI: + case CS4349_MUTE: + case CS4349_VOLA: + case CS4349_VOLB: + case CS4349_RMPFLT: + case CS4349_MISC: + return true; + default: + return false; + } +} + +static int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); + unsigned int fmt; + + fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; + + switch (fmt) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + cs4349->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); + int mode, fmt, ret; + + mode = snd_soc_read(codec, CS4349_MODE); + cs4349->rate = params_rate(params); + + switch (cs4349->mode) { + case SND_SOC_DAIFMT_I2S: + mode |= MODE_FORMAT(DIF_I2S); + break; + case SND_SOC_DAIFMT_LEFT_J: + mode |= MODE_FORMAT(DIF_LEFT_JST); + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + fmt = DIF_RGHT_JST16; + break; + case 24: + fmt = DIF_RGHT_JST24; + break; + default: + return -EINVAL; + } + mode |= MODE_FORMAT(fmt); + break; + default: + return -EINVAL; + } + + ret = snd_soc_write(codec, CS4349_MODE, mode); + if (ret < 0) + return ret; + + return 0; +} + +static int cs4349_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + int reg; + + reg = 0; + if (mute) + reg = MUTE_AB_MASK; + + return snd_soc_update_bits(codec, CS4349_MUTE, MUTE_AB_MASK, reg); +} + +static DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0); + +static const char * const chan_mix_texts[] = { + "Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB", + "BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL", + "MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono", + /*Normal == Channel A = Left, Channel B = Right*/ +}; + +static const char * const fm_texts[] = { + "Auto", "Single", "Double", "Quad", +}; + +static const char * const deemph_texts[] = { + "None", "44.1k", "48k", "32k", +}; + +static const char * const softr_zeroc_texts[] = { + "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", +}; + +static int deemph_values[] = { + 0, 4, 8, 12, +}; + +static int softr_zeroc_values[] = { + 0, 64, 128, 192, +}; + +static const struct soc_enum chan_mix_enum = + SOC_ENUM_SINGLE(CS4349_VMI, 0, + ARRAY_SIZE(chan_mix_texts), + chan_mix_texts); + +static const struct soc_enum fm_mode_enum = + SOC_ENUM_SINGLE(CS4349_MODE, 0, + ARRAY_SIZE(fm_texts), + fm_texts); + +static SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum, CS4349_MODE, 0, DEM_MASK, + deemph_texts, deemph_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum, CS4349_RMPFLT, 0, + SR_ZC_MASK, softr_zeroc_texts, + softr_zeroc_values); + +static const struct snd_kcontrol_new cs4349_snd_controls[] = { + SOC_DOUBLE_R_TLV("Master Playback Volume", + CS4349_VOLA, CS4349_VOLB, 0, 0xFF, 1, dig_tlv), + SOC_ENUM("Functional Mode", fm_mode_enum), + SOC_ENUM("De-Emphasis Control", deemph_enum), + SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum), + SOC_ENUM("Channel Mixer", chan_mix_enum), + SOC_SINGLE("VolA = VolB Switch", CS4349_VMI, 7, 1, 0), + SOC_SINGLE("InvertA Switch", CS4349_VMI, 6, 1, 0), + SOC_SINGLE("InvertB Switch", CS4349_VMI, 5, 1, 0), + SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE, 7, 1, 0), + SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE, 5, 1, 0), + SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT, 5, 1, 0), + SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT, 4, 1, 0), + SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT, 2, 1, 0), + SOC_SINGLE("Freeze Switch", CS4349_MISC, 5, 1, 0), + SOC_SINGLE("Popguard Switch", CS4349_MISC, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget cs4349_dapm_widgets[] = { + SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OutputA"), + SND_SOC_DAPM_OUTPUT("OutputB"), +}; + +static const struct snd_soc_dapm_route cs4349_routes[] = { + {"DAC Playback", NULL, "OutputA"}, + {"DAC Playback", NULL, "OutputB"}, + + {"OutputA", NULL, "HiFi DAC"}, + {"OutputB", NULL, "HiFi DAC"}, +}; + +#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000 + +static const struct snd_soc_dai_ops cs4349_dai_ops = { + .hw_params = cs4349_pcm_hw_params, + .set_fmt = cs4349_set_dai_fmt, + .digital_mute = cs4349_digital_mute, +}; + +static struct snd_soc_dai_driver cs4349_dai = { + .name = "cs4349_hifi", + .playback = { + .stream_name = "DAC Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS4349_PCM_RATES, + .formats = CS4349_PCM_FORMATS, + }, + .ops = &cs4349_dai_ops, + .symmetric_rates = 1, +}; + +static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { + .controls = cs4349_snd_controls, + .num_controls = ARRAY_SIZE(cs4349_snd_controls), + + .dapm_widgets = cs4349_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets), + .dapm_routes = cs4349_routes, + .num_dapm_routes = ARRAY_SIZE(cs4349_routes), +}; + +static struct regmap_config cs4349_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS4349_NUMREGS, + .reg_defaults = cs4349_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), + .readable_reg = cs4349_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs4349_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs4349_private *cs4349; + struct cs4349_platform_data *pdata = dev_get_platdata(&client->dev); + int ret = 0; + + cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL); + if (!cs4349) + return -ENOMEM; + + cs4349->regmap = devm_regmap_init_i2c(client, &cs4349_regmap); + if (IS_ERR(cs4349->regmap)) { + ret = PTR_ERR(cs4349->regmap); + dev_err(&client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) + cs4349->pdata = *pdata; + + /* Reset the Device */ + cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs4349->reset_gpio)) + return PTR_ERR(cs4349->reset_gpio); + + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + + i2c_set_clientdata(client, cs4349); + + return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4349, + &cs4349_dai, 1); +} + +static int cs4349_i2c_remove(struct i2c_client *client) +{ + struct cs4349_private *cs4349 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + + /* Hold down reset */ + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int cs4349_runtime_suspend(struct device *dev) +{ + struct cs4349_private *cs4349 = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + int ret; + + ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 1); + if (ret < 0) + return ret; + + regcache_cache_only(cs4349->regmap, true); + + /* Hold down reset */ + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + + return 0; +} + +static int cs4349_runtime_resume(struct device *dev) +{ + struct cs4349_private *cs4349 = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + int ret; + + ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 0); + if (ret < 0) + return ret; + + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + + regcache_cache_only(cs4349->regmap, false); + regcache_sync(cs4349->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs4349_runtime_pm = { + SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, + NULL) +}; + +static const struct of_device_id cs4349_of_match[] = { + { .compatible = "cirrus,cs4349", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, cs4349_of_match); + +static const struct i2c_device_id cs4349_i2c_id[] = { + {"cs4349", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id); + +static struct i2c_driver cs4349_i2c_driver = { + .driver = { + .name = "cs4349", + .owner = THIS_MODULE, + .of_match_table = cs4349_of_match, + }, + .id_table = cs4349_i2c_id, + .probe = cs4349_i2c_probe, + .remove = cs4349_i2c_remove, +}; + +module_i2c_driver(cs4349_i2c_driver); + +MODULE_AUTHOR("Tim Howe "); +MODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h new file mode 100644 index 0000000..3884a89 --- /dev/null +++ b/sound/soc/codecs/cs4349.h @@ -0,0 +1,146 @@ +/* + * ALSA SoC CS4349 codec driver + * + * Copyright 2015 Cirrus Logic, Inc. + * + * Author: Tim Howe + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef __CS4349_H__ +#define __CS4349_H__ + +struct cs4349_platform_data { + + /* GPIO for Reset */ + unsigned int gpio_nreset; + +}; + +/* CS4349 registers addresses */ +#define CS4349_CHIPID 0x01 /* Device and Rev ID, Read Only */ +#define CS4349_MODE 0x02 /* Mode Control */ +#define CS4349_VMI 0x03 /* Volume, Mixing, Inversion Control */ +#define CS4349_MUTE 0x04 /* Mute Control */ +#define CS4349_VOLA 0x05 /* DAC Channel A Volume Control */ +#define CS4349_VOLB 0x06 /* DAC Channel B Volume Control */ +#define CS4349_RMPFLT 0x07 /* Ramp and Filter Control */ +#define CS4349_MISC 0x08 /* Power Down,Freeze Control,Pop Stop*/ + +#define CS4349_FIRSTREG 0x01 +#define CS4349_LASTREG 0x08 +#define CS4349_NUMREGS (CS4349_LASTREG - CS4349_FIRSTREG + 1) +#define CS4349_I2C_INCR 0x80 + + +/* Device and Revision ID */ +#define CS4349_REVA 0xF0 /* Rev A */ +#define CS4349_REVB 0xF1 /* Rev B */ +#define CS4349_REVC2 0xFF /* Rev C2 */ + + +/* PDN_DONE Poll Maximum + * If soft ramp is set it will take much longer to power down + * the system. + */ +#define PDN_POLL_MAX 900 + + +/* Bitfield Definitions */ + +/* CS4349_MODE */ +/* (Digital Interface Format, De-Emphasis Control, Functional Mode */ +#define DIF2 (1 << 6) +#define DIF1 (1 << 5) +#define DIF0 (1 << 4) +#define DEM1 (1 << 3) +#define DEM0 (1 << 2) +#define FM1 (1 << 1) +#define DIF_LEFT_JST 0x00 +#define DIF_I2S 0x01 +#define DIF_RGHT_JST16 0x02 +#define DIF_RGHT_JST24 0x03 +#define DIF_TDM0 0x04 +#define DIF_TDM1 0x05 +#define DIF_TDM2 0x06 +#define DIF_TDM3 0x07 +#define DIF_MASK 0x70 +#define MODE_FORMAT(x) (((x)&7)<<4) +#define DEM_MASK 0x0C +#define NO_DEM 0x00 +#define DEM_441 0x04 +#define DEM_48K 0x08 +#define DEM_32K 0x0C +#define FM_AUTO 0x00 +#define FM_SNGL 0x01 +#define FM_DBL 0x02 +#define FM_QUAD 0x03 +#define FM_SNGL_MIN 30000 +#define FM_SNGL_MAX 54000 +#define FM_DBL_MAX 108000 +#define FM_QUAD_MAX 216000 +#define FM_MASK 0x03 + +/* CS4349_VMI (VMI = Volume, Mixing and Inversion Controls) */ +#define VOLBISA (1 << 7) +#define VOLAISB (1 << 7) +/* INVERT_A only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */ +#define INVERT_A (1 << 6) +/* INVERT_B only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */ +#define INVERT_B (1 << 5) +#define ATAPI3 (1 << 3) +#define ATAPI2 (1 << 2) +#define ATAPI1 (1 << 1) +#define ATAPI0 (1 << 0) +#define MUTEAB 0x00 +#define MUTEA_RIGHTB 0x01 +#define MUTEA_LEFTB 0x02 +#define MUTEA_SUMLRDIV2B 0x03 +#define RIGHTA_MUTEB 0x04 +#define RIGHTA_RIGHTB 0x05 +#define RIGHTA_LEFTB 0x06 +#define RIGHTA_SUMLRDIV2B 0x07 +#define LEFTA_MUTEB 0x08 +#define LEFTA_RIGHTB 0x09 /* Default */ +#define LEFTA_LEFTB 0x0A +#define LEFTA_SUMLRDIV2B 0x0B +#define SUMLRDIV2A_MUTEB 0x0C +#define SUMLRDIV2A_RIGHTB 0x0D +#define SUMLRDIV2A_LEFTB 0x0E +#define SUMLRDIV2_AB 0x0F +#define CHMIX_MASK 0x0F + +/* CS4349_MUTE */ +#define AUTOMUTE (1 << 7) +#define MUTEC_AB (1 << 5) +#define MUTE_A (1 << 4) +#define MUTE_B (1 << 3) +#define MUTE_AB_MASK 0x18 + +/* CS4349_RMPFLT (Ramp and Filter Control) */ +#define SCZ1 (1 << 7) +#define SCZ0 (1 << 6) +#define RMP_UP (1 << 5) +#define RMP_DN (1 << 4) +#define FILT_SEL (1 << 2) +#define IMMDT_CHNG 0x31 +#define ZEROCRSS 0x71 +#define SOFT_RMP 0xB1 +#define SFTRMP_ZEROCRSS 0xF1 +#define SR_ZC_MASK 0xC0 + +/* CS4349_MISC */ +#define PWR_DWN (1 << 7) +#define FREEZE (1 << 5) +#define POPG_EN (1 << 4) + +#endif /* __CS4349_H__ */ -- cgit v0.10.2 From 5e3cdaa20816dd2fe4dc17d06a9f0dae0abc930c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:07:42 +0000 Subject: ASoC: core: add snd_soc_of_parse_audio_prefix() Current ASoC can add name_prefix for DAPM, and it is necessary for route settings. This patch adds snd_soc_of_parse_audio_prefix() for this purpose. It will be used with snd_soc_of_parse_audio_routing(). Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf..75cd19c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1604,6 +1604,10 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *slots, unsigned int *slot_width); +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0..fd15d54 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3303,6 +3303,26 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) +{ + struct device_node *np = card->dev->of_node; + const char *str; + int ret; + + ret = of_property_read_string(np, propname, &str); + if (ret < 0) { + /* no prefix is not error */ + return; + } + + codec_conf->of_node = of_node; + codec_conf->name_prefix = str; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); + int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) { -- cgit v0.10.2 From 8019ff6cfc0440415fcfb6352c58c3951e6ab053 Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Thu, 16 Jul 2015 16:36:21 +0100 Subject: regmap: Use reg_sequence for multi_reg_write / register_patch Separate the functionality using sequences of register writes from the functions that take register defaults. This change renames the arguments in order to support the extension of reg_sequence to take an optional delay to be applied after any given register in a sequence is written. This avoids adding an int to all register defaults, which could substantially increase memory usage for regmaps with large default tables. This also updates all the clients of multi_reg_write/register_patch. Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b2b2849..873ddf9 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -136,7 +136,7 @@ struct regmap { /* if set, the HW registers are known to match map->reg_defaults */ bool no_sync_defaults; - struct reg_default *patch; + struct reg_sequence *patch; int patch_regs; /* if set, converts bulk rw to single rw */ diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04..2cbb450 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1743,7 +1743,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); * relative. The page register has been written if that was neccessary. */ static int _regmap_raw_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int ret; @@ -1800,12 +1800,12 @@ static unsigned int _regmap_register_page(struct regmap *map, } static int _regmap_range_multi_paged_reg_write(struct regmap *map, - struct reg_default *regs, + struct reg_sequence *regs, size_t num_regs) { int ret; int i, n; - struct reg_default *base; + struct reg_sequence *base; unsigned int this_page = 0; /* * the set of registers are not neccessarily in order, but @@ -1843,7 +1843,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, } static int _regmap_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int i; @@ -1895,8 +1895,8 @@ static int _regmap_multi_reg_write(struct regmap *map, struct regmap_range_node *range; range = _regmap_range_lookup(map, reg); if (range) { - size_t len = sizeof(struct reg_default)*num_regs; - struct reg_default *base = kmemdup(regs, len, + size_t len = sizeof(struct reg_sequence)*num_regs; + struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); if (!base) return -ENOMEM; @@ -1929,7 +1929,7 @@ static int _regmap_multi_reg_write(struct regmap *map, * A value of zero will be returned on success, a negative errno will be * returned in error cases. */ -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs) { int ret; @@ -1962,7 +1962,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write); * be returned in error cases. */ int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs) { int ret; @@ -2552,10 +2552,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete); * The caller must ensure that this function cannot be called * concurrently with either itself or regcache_sync(). */ -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs) { - struct reg_default *p; + struct reg_sequence *p; int ret; bool bypass; @@ -2564,7 +2564,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, return 0; p = krealloc(map->patch, - sizeof(struct reg_default) * (map->patch_regs + num_regs), + sizeof(struct reg_sequence) * (map->patch_regs + num_regs), GFP_KERNEL); if (p) { memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs)); diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index 2aaa3c8..00416f2 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -54,7 +54,7 @@ static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) } /* ADI recommended values for proper operation. */ -static const struct reg_default adv7511_fixed_registers[] = { +static const struct reg_sequence adv7511_fixed_registers[] = { { 0x98, 0x03 }, { 0x9a, 0xe0 }, { 0x9c, 0x30 }, diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e5d60ec..f5c9cf2 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input) gpiod_set_value(haptics->enable_gpio, 0); } -static const struct reg_default drv260x_lra_cal_regs[] = { +static const struct reg_sequence drv260x_lra_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_CTRL3, DRV260X_NG_THRESH_2 }, { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH }, }; -static const struct reg_default drv260x_lra_init_regs[] = { +static const struct reg_sequence drv260x_lra_init_regs[] = { { DRV260X_MODE, DRV260X_RT_PLAYBACK }, { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS | DRV260X_AUDIO_HAPTICS_FILTER_125HZ }, @@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = { { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, }; -static const struct reg_default drv260x_erm_cal_regs[] = { +static const struct reg_sequence drv260x_erm_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT }, { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0afaa33..924456e 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2665_init_regs[] = { +static const struct reg_sequence drv2665_init_regs[] = { { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT }, { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN }, }; diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index fc0fddf..047136a 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2667_init_regs[] = { +static const struct reg_sequence drv2667_init_regs[] = { { DRV2667_CTRL_2, 0 }, { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN }, { DRV2667_WV_SEQ_0, 1 }, { DRV2667_WV_SEQ_1, 0 } }; -static const struct reg_default drv2667_page1_init[] = { +static const struct reg_sequence drv2667_page1_init[] = { { DRV2667_RAM_HDR_SZ, 0x05 }, { DRV2667_RAM_START_HI, 0x80 }, { DRV2667_RAM_START_LO, 0x06 }, diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bebf58a..66d50be 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -392,7 +392,7 @@ err: * Register patch to some of the CODECs internal write sequences * to ensure a clean exit from the low power sleep state. */ -static const struct reg_default wm5110_sleep_patch[] = { +static const struct reg_sequence wm5110_sleep_patch[] = { { 0x337A, 0xC100 }, { 0x337B, 0x0041 }, { 0x3300, 0xA210 }, diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index c5265c1..583dc33 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -86,7 +86,7 @@ static const struct reg_default twl6040_defaults[] = { { 0x2E, 0x00 }, /* REG_STATUS (ro) */ }; -static struct reg_default twl6040_patch[] = { +static struct reg_sequence twl6040_patch[] = { /* * Select I2C bus access to dual access registers * Interrupt register is cleared on read diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index aeae6ec..423fb37 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -21,7 +21,7 @@ #define WM5102_NUM_AOD_ISR 2 #define WM5102_NUM_ISR 5 -static const struct reg_default wm5102_reva_patch[] = { +static const struct reg_sequence wm5102_reva_patch[] = { { 0x80, 0x0003 }, { 0x221, 0x0090 }, { 0x211, 0x0014 }, @@ -57,7 +57,7 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x80, 0x0000 }, }; -static const struct reg_default wm5102_revb_patch[] = { +static const struct reg_sequence wm5102_revb_patch[] = { { 0x19, 0x0001 }, { 0x80, 0x0003 }, { 0x081, 0xE022 }, @@ -80,7 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = { /* We use a function so we can use ARRAY_SIZE() */ int wm5102_patch(struct arizona *arizona) { - const struct reg_default *wm5102_patch; + const struct reg_sequence *wm5102_patch; int patch_size; switch (arizona->rev) { diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94..26ce14f 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -21,7 +21,7 @@ #define WM5110_NUM_AOD_ISR 2 #define WM5110_NUM_ISR 5 -static const struct reg_default wm5110_reva_patch[] = { +static const struct reg_sequence wm5110_reva_patch[] = { { 0x80, 0x3 }, { 0x44, 0x20 }, { 0x45, 0x40 }, @@ -134,7 +134,7 @@ static const struct reg_default wm5110_reva_patch[] = { { 0x209, 0x002A }, }; -static const struct reg_default wm5110_revb_patch[] = { +static const struct reg_sequence wm5110_revb_patch[] = { { 0x80, 0x3 }, { 0x36e, 0x0210 }, { 0x370, 0x0210 }, @@ -224,7 +224,7 @@ static const struct reg_default wm5110_revb_patch[] = { { 0x80, 0x0 }, }; -static const struct reg_default wm5110_revd_patch[] = { +static const struct reg_sequence wm5110_revd_patch[] = { { 0x80, 0x3 }, { 0x80, 0x3 }, { 0x393, 0x27 }, diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 53ae5af..0f4169a 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -243,21 +243,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif -static const struct reg_default wm8994_revc_patch[] = { +static const struct reg_sequence wm8994_revc_patch[] = { { 0x102, 0x3 }, { 0x56, 0x3 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm8958_reva_patch[] = { +static const struct reg_sequence wm8958_reva_patch[] = { { 0x102, 0x3 }, { 0xcb, 0x81 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm1811_reva_patch[] = { +static const struct reg_sequence wm1811_reva_patch[] = { { 0x102, 0x3 }, { 0x56, 0xc07 }, { 0x5d, 0x7e }, @@ -326,7 +326,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata; struct regmap_config *regmap_config; - const struct reg_default *regmap_patch = NULL; + const struct reg_sequence *regmap_patch = NULL; const char *devname; int ret, i, patch_regs = 0; int pulls = 0; diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index c0c25d75..cab2c68 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -17,7 +17,7 @@ #include "arizona.h" -static const struct reg_default wm8997_reva_patch[] = { +static const struct reg_sequence wm8997_reva_patch[] = { { 0x80, 0x0003 }, { 0x214, 0x0008 }, { 0x458, 0x0000 }, diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea..c9ef2ec 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -50,6 +50,17 @@ struct reg_default { unsigned int def; }; +/** + * Register/value pairs for sequences of writes + * + * @reg: Register address. + * @def: Register value. + */ +struct reg_sequence { + unsigned int reg; + unsigned int def; +}; + #ifdef CONFIG_REGMAP enum regmap_endian { @@ -410,10 +421,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count); -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs); int regmap_raw_write_async(struct regmap *map, unsigned int reg, const void *val, size_t val_len); @@ -450,7 +461,7 @@ void regcache_mark_dirty(struct regmap *map); bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table); -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05e..5edd33f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; - struct reg_default dac_comp[] = { + struct reg_sequence dac_comp[] = { { 0x80, 0x3 }, { ARIZONA_DAC_COMP_1, 0 }, { ARIZONA_DAC_COMP_2, 0 }, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025..2813a1b 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -276,7 +276,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { }; /* Current and threshold powerup sequence Pg37 in datasheet */ -static const struct reg_default cs35l32_monitor_patch[] = { +static const struct reg_sequence cs35l32_monitor_patch[] = { { 0x00, 0x99 }, { 0x48, 0x17 }, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9..8b2d059 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1118,7 +1118,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { }; /* Current and threshold powerup sequence Pg37 */ -static const struct reg_default cs42l52_threshold_patch[] = { +static const struct reg_sequence cs42l52_threshold_patch[] = { { 0x00, 0x99 }, { 0x3E, 0xBA }, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5..bf0fb3d 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { #if IS_ENABLED(CONFIG_I2C) -static struct reg_default da7210_regmap_i2c_patch[] = { +static struct reg_sequence da7210_regmap_i2c_patch[] = { /* System controller master disable */ { DA7210_STARTUP1, 0x00 }, @@ -1269,7 +1269,7 @@ static struct i2c_driver da7210_i2c_driver = { #if defined(CONFIG_SPI_MASTER) -static struct reg_default da7210_regmap_spi_patch[] = { +static struct reg_sequence da7210_regmap_spi_patch[] = { /* Dummy read to give two pulses over nCS for SPI */ { DA7210_AUX2, 0x00 }, { DA7210_AUX2, 0x00 }, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..1ed1f88 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5640_PR_BASE + 0x3d, 0x3600}, {RT5640_PR_BASE + 0x12, 0x0aa8}, {RT5640_PR_BASE + 0x14, 0x0aaa}, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..c0f4be4 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x3d, 0x3600}, {RT5645_PR_BASE + 0x1c, 0xfd20}, {RT5645_PR_BASE + 0x20, 0x611f}, @@ -63,7 +63,7 @@ static const struct reg_default init_list[] = { }; #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5650_init_list[] = { +static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, }; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..db9b866 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = { .window_len = 0x1, }, }; -static struct reg_default init_list[] = { +static struct reg_sequence init_list[] = { {RT5651_PR_BASE + 0x3d, 0x3e00}, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..462a91f 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { { RT5670_PR_BASE + 0x14, 0x9a8a }, { RT5670_PR_BASE + 0x38, 0x3ba1 }, { RT5670_PR_BASE + 0x3d, 0x3640 }, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..b897752 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5677_ASRC_12, 0x0018}, {RT5677_PR_BASE + 0x3d, 0x364d}, {RT5677_PR_BASE + 0x17, 0x4fc0}, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a7cf19b..83ae1eb 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1668,7 +1668,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); -static const struct reg_default aic3007_class_d[] = { +static const struct reg_sequence aic3007_class_d[] = { /* Class-D speaker driver init; datasheet p. 46 */ { AIC3X_PAGE_SELECT, 0x0D }, { 0xD, 0x0D }, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c830832..6c60792 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -897,7 +897,7 @@ static bool wm2200_readable_register(struct device *dev, unsigned int reg) } } -static const struct reg_default wm2200_reva_patch[] = { +static const struct reg_sequence wm2200_reva_patch[] = { { 0x07, 0x0003 }, { 0x102, 0x0200 }, { 0x203, 0x0084 }, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd8..26d79bb 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1247,7 +1247,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const struct reg_default wm5100_reva_patches[] = { +static const struct reg_sequence wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd..05492e8 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3495,7 +3495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { }; /* Improve power consumption for IN4 DC measurement mode */ -static const struct reg_default wm8962_dc_measure[] = { +static const struct reg_sequence wm8962_dc_measure[] = { { 0xfd, 0x1 }, { 0xcc, 0x40 }, { 0xfd, 0 }, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db86..52ec64d 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) #endif /* Tune DC servo configuration */ -static struct reg_default wm8993_regmap_patch[] = { +static struct reg_sequence wm8993_regmap_patch[] = { { 0x44, 3 }, { 0x56, 3 }, { 0x44, 0 }, -- cgit v0.10.2 From b7419dd73606118b8797d49b53a9fbe2e2dfa863 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:05 +0000 Subject: ASoC: rsrc-card: use snd_soc_of_parse_audio_route/prefix for routing using common audio routing path method makes sense. Let's use snd_soc_of_parse_audio_route/prefix. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index c641550..962748a 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -6,6 +6,7 @@ Required properties: - compatible : "renesas,rsrc-card," Examples with soctypes are: + - "renesas,rsrc-card" - "renesas,rsrc-card,lager" - "renesas,rsrc-card,koelsch" Optional properties: @@ -29,6 +30,12 @@ Optional subnode properties: - frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. - convert-rate : platform specified sampling rate convert +- audio-prefix : see audio-routing +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources. + use audio-prefix if some components is using same sink/sources naming. + it can be used if compatible was "renesas,rsrc-card"; Required CPU/CODEC subnodes properties: diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 84e9357..d61db9c 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -41,6 +41,7 @@ static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = { static const struct of_device_id rsrc_card_of_match[] = { { .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 }, { .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 }, + { .compatible = "renesas,rsrc-card", }, {}, }; MODULE_DEVICE_TABLE(of, rsrc_card_of_match); @@ -242,8 +243,15 @@ static int rsrc_card_parse_links(struct device_node *np, snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); /* additional name prefix */ - priv->codec_conf.of_node = dai_link->codec_of_node; - priv->codec_conf.name_prefix = of_data->prefix; + if (of_data) { + priv->codec_conf.of_node = dai_link->codec_of_node; + priv->codec_conf.name_prefix = of_data->prefix; + } else { + snd_soc_of_parse_audio_prefix(&priv->snd_card, + &priv->codec_conf, + dai_link->codec_of_node, + "audio-prefix"); + } /* set dai_name */ snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s", @@ -361,8 +369,14 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.num_links = num; priv->snd_card.codec_conf = &priv->codec_conf; priv->snd_card.num_configs = 1; - priv->snd_card.of_dapm_routes = of_data->routes; - priv->snd_card.num_of_dapm_routes = of_data->num_routes; + + if (of_data) { + priv->snd_card.of_dapm_routes = of_data->routes; + priv->snd_card.num_of_dapm_routes = of_data->num_routes; + } else { + snd_soc_of_parse_audio_routing(&priv->snd_card, + "audio-routing"); + } /* Parse the card name from DT */ snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); -- cgit v0.10.2 From afa700729646761f58cc068d86a37e09a70e4cf6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:24 +0000 Subject: ASoC: rsnd: remove unnecessary 'out of memory' message from SSI Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2fbe59f..d45b9a7 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -770,10 +770,8 @@ int rsnd_ssi_probe(struct platform_device *pdev, */ nr = info->ssi_info_nr; ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); - if (!ssi) { - dev_err(dev, "SSI allocate failed\n"); + if (!ssi) return -ENOMEM; - } priv->ssi = ssi; priv->ssi_nr = nr; -- cgit v0.10.2 From 33363f7a18f3baaa04b678aac8819c43296c8c9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:44 +0000 Subject: ASoC: rsnd: remove unnecessary 'out of memory' message from SRC Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c61c171..37927ca 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -1047,10 +1047,8 @@ int rsnd_src_probe(struct platform_device *pdev, return 0; src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); - if (!src) { - dev_err(dev, "SRC allocate failed\n"); + if (!src) return -ENOMEM; - } priv->src_nr = nr; priv->src = src; -- cgit v0.10.2 From 6abcae32ea68899bfd4b770433860a71f8c3500b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:07 +0000 Subject: ASoC: rsnd: remove unnecessary 'out of memory' message from DVC Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 36fc020..dbf0da6 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -354,10 +354,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, } dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); - if (!dvc) { - dev_err(dev, "CMD allocate failed\n"); + if (!dvc) return -ENOMEM; - } priv->dvc_nr = nr; priv->dvc = dvc; -- cgit v0.10.2 From cdde84d10d3cb4d35051bc5fdb268f6faf33d1c8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:27 +0000 Subject: ASoC: rsnd: rename BUSIF_DALIGN to SSI_BUSIF_DALIGN based on datasheet Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 48f704b..9dc1968 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -216,7 +216,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(BUSIF_DALIGN, 0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f729646..f49b0cb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -136,7 +136,7 @@ enum rsnd_reg { #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 -#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 +#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22 #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 37927ca..3f6f4df 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,7 +189,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, val |= 0x76543210 & ~mask; break; } - rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val); + rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); } -- cgit v0.10.2 From efa991dc9143815179fd55a88e846cc39792608c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:47 +0000 Subject: ASoC: rsnd: rename INT_ENABLE to SSI_INT_ENABLE based on datasheet Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 9dc1968..5d3592df 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -218,7 +218,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), + RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; struct rsnd_regmap_field_conf conf_scu[] = { RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f49b0cb..9ecd151 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -119,7 +119,7 @@ enum rsnd_reg { #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 #define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 #define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 -#define RSND_REG_INT_ENABLE RSND_REG_SHARE05 +#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05 #define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 #define RSND_REG_SRC_BSISR RSND_REG_SHARE07 #define RSND_REG_DIV_EN RSND_REG_SHARE08 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3f6f4df..9e11f73 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -215,10 +215,9 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) return 0; /* enable SSI interrupt if Gen2 */ - if (rsnd_ssi_is_dma_mode(ssi_mod)) - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000); - else - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, + rsnd_ssi_is_dma_mode(ssi_mod) ? + 0x0e000000 : 0x0f000000); return 0; } @@ -231,7 +230,7 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) return 0; /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); return 0; } -- cgit v0.10.2 From a48e3f9747fd62b385221a892cd4726b82dacd11 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:04 +0000 Subject: ASoC: rsnd: fixup each module counter on __rsnd_mod_call() '5451ea443b ("ASoC: rsnd: count each mod (SSI/SRC/DVC)")' counts each module's callback status, but counts 1st callback only. This patch fixup it. Otherwise, multi-called function will be trouble Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f1e5920..d44bfb7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -242,9 +242,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (val == __rsnd_mod_call_##func) { \ called = 1; \ ret = (mod)->ops->func(mod, io, param); \ - mod->status = (mod->status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ } \ + mod->status = (mod->status & ~mask) + \ + (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d] 0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status, \ called ? #func : ""); \ -- cgit v0.10.2 From 1a1bf58aafd09b3cb148eead3d709e2d7974a1f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:22 +0000 Subject: ASoC: rsnd: add workaround for SRC sync convert + DVC We couldn't use SRC sync convert mode together with DVC, but we can use workaround for it. This patch adds workaround and can use SRC sync convert + DVC Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 9e11f73..38d0aba 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -616,6 +616,14 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) int_val = 0; } + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + sys_int_val = sys_int_val & 0xffff; + rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); @@ -631,11 +639,22 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) { - u32 val = OUF_SRC(rsnd_mod_id(mod)); + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val0, val1; bool ret = false; - if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) || - (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) { + val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); + + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + val0 = val0 & 0xffff; + + if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || + (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) { struct rsnd_src *src = rsnd_mod_to_src(mod); src->err++; @@ -651,7 +670,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) static int _rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val; + + /* + * WORKAROUND + * + * Enable SRC output if you want to use sync convert together with DVC + */ + val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ? + 0x01 : 0x11; rsnd_mod_write(mod, SRC_CTRL, val); @@ -921,13 +949,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, return 0; /* - * We can't use SRC sync convert - * if it has DVC - */ - if (rsnd_io_to_mod_dvc(io)) - return 0; - - /* * enable sync convert */ ret = rsnd_kctrl_new_s(mod, io, rtd, -- cgit v0.10.2 From 72413c107e81386a7da438bcf888ee2af5d3b72f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:43 +0000 Subject: ASoC: rsnd: rsnd_mod_id() return -1 if mod was NULL enabling to use same method for exception case is useful. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9ecd151..46eb4da 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -316,7 +316,7 @@ struct rsnd_mod { #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_to_dma(mod) (&(mod)->dma) -#define rsnd_mod_id(mod) ((mod)->id) +#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) #define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) -- cgit v0.10.2 From 4f35fabaa30b116d549d95fe7dae907510c71862 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:11:02 +0000 Subject: ASoC: rsnd: move DVC specific macro into dvc.c rsnd_dvc_nr() is used only from dvc.c Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index dbf0da6..8a61aa3 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -24,6 +24,7 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ }; +#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 46eb4da..8f793f0 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -579,7 +579,4 @@ void rsnd_dvc_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) - - #endif -- cgit v0.10.2 From da599fd34b1f2f14f2c387e6b3a909f9ff519c8a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:11:21 +0000 Subject: ASoC: rsnd: move SRC specific macro into src.c rsnd_src_nr() is used only from src.c Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 8f793f0..c8d2029 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -554,8 +554,6 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); -#define rsnd_src_nr(priv) ((priv)->src_nr) - /* * R-Car SSI */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 38d0aba..0b06ac8 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -30,6 +30,7 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") -- cgit v0.10.2 From 636e4bad5cca947839c09d3e13ad6feeb7fa45da Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:00 +0000 Subject: ASoC: rsnd: dvc: make sure DVC soft reset Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxRSR (Software reset Register) is one of them. These xxxRSR need be set to 1 to 0 when software reset. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_dvc_soft_reset() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 8a61aa3..24d0763 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -64,6 +64,12 @@ static const char * const dvc_ramp_rate[] = { "0.125 dB/8192 steps", /* 10111 */ }; +static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, DVC_SWRSR, 0); + rsnd_mod_write(mod, DVC_SWRSR, 1); +} + static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -160,15 +166,14 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, rsnd_mod_hw_start(dvc_mod); + rsnd_dvc_soft_reset(dvc_mod); + /* * fixme * it doesn't support CTU/MIX */ rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]); - rsnd_mod_write(dvc_mod, DVC_SWRSR, 0); - rsnd_mod_write(dvc_mod, DVC_SWRSR, 1); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io)); -- cgit v0.10.2 From 379febfd2e30ec8db5baccd9f9403bf650c6afa1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:18 +0000 Subject: ASoC: rsnd: src: make sure SRC soft reset Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxRSR (Software reset Register) is one of them. These xxxRSR need be set to 1 to 0 when software reset. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_src_soft_reset() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 0b06ac8..74ab644 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -118,6 +118,12 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ +static void rsnd_src_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -294,10 +300,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, if (convert_rate) fsrate = 0x0400000 / convert_rate * runtime->rate; - /* set/clear soft reset */ - rsnd_mod_write(mod, SRC_SWRSR, 0); - rsnd_mod_write(mod, SRC_SWRSR, 1); - /* Set channel number and output bit length */ rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); @@ -358,6 +360,8 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_mod_hw_start(mod); + rsnd_src_soft_reset(mod); + src->err = 0; /* reset sync convert_rate */ -- cgit v0.10.2 From d6f8d5b4422a5a391c02df97af9ef7da5a929d71 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:36 +0000 Subject: ASoC: rsnd: enable module multi connection '8a4e379b54f8("ASoC: rsnd: remove io from rsnd_mod")' removed mod/io relationship. rsnd_dai_connect() mod/io check is no longer needed Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d44bfb7..ff4f15a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -277,16 +277,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, if (!mod) return -EIO; - if (io->mod[mod->type]) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "%s[%d] is not empty\n", - rsnd_mod_name(mod), - rsnd_mod_id(mod)); - return -EIO; - } - io->mod[mod->type] = mod; return 0; -- cgit v0.10.2 From c8cf15f64f8ddb3169987c2f26df3341b8556296 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:52 +0000 Subject: ASoC: rsnd: rename rsnd_path_parse/break() into add/remove parse/break is a little ambiguous/confusable name for rsnd module path. Especially for CTU/MIX support. It was renamed to add/remove Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ff4f15a..93fed50 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -507,7 +507,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; -#define rsnd_path_parse(priv, io, type) \ +#define rsnd_path_add(priv, io, type) \ ({ \ struct rsnd_mod *mod; \ int ret = 0; \ @@ -523,7 +523,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { ret; \ }) -#define rsnd_path_break(priv, io, type) \ +#define rsnd_path_remove(priv, io, type) \ { \ struct rsnd_mod *mod; \ int id = -1; \ @@ -555,17 +555,17 @@ static int rsnd_path_init(struct rsnd_priv *priv, */ /* SRC */ - ret = rsnd_path_parse(priv, io, src); + ret = rsnd_path_add(priv, io, src); if (ret < 0) return ret; /* SSI */ - ret = rsnd_path_parse(priv, io, ssi); + ret = rsnd_path_add(priv, io, ssi); if (ret < 0) return ret; /* DVC */ - ret = rsnd_path_parse(priv, io, dvc); + ret = rsnd_path_add(priv, io, dvc); if (ret < 0) return ret; @@ -1023,8 +1023,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, /* * remove SRC/DVC from DAI, */ - rsnd_path_break(priv, io, src); - rsnd_path_break(priv, io, dvc); + rsnd_path_remove(priv, io, src); + rsnd_path_remove(priv, io, dvc); /* * fallback -- cgit v0.10.2 From e2c08416196bd10a6575057fdd1347a307ce3a15 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:10 +0000 Subject: ASoC: rsnd: add rsnd_path_parse() for CTU/MIX/DVC route setting Current sound data route settings is done in dvc.c, and it doesn't care about CTU/MIX at this poinnt, but we need to care about these. OTOH, rsnd driver already has rsnd_path_xxx() functions for data path which are good match for CTU/MIX/DVC path selectio. This patch adds new rsnd_path_parse() to select sound data route which will care about CTU/MIX/DVC path. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 93fed50..cb82067 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -537,6 +537,28 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { } \ } +void rsnd_path_parse(struct rsnd_priv *priv, + struct rsnd_dai_stream *io) +{ + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + int src_id = rsnd_mod_id(src); + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + /* Gen1 is not supported */ + if (rsnd_is_gen1(priv)) + return; + + rsnd_mod_write(dvc, CMD_ROUTE_SLCT, path[src_id]); +} + static int rsnd_path_init(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 24d0763..9392507 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -142,48 +142,26 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, return 0; } -static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, +static int rsnd_dvc_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct device *dev = rsnd_priv_to_dev(priv); - int dvc_id = rsnd_mod_id(dvc_mod); - int src_id = rsnd_mod_id(src_mod); - u32 route[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; - - if (src_id >= ARRAY_SIZE(route)) { - dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id); - return -EINVAL; - } - - rsnd_mod_hw_start(dvc_mod); + rsnd_mod_hw_start(mod); - rsnd_dvc_soft_reset(dvc_mod); + rsnd_dvc_soft_reset(mod); - /* - * fixme - * it doesn't support CTU/MIX - */ - rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]); + rsnd_path_parse(priv, io); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); + rsnd_mod_write(mod, DVC_DVUIR, 1); - rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io)); + rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); /* ch0/ch1 Volume */ - rsnd_dvc_volume_update(io, dvc_mod); + rsnd_dvc_volume_update(io, mod); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); + rsnd_mod_write(mod, DVC_DVUIR, 0); - rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io); + rsnd_adg_set_cmd_timsel_gen2(mod, io); return 0; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c8d2029..6a87757 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,6 +170,8 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +void rsnd_path_parse(struct rsnd_priv *priv, + struct rsnd_dai_stream *io); /* * R-Car DMA -- cgit v0.10.2 From 3bb3d363e50d371289f0bd63b48da771ea807c02 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:29 +0000 Subject: ASoC: rsnd: add rsnd_dvc_initialize_lock/unlock() Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxIR (Initialization Register) is one of them. These xxxIR need be set to 1 during initialization. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_dvc_initialize_lock/unlock() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 9392507..343d446 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -70,6 +70,13 @@ static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_SWRSR, 1); } +#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1) +#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0) +static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, DVC_DVUIR, enable); +} + static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -150,17 +157,15 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_dvc_soft_reset(mod); - rsnd_path_parse(priv, io); + rsnd_dvc_initialize_lock(mod); - rsnd_mod_write(mod, DVC_DVUIR, 1); + rsnd_path_parse(priv, io); rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); - rsnd_mod_write(mod, DVC_DVUIR, 0); - rsnd_adg_set_cmd_timsel_gen2(mod, io); return 0; @@ -179,6 +184,8 @@ static int rsnd_dvc_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_dvc_initialize_unlock(mod); + rsnd_mod_write(mod, CMD_CTRL, 0x10); return 0; -- cgit v0.10.2 From d1ade514e84ea55cba999edb04cb88daa4da94b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:47 +0000 Subject: ASoC: rsnd: add rsnd_src_initialize_lock/unlock() Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxIR (Initialization Register) is one of them. These xxxIR need be set to 1 during initialization. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_src_initialize_lock/unlock() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 74ab644..b3d965e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -124,6 +124,14 @@ static void rsnd_src_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, SRC_SWRSR, 1); } + +#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) +#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) +static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, SRC_SRCIR, enable); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -362,17 +370,13 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_src_soft_reset(mod); + rsnd_src_initialize_lock(mod); + src->err = 0; /* reset sync convert_rate */ src->sync.val = 0; - /* - * Initialize the operation of the SRC internal circuits - * see rsnd_src_start() - */ - rsnd_mod_write(mod, SRC_SRCIR, 1); - return 0; } @@ -399,11 +403,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod, static int rsnd_src_start(struct rsnd_mod *mod) { - /* - * Cancel the initialization and operate the SRC function - * see rsnd_src_init() - */ - rsnd_mod_write(mod, SRC_SRCIR, 0); + rsnd_src_initialize_unlock(mod); return 0; } -- cgit v0.10.2 From 3023b384d0c9da49028131b91fe64b24b5b84e6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:05 +0000 Subject: ASoC: rsnd: tidyup ADINR function name Renesas sound IP (= SSIU/SRC/CTU/MIX/DVC) have ADINR (= Audio Information Register), but some of them (= SSIU/SRC/DVC) are for audio data bits, some of them (= CTU/MIX) are for audio data channels. Current rsnd driver is supporting SSIU/SRC/DVC, and these ADINR were for bits. This patch rename rsnd_get_adinr() to rsnd_get_adinr_bit(), and we will have rsnd_get_adinr_chan() for CTU/MIX. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cb82067..0ca6d02 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -203,9 +203,9 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) } /* - * settting function + * ADINR function */ -u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 343d446..d06e4ee 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -161,7 +161,7 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_path_parse(priv, io); - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); + rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6a87757..224a4a9 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -169,7 +169,7 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); -u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index b3d965e..c45da61 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,7 +189,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, u32 mask = ~0; rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, - rsnd_get_adinr(ssi_mod, io)); + rsnd_get_adinr_bit(ssi_mod, io)); rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); @@ -309,7 +309,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, fsrate = 0x0400000 / convert_rate * runtime->rate; /* Set channel number and output bit length */ - rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); + rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); /* Enable the initial value of IFS */ if (fsrate) { -- cgit v0.10.2 From bfe1360d79210f9c1d330a07c26a8d5cb202159d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:29 +0000 Subject: ASoC: rsnd: add rsnd_get_adinr_chan() Current rsnd driver has rsnd_get_adinr_bit() to get bit settings for ADINR (= Audio Information Register) of SSIU/SRC/DVC. This patch adds rsnd_get_adinr_chan() to get channel settings for ADINR (= Audio Information Register) of CTU/MIX. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0ca6d02..a3637b9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -227,6 +227,28 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return adinr; } +u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 chan = runtime->channels; + + switch (chan) { + case 1: + case 2: + case 4: + case 6: + case 8: + break; + default: + dev_warn(dev, "not supported channel\n"); + chan = 0; + break; + } + + return chan; +} /* * rsnd_dai functions */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 224a4a9..1296b35 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,6 +170,7 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); -- cgit v0.10.2 From 4689032b11d1af10e5eb755eb575f9761a455a72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:47 +0000 Subject: ASoC: rsnd: tidyup data align position Sound L/R order of SSI is different from Linux sound data order. So current rsnd driver is using DALIGN (= data align) to exchange data align on SSIU. OTOH, CMD/SRC/SSIU have DALIGN register. Now inverted sound volume will be exchanged if user used volume control on DVC. Because SSIU which exchanges data align is located after DVC. MEM -> SRC -> DVC -> SSI This patch exchanges data align SRC if possible Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a3637b9..0f9323f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -249,6 +249,42 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return chan; } + +/* + * DALIGN function + */ +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *target = src ? src : ssi; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 val = 0x76543210; + u32 mask = ~0; + + mask <<= runtime->channels * 4; + val = val & mask; + + switch (runtime->sample_bits) { + case 16: + val |= 0x67452301 & ~mask; + break; + case 32: + val |= 0x76543210 & ~mask; + break; + } + + /* + * exchange channeles on SRC if possible, + * otherwise, R/L volume settings on DVC + * changes inverted channels + */ + if (mod == target) + return val; + else + return 0x76543210; +} + /* * rsnd_dai functions */ diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 5d3592df..a2d5df4 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -222,6 +222,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, }; struct rsnd_regmap_field_conf conf_scu[] = { RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), + RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 1296b35..6c10a8b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -99,6 +99,7 @@ enum rsnd_reg { RSND_REG_SHARE26, RSND_REG_SHARE27, RSND_REG_SHARE28, + RSND_REG_SHARE29, RSND_REG_MAX, }; @@ -143,6 +144,7 @@ enum rsnd_reg { #define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 #define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 #define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 +#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29 struct rsnd_of_data; struct rsnd_priv; @@ -171,6 +173,7 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c45da61..89a18e1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -148,7 +148,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); int ssi_id = rsnd_mod_id(ssi_mod); /* @@ -185,27 +184,14 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, * DMA settings for SSIU */ if (use_busif) { - u32 val = 0x76543210; - u32 mask = ~0; + u32 val = rsnd_get_dalign(ssi_mod, io); rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(ssi_mod, io)); rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); - mask <<= runtime->channels * 4; - val = val & mask; - - switch (runtime->sample_bits) { - case 16: - val |= 0x67452301 & ~mask; - break; - case 32: - val |= 0x76543210 & ~mask; - break; - } rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); - } return 0; @@ -678,6 +664,10 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; + val = rsnd_get_dalign(mod, io); + + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); + /* * WORKAROUND * -- cgit v0.10.2 From 84e95355602c59865be8a3bd18cd2f0b3863b4cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:10 +0000 Subject: ASoC: rsnd: show debug message for SSI/SRC/DVC connection It can help for connection debug Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0f9323f..8919afa 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -332,11 +332,18 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) static int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + if (!mod) return -EIO; io->mod[mod->type] = mod; + dev_dbg(dev, "%s[%d] is connected to io (%s)\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_io_is_play(io) ? "Playback" : "Capture"); + return 0; } -- cgit v0.10.2 From 98d358af07aa6fc4cd6cdfd3256ab792eb3675cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:27 +0000 Subject: ASoC: rsnd: tidyup rsnd_dma_ops definition place rsnd_dma_ops is used only from dma.c, rsnd.h doesn't need it. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index d306e29..9431061 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -27,6 +27,14 @@ struct rsnd_dma_ctrl { int dmapp_num; }; +struct rsnd_dma_ops { + void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); + void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); + int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); + void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); +}; + #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) /* diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6c10a8b..705e66f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -181,13 +181,6 @@ void rsnd_path_parse(struct rsnd_priv *priv, * R-Car DMA */ struct rsnd_dma; -struct rsnd_dma_ops { - void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); - void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -}; struct rsnd_dmaen { struct dma_chan *chan; -- cgit v0.10.2 From 9469b8b6092d347ef8a5fa9d2d7dde4c857a0994 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:47 +0000 Subject: ASoC: rsnd: check the Gen1 at the beginning of DVC probe DVC doesn't support Gen1, check it beginning of probe Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d06e4ee..5779638 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -332,18 +332,18 @@ int rsnd_dvc_probe(struct platform_device *pdev, char name[RSND_DVC_NAME_SIZE]; int i, nr, ret; - rsnd_of_parse_dvc(pdev, of_data, priv); - - nr = info->dvc_info_nr; - if (!nr) - return 0; - /* This driver doesn't support Gen1 at this point */ if (rsnd_is_gen1(priv)) { dev_warn(dev, "CMD is not supported on Gen1\n"); return -EINVAL; } + rsnd_of_parse_dvc(pdev, of_data, priv); + + nr = info->dvc_info_nr; + if (!nr) + return 0; + dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); if (!dvc) return -ENOMEM; -- cgit v0.10.2 From ddea1b2e83c379840aa54fadc587e418cf986ccb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:03 +0000 Subject: ASoC: rsnd: dma: add DMA name on .ops Current rsnd driver is using Audio DMAC (via DMAEngine) and Audio DMAC peri peri (via original method), and usage of these DMAC are different. Indicates its naming is useful for debugging. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 9431061..a175863 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -28,6 +28,7 @@ struct rsnd_dma_ctrl { }; struct rsnd_dma_ops { + char *name; void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, @@ -190,7 +191,8 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "dma : %pad -> %pad\n", + dev_dbg(dev, "%s %pad -> %pad\n", + dma->ops->name, &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); @@ -223,6 +225,7 @@ static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) } static struct rsnd_dma_ops rsnd_dmaen_ops = { + .name = "audmac", .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .init = rsnd_dmaen_init, @@ -368,6 +371,7 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io, } static struct rsnd_dma_ops rsnd_dmapp_ops = { + .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, .init = rsnd_dmapp_init, @@ -580,6 +584,7 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) struct rsnd_mod *mod_to; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); int is_play = rsnd_io_is_play(io); /* @@ -606,6 +611,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) if (rsnd_is_gen1(priv)) dma->ops = &rsnd_dmaen_ops; + dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", + dma->ops->name, + rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), + rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + return dma->ops->init(io, dma, id, mod_from, mod_to); } -- cgit v0.10.2 From 5cbbadd3d507eeb7711266e3932f4c427cbcbd61 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:19 +0000 Subject: ASoC: rsnd: add rsnd_io_to_mod() Sometimes we would like to get each module directly, especially data path searching. this patch adds rsnd_io_to_mod() macro, and existing rsnd_io_to_mod_xxx() use it. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 705e66f..5f5b8b1 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -348,9 +348,10 @@ struct rsnd_dai_stream { int byte_per_period; int next_period_byte; }; -#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI]) -#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC]) -#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC]) +#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) +#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) +#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) -- cgit v0.10.2 From 78edead4494219640d9fdf37d76beae24f79de9e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:37 +0000 Subject: ASoC: rsnd: tidyup SRC position on each code This is cleanup for CTU/MIX support Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index f1b4451..3a274fd 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8919afa..e20d8ea 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -641,13 +641,13 @@ static int rsnd_path_init(struct rsnd_priv *priv, * using fixed path. */ - /* SRC */ - ret = rsnd_path_add(priv, io, src); + /* SSI */ + ret = rsnd_path_add(priv, io, ssi); if (ret < 0) return ret; - /* SSI */ - ret = rsnd_path_add(priv, io, ssi); + /* SRC */ + ret = rsnd_path_add(priv, io, src); if (ret < 0) return ret; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5f5b8b1..7fee207 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -441,12 +441,6 @@ struct rsnd_priv { void *gen; /* - * below value will be filled on rsnd_src_probe() - */ - void *src; - int src_nr; - - /* * below value will be filled on rsnd_adg_probe() */ void *adg; @@ -463,6 +457,12 @@ struct rsnd_priv { int ssi_nr; /* + * below value will be filled on rsnd_src_probe() + */ + void *src; + int src_nr; + + /* * below value will be filled on rsnd_dvc_probe() */ void *dvc; @@ -535,6 +535,19 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, u32 max); /* + * R-Car SSI + */ +int rsnd_ssi_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); +void rsnd_ssi_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +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_dai_stream *io, struct rsnd_mod *mod); + +/* * R-Car SRC */ int rsnd_src_probe(struct platform_device *pdev, @@ -555,19 +568,6 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); /* - * R-Car SSI - */ -int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv); -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_dai_stream *io, struct rsnd_mod *mod); - -/* * R-Car DVC */ int rsnd_dvc_probe(struct platform_device *pdev, -- cgit v0.10.2 From f2da4542268503d22869617b7dbcb40d364c78bb Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 17 Jul 2015 07:44:09 +0800 Subject: ASoC: sti: sti_uniperiph_dai_create_ctrl() can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 749e6b2..83a301f 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -14,7 +14,7 @@ * This function is used to create Ctrl associated to DAI but also pcm device. * Request is done by front end to associate ctrl with pcm device id */ -int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) +static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *uni = priv->dai_data.uni; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d990d2c..f609089 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -43,7 +43,7 @@ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate DAI_CPU capability in term of rate and supported channels */ -const struct snd_pcm_hardware uni_player_pcm_hw = { +static const struct snd_pcm_hardware uni_player_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, @@ -175,7 +175,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) return ret; } -int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) +static int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) { int rate_adjusted, rate_achieved, delta, ret; int adjustment = player->clk_adj; diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 7d83827..c502626 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -17,7 +17,7 @@ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate unireader capability in term of rate and supported channels */ -const struct snd_pcm_hardware uni_reader_pcm_hw = { +static const struct snd_pcm_hardware uni_reader_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, @@ -324,7 +324,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, return 0; } -const struct snd_soc_dai_ops uni_reader_dai_ops = { +static const struct snd_soc_dai_ops uni_reader_dai_ops = { .shutdown = uni_reader_shutdown, .prepare = uni_reader_prepare, .trigger = uni_reader_trigger, -- cgit v0.10.2 From 42d1b8ce2973c2f5956f4d4e4af002986ccc5748 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 10:54:49 +0800 Subject: ASoC: Constify dev_pm_ops variables The dev_pm_ops variables are not modified after initialization in these drivers, so make them const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c830832..3e3f638 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2481,7 +2481,7 @@ static int wm2200_runtime_resume(struct device *dev) } #endif -static struct dev_pm_ops wm2200_pm = { +static const struct dev_pm_ops wm2200_pm = { SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, NULL) }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd8..3ea29cf 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2708,7 +2708,7 @@ static int wm5100_runtime_resume(struct device *dev) } #endif -static struct dev_pm_ops wm5100_pm = { +static const struct dev_pm_ops wm5100_pm = { SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, NULL) }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd..ad16414 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3859,7 +3859,7 @@ static int wm8962_runtime_suspend(struct device *dev) } #endif -static struct dev_pm_ops wm8962_pm = { +static const struct dev_pm_ops wm8962_pm = { SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; -- cgit v0.10.2 From 582edace0b2af5f5fd44446ff6651a23417f1aee Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Fri, 17 Jul 2015 10:58:40 +0800 Subject: ASoC: rt5645: Remove unused rt5645 variable "ASoC: rt5645: Simplify rt5645_enable_push_button_irq" removes the test that accessed rt5645->pdata.jd_mode (that test is now done in rt5645_jack_detect only), so we do not need that variable anymore. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 11a2bfc..c16adf4 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2763,7 +2763,6 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { snd_soc_dapm_force_enable_pin(dapm, "ADC L power"); -- cgit v0.10.2 From 5168c5476a07233ecafaed0effaa59859327e366 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Fri, 17 Jul 2015 11:33:11 +0800 Subject: ASoC: rt5645: Fix missing free_irq The driver does not free irq when snd_soc_register_codec returns error. It does not return error when request irq failed, either. Add return when request irq failed, and free_irq if snd_soc_register_codec failed. Signed-off-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c16adf4..827e3bf 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3397,12 +3397,23 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5645", rt5645); - if (ret) + if (ret) { dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + return ret; + } } - return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, - rt5645_dai, ARRAY_SIZE(rt5645_dai)); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, + rt5645_dai, ARRAY_SIZE(rt5645_dai)); + if (ret) + goto err_irq; + + return 0; + +err_irq: + if (rt5645->i2c->irq) + free_irq(rt5645->i2c->irq, rt5645); + return ret; } static int rt5645_i2c_remove(struct i2c_client *i2c) -- cgit v0.10.2 From 9fc114c5d7af6cfb72a2d983e16b83161716d6d0 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Fri, 17 Jul 2015 11:33:12 +0800 Subject: ASoC: rt5645: Add regulator support This adds basic regulator support for rt5645. Signed-off-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 827e3bf..5f5d8ad 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,38 @@ static const struct reg_default rt5645_reg[] = { { 0xff, 0x6308 }, }; +static const char *const rt5645_supply_names[] = { + "avdd", + "cpvdd", +}; + +struct rt5645_priv { + struct snd_soc_codec *codec; + struct rt5645_platform_data pdata; + struct regmap *regmap; + struct i2c_client *i2c; + struct gpio_desc *gpiod_hp_det; + struct snd_soc_jack *hp_jack; + struct snd_soc_jack *mic_jack; + struct snd_soc_jack *btn_jack; + struct delayed_work jack_detect_work; + struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)]; + + int codec_type; + int sysclk; + int sysclk_src; + int lrck[RT5645_AIFS]; + int bclk[RT5645_AIFS]; + int master[RT5645_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + bool en_button_func; +}; + static int rt5645_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, RT5645_RESET, 0); @@ -3214,7 +3247,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, { struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5645_priv *rt5645; - int ret; + int ret, i; unsigned int val; rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), @@ -3248,6 +3281,24 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return ret; } + for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) + rt5645->supplies[i].supply = rt5645_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5645->supplies), + rt5645->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5645->supplies), + rt5645->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); switch (val) { @@ -3261,7 +3312,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5645 or rt5650\n", val); - return -ENODEV; + ret = -ENODEV; + goto err_enable; } if (rt5645->codec_type == CODEC_TYPE_RT5650) { @@ -3399,7 +3451,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | IRQF_ONESHOT, "rt5645", rt5645); if (ret) { dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); - return ret; + goto err_enable; } } @@ -3413,6 +3465,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, err_irq: if (rt5645->i2c->irq) free_irq(rt5645->i2c->irq, rt5645); +err_enable: + regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); return ret; } @@ -3426,6 +3480,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) cancel_delayed_work_sync(&rt5645->jack_detect_work); snd_soc_unregister_codec(&i2c->dev); + regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); return 0; } diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 0353a6a..199b22f 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2177,32 +2177,6 @@ enum { int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, unsigned int filter_mask, unsigned int clk_src); -struct rt5645_priv { - struct snd_soc_codec *codec; - struct rt5645_platform_data pdata; - struct regmap *regmap; - struct i2c_client *i2c; - struct gpio_desc *gpiod_hp_det; - struct snd_soc_jack *hp_jack; - struct snd_soc_jack *mic_jack; - struct snd_soc_jack *btn_jack; - struct delayed_work jack_detect_work; - - int codec_type; - int sysclk; - int sysclk_src; - int lrck[RT5645_AIFS]; - int bclk[RT5645_AIFS]; - int master[RT5645_AIFS]; - - int pll_src; - int pll_in; - int pll_out; - - int jack_type; - bool en_button_func; -}; - int rt5645_set_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, struct snd_soc_jack *btn_jack); -- cgit v0.10.2 From 6d058c5643e16779ae4c001d2e893c140940e48f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Jul 2015 04:37:07 -0300 Subject: [media] vb2: Only requeue buffers immediately once streaming is started Buffers can be returned back to videobuf2 in driver's streamon handler. In this case vb2_buffer_done() with buffer state VB2_BUF_STATE_QUEUED will cause the driver's buf_queue vb2 operation to be called, queueing the same buffer again only to be returned to videobuf2 using vb2_buffer_done() and so on. Add a new buffer state VB2_BUF_STATE_REQUEUEING which, when used as the state argument to vb2_buffer_done(), will result in buffers queued to the driver. Using VB2_BUF_STATE_QUEUED will leave the buffer to videobuf2, as it was before "[media] vb2: allow requeuing buffers while streaming". Fixes: ce0eff016f72 ("[media] vb2: allow requeuing buffers while streaming") [mchehab@osg.samsung.com: fix warning: enumeration value 'VB2_BUF_STATE_REQUEUEING' not handled in switch] Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Cc: stable@vger.kernel.org # for v4.1 Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index dd4bff9..d1f5898 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -139,7 +139,7 @@ done: also know about dropped frames. */ cb->vb.v4l2_buf.sequence = s->sequence++; vb2_buffer_done(&cb->vb, (skip || s->unstable_frame) ? - VB2_BUF_STATE_QUEUED : VB2_BUF_STATE_DONE); + VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE); } irqreturn_t cobalt_irq_handler(int irq, void *dev_id) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 93b3154..0c7b6a7 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -715,6 +715,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) break; case VB2_BUF_STATE_PREPARING: case VB2_BUF_STATE_DEQUEUED: + case VB2_BUF_STATE_REQUEUEING: /* nothing */ break; } @@ -1182,7 +1183,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) if (WARN_ON(state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR && - state != VB2_BUF_STATE_QUEUED)) + state != VB2_BUF_STATE_QUEUED && + state != VB2_BUF_STATE_REQUEUEING)) state = VB2_BUF_STATE_ERROR; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1199,22 +1201,30 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); - /* Add the buffer to the done buffers list */ spin_lock_irqsave(&q->done_lock, flags); - vb->state = state; - if (state != VB2_BUF_STATE_QUEUED) + if (state == VB2_BUF_STATE_QUEUED || + state == VB2_BUF_STATE_REQUEUEING) { + vb->state = VB2_BUF_STATE_QUEUED; + } else { + /* Add the buffer to the done buffers list */ list_add_tail(&vb->done_entry, &q->done_list); + vb->state = state; + } atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); - if (state == VB2_BUF_STATE_QUEUED) { + switch (state) { + case VB2_BUF_STATE_QUEUED: + return; + case VB2_BUF_STATE_REQUEUEING: if (q->start_streaming_called) __enqueue_in_driver(vb); return; + default: + /* Inform any processes that may be waiting for buffers */ + wake_up(&q->done_wq); + break; } - - /* Inform any processes that may be waiting for buffers */ - wake_up(&q->done_wq); } EXPORT_SYMBOL_GPL(vb2_buffer_done); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 22a44c2..c192e1b 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -139,6 +139,7 @@ enum vb2_io_modes { * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf * @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver + * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used * in a hardware operation * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but @@ -152,6 +153,7 @@ enum vb2_buffer_state { VB2_BUF_STATE_PREPARING, VB2_BUF_STATE_PREPARED, VB2_BUF_STATE_QUEUED, + VB2_BUF_STATE_REQUEUEING, VB2_BUF_STATE_ACTIVE, VB2_BUF_STATE_DONE, VB2_BUF_STATE_ERROR, -- cgit v0.10.2 From dc606e05468fc5e3b125bffdd54253f853bfbb8e Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Fri, 17 Jul 2015 15:11:10 +0100 Subject: ASoC: wm5110: Use reg_sequence for multi_reg_write/register_patch Introduced by: commit 8019ff6cfc04 ("regmap: Use reg_sequence for multi_reg_write / register_patch") Interacting with: commit d1acd31883d7 ("ASoC: wm5110: Add special DRE on/off handling for the headphone path") Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b5c201b..1f29991 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -185,7 +185,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } -static const struct reg_default wm5110_no_dre_left_enable[] = { +static const struct reg_sequence wm5110_no_dre_left_enable[] = { { 0x3024, 0xE410 }, { 0x3025, 0x0056 }, { 0x301B, 0x0224 }, @@ -203,7 +203,7 @@ static const struct reg_default wm5110_no_dre_left_enable[] = { { 0x3039, 0x3080 }, }; -static const struct reg_default wm5110_dre_left_enable[] = { +static const struct reg_sequence wm5110_dre_left_enable[] = { { 0x3024, 0x0231 }, { 0x3025, 0x0B00 }, { 0x301B, 0x0227 }, @@ -221,7 +221,7 @@ static const struct reg_default wm5110_dre_left_enable[] = { { 0x3039, 0x0B00 }, }; -static const struct reg_default wm5110_no_dre_right_enable[] = { +static const struct reg_sequence wm5110_no_dre_right_enable[] = { { 0x3074, 0xE414 }, { 0x3075, 0x0056 }, { 0x306B, 0x0224 }, @@ -239,7 +239,7 @@ static const struct reg_default wm5110_no_dre_right_enable[] = { { 0x3089, 0x3080 }, }; -static const struct reg_default wm5110_dre_right_enable[] = { +static const struct reg_sequence wm5110_dre_right_enable[] = { { 0x3074, 0x0231 }, { 0x3075, 0x0B00 }, { 0x306B, 0x0227 }, @@ -263,7 +263,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w) struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); - const struct reg_default *wseq; + const struct reg_sequence *wseq; int nregs; switch (w->shift) { @@ -354,7 +354,7 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, static int wm5110_clear_pga_volume(struct arizona *arizona, int output) { - struct reg_default clear_pga = { + struct reg_sequence clear_pga = { ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 }; int ret; -- cgit v0.10.2 From 7dfb49194557ccf27ab99c8c04c021320e7ae458 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:56 +0000 Subject: ASoC: rsnd: update Audio DMA path search method Current rsnd driver is assuming Audio DMAC / Audio DMAC peri peri are used from SSI/SSIU/SRC/DVC. But we will add CTU/MIX to this driver. Then, current DMA path searching method is not understandable, and good enough for this purpose. This patch update DMA path search method, more simply. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index a175863..23282f4 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -494,7 +494,7 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, return rsnd_gen2_dma_addr(io, mod, is_play, is_from); } -#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ +#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_dai_stream *io, int is_play, @@ -506,53 +506,71 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, 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; + struct rsnd_mod *mod_start, *mod_end; + struct rsnd_priv *priv = rsnd_mod_to_priv(this); + struct device *dev = rsnd_priv_to_dev(priv); + int nr, i; + if (!ssi) + return; - for (i = 0; i < MOD_MAX; i++) + nr = 0; + for (i = 0; i < MOD_MAX; i++) { mod[i] = NULL; + nr += !!rsnd_io_to_mod(io, i); + } /* - * in play case... + * [S] -*-> [E] + * [S] -*-> SRC -o-> [E] + * [S] -*-> SRC -> DVC -o-> [E] + * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] + * + * playback [S] = mem + * [E] = SSI * - * src -> dst + * capture [S] = SSI + * [E] = mem * - * mem -> SSI - * mem -> SRC -> SSI - * mem -> SRC -> DVC -> SSI + * -*-> Audio DMAC + * -o-> Audio DMAC peri peri */ - 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_start = (is_play) ? NULL : ssi; + mod_end = (is_play) ? ssi : NULL; - mod[i] = (is_play) ? src : dvc; - i++; - mod[i] = (is_play) ? dvc : src; + mod[0] = mod_start; + for (i = 1; i < nr; i++) { + if (src) { + mod[i] = src; src = NULL; + } else if (dvc) { + mod[i] = dvc; dvc = NULL; } - - if (mod[i] == this) - index = i; - - if (mod[i] == ssi) - break; } + mod[i] = mod_end; - if (is_play) { - *mod_from = mod[index - 1]; - *mod_to = mod[index]; + /* + * | SSI | SRC | + * -------------+-----+-----+ + * is_play | o | * | + * !is_play | * | o | + */ + if ((this == ssi) == (is_play)) { + *mod_from = mod[nr - 1]; + *mod_to = mod[nr]; } else { - *mod_from = mod[index]; - *mod_to = mod[index - 1]; + *mod_from = mod[0]; + *mod_to = mod[1]; + } + + dev_dbg(dev, "module connection (this is %s[%d])\n", + rsnd_mod_name(this), rsnd_mod_id(this)); + for (i = 0; i <= nr; i++) { + dev_dbg(dev, " %s[%d]%s\n", + rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), + (mod[i] == *mod_from) ? " from" : + (mod[i] == *mod_to) ? " to" : ""); } } @@ -580,8 +598,8 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) { - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; + struct rsnd_mod *mod_from = NULL; + struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); -- cgit v0.10.2 From 9269e3c3cfac277a49b485e27ac6850f9a11a259 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:17:17 +0000 Subject: ASoC: rsnd: add CTU (Channel Transfer Unit) prototype support This patch adds CTU (Channel Transfer Unit) support for rsnd driver. But, it does nothing to data at this point, but is required for MIX support. CTU design is a little different from other IPs (CTU0 is including CTU00 - CTU03, and CTU1 is including CTU10 - CTU13, these have different register mapping) We need to care about it on this driver. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index b6b3a78..278607d 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -18,6 +18,9 @@ Required properties: - rcar_sound,src : Should contain SRC feature. The number of SRC subnode should be same as HW. see below for detail. +- rcar_sound,ctu : Should contain CTU feature. + The number of CTU subnode should be same as HW. + see below for detail. - rcar_sound,dvc : Should contain DVC feature. The number of DVC subnode should be same as HW. see below for detail. @@ -90,6 +93,17 @@ rcar_sound: sound@ec500000 { }; }; + rcar_sound,ctu { + ctu00: ctu@0 { }; + ctu01: ctu@1 { }; + ctu02: ctu@2 { }; + ctu03: ctu@3 { }; + ctu10: ctu@4 { }; + ctu11: ctu@5 { }; + ctu12: ctu@6 { }; + ctu13: ctu@7 { }; + }; + rcar_sound,src { src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 4cecd0c..8f93030 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -61,6 +61,10 @@ struct rsnd_src_platform_info { /* * flags */ +struct rsnd_ctu_platform_info { + u32 flags; +}; + struct rsnd_dvc_platform_info { u32 flags; }; @@ -68,6 +72,7 @@ struct rsnd_dvc_platform_info { struct rsnd_dai_path_info { struct rsnd_ssi_platform_info *ssi; struct rsnd_src_platform_info *src; + struct rsnd_ctu_platform_info *ctu; struct rsnd_dvc_platform_info *dvc; }; @@ -93,6 +98,8 @@ struct rcar_snd_info { int ssi_info_nr; struct rsnd_src_platform_info *src_info; int src_info_nr; + struct rsnd_ctu_platform_info *ctu_info; + int ctu_info_nr; struct rsnd_dvc_platform_info *dvc_info; int dvc_info_nr; struct rsnd_dai_platform_info *dai_info; diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 3a274fd..7c4730a 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e20d8ea..63ae7bb 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -651,6 +651,11 @@ static int rsnd_path_init(struct rsnd_priv *priv, if (ret < 0) return ret; + /* CTU */ + ret = rsnd_path_add(priv, io, ctu); + if (ret < 0) + return ret; + /* DVC */ ret = rsnd_path_add(priv, io, dvc); if (ret < 0) @@ -666,13 +671,14 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, struct device_node *dai_node, *dai_np; struct device_node *ssi_node, *ssi_np; struct device_node *src_node, *src_np; + struct device_node *ctu_node, *ctu_np; struct device_node *dvc_node, *dvc_np; struct device_node *playback, *capture; struct rsnd_dai_platform_info *dai_info; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = &pdev->dev; int nr, i; - int dai_i, ssi_i, src_i, dvc_i; + int dai_i, ssi_i, src_i, ctu_i, dvc_i; if (!of_data) return; @@ -698,6 +704,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); + ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); #define mod_parse(name) \ @@ -734,6 +741,7 @@ if (name##_node) { \ mod_parse(ssi); mod_parse(src); + mod_parse(ctu); mod_parse(dvc); of_node_put(playback); @@ -1146,6 +1154,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_dma_probe, rsnd_ssi_probe, rsnd_src_probe, + rsnd_ctu_probe, rsnd_dvc_probe, rsnd_adg_probe, rsnd_dai_probe, @@ -1241,6 +1250,7 @@ static int rsnd_remove(struct platform_device *pdev) struct rsnd_priv *priv) = { rsnd_ssi_remove, rsnd_src_remove, + rsnd_ctu_remove, rsnd_dvc_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c new file mode 100644 index 0000000..05edd20 --- /dev/null +++ b/sound/soc/sh/rcar/ctu.c @@ -0,0 +1,171 @@ +/* + * ctu.c + * + * 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" + +#define CTU_NAME_SIZE 16 +#define CTU_NAME "ctu" + +struct rsnd_ctu { + struct rsnd_ctu_platform_info *info; /* rcar_snd.h */ + struct rsnd_mod mod; +}; + +#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) +#define for_each_rsnd_ctu(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_ctu_nr(priv)) && \ + ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ + i++) + +#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) +#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) +static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, CTU_CTUIR, enable); +} + +static int rsnd_ctu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_start(mod); + + rsnd_ctu_initialize_lock(mod); + + rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); + + rsnd_ctu_initialize_unlock(mod); + + return 0; +} + +static int rsnd_ctu_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_stop(mod); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ctu_ops = { + .name = CTU_NAME, + .init = rsnd_ctu_init, + .quit = rsnd_ctu_quit, +}; + +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) + id = 0; + + return &((struct rsnd_ctu *)(priv->ctu) + id)->mod; +} + +void rsnd_of_parse_ctu(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct rsnd_ctu_platform_info *ctu_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + goto rsnd_of_parse_ctu_end; + + ctu_info = devm_kzalloc(dev, + sizeof(struct rsnd_ctu_platform_info) * nr, + GFP_KERNEL); + if (!ctu_info) { + dev_err(dev, "ctu info allocation error\n"); + goto rsnd_of_parse_ctu_end; + } + + info->ctu_info = ctu_info; + info->ctu_info_nr = nr; + +rsnd_of_parse_ctu_end: + of_node_put(node); + +} + +int rsnd_ctu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ctu *ctu; + struct clk *clk; + char name[CTU_NAME_SIZE]; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) { + dev_warn(dev, "CTU is not supported on Gen1\n"); + return -EINVAL; + } + + rsnd_of_parse_ctu(pdev, of_data, priv); + + nr = info->ctu_info_nr; + if (!nr) + return 0; + + ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); + if (!ctu) + return -ENOMEM; + + priv->ctu_nr = nr; + priv->ctu = ctu; + + for_each_rsnd_ctu(ctu, priv, i) { + /* + * CTU00, CTU01, CTU02, CTU03 => CTU0 + * CTU10, CTU11, CTU12, CTU13 => CTU1 + */ + snprintf(name, CTU_NAME_SIZE, "%s.%d", + CTU_NAME, i / 4); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ctu->info = &info->ctu_info[i]; + + ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops, + clk, RSND_MOD_CTU, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_ctu_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_ctu *ctu; + int i; + + for_each_rsnd_ctu(ctu, priv, i) { + rsnd_mod_quit(&ctu->mod); + } +} diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 23282f4..229b68d 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -426,7 +426,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, 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 use_cmd = !!rsnd_io_to_mod_dvc(io) || + !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); struct dma_addr { dma_addr_t out_addr; @@ -464,7 +465,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, }; /* it shouldn't happen */ - if (use_dvc && !use_src) + if (use_cmd && !use_src) dev_err(dev, "DVC is selected without SRC\n"); /* use SSIU or SSI ? */ @@ -472,8 +473,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, 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_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : + dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; } static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, @@ -504,6 +505,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *mod_start, *mod_end; @@ -543,6 +545,9 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, if (src) { mod[i] = src; src = NULL; + } else if (ctu) { + mod[i] = ctu; + ctu = NULL; } else if (dvc) { mod[i] = dvc; dvc = NULL; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index a2d5df4..41b75cd 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -240,6 +240,8 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), + RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), + RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7fee207..f2128a7 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -47,6 +47,8 @@ enum rsnd_reg { RSND_REG_SCU_SYS_STATUS0, RSND_REG_SCU_SYS_INT_EN0, RSND_REG_CMD_ROUTE_SLCT, + RSND_REG_CTU_CTUIR, + RSND_REG_CTU_ADINR, RSND_REG_DVC_SWRSR, RSND_REG_DVC_DVUIR, RSND_REG_DVC_ADINR, @@ -220,6 +222,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, */ enum rsnd_mod_type { RSND_MOD_DVC = 0, + RSND_MOD_CTU, RSND_MOD_SRC, RSND_MOD_SSI, RSND_MOD_MAX, @@ -351,6 +354,7 @@ struct rsnd_dai_stream { #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) +#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) @@ -463,6 +467,12 @@ struct rsnd_priv { int src_nr; /* + * below value will be filled on rsnd_ctu_probe() + */ + void *ctu; + int ctu_nr; + + /* * below value will be filled on rsnd_dvc_probe() */ void *dvc; @@ -568,6 +578,17 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); /* + * R-Car CTU + */ +int rsnd_ctu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); + +void rsnd_ctu_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); + +/* * R-Car DVC */ int rsnd_dvc_probe(struct platform_device *pdev, -- cgit v0.10.2 From 70fb10529f61c31c26397a02091177bedd23217d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:17:36 +0000 Subject: ASoC: rsnd: add MIX (Mixer) support This patch adds MIX (Mixer) initial support for rsnd driver. It is assuming that this MIX is used via DPCM. This is sample code for playback. CPU0 : [MEM] -> [SRC1] -> [CTU02] -+ | +-> [MIX0] -> [DVC0] -> [SSI0] | CPU1 : [MEM] -> [SRC2] -> [CTU03] -+ sound { compatible = "renesas,rsrc-card"; ... cpu@0 { sound-dai = <&rcar_sound 0>; }; cpu@1 { sound-dai = <&rcar_sound 1>; }; codec { ... }; }; rcar_sound { ... rcar_sound,dai { dai0 { playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>; }; dai1 { playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; }; }; }; Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 278607d..1173395 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -21,6 +21,9 @@ Required properties: - rcar_sound,ctu : Should contain CTU feature. The number of CTU subnode should be same as HW. see below for detail. +- rcar_sound,mix : Should contain MIX feature. + The number of MIX subnode should be same as HW. + see below for detail. - rcar_sound,dvc : Should contain DVC feature. The number of DVC subnode should be same as HW. see below for detail. @@ -93,6 +96,11 @@ rcar_sound: sound@ec500000 { }; }; + rcar_sound,mix { + mix0: mix@0 { }; + mix1: mix@1 { }; + }; + rcar_sound,ctu { ctu00: ctu@0 { }; ctu01: ctu@1 { }; diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 8f93030..bb7b2eb 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -65,6 +65,10 @@ struct rsnd_ctu_platform_info { u32 flags; }; +struct rsnd_mix_platform_info { + u32 flags; +}; + struct rsnd_dvc_platform_info { u32 flags; }; @@ -73,6 +77,7 @@ struct rsnd_dai_path_info { struct rsnd_ssi_platform_info *ssi; struct rsnd_src_platform_info *src; struct rsnd_ctu_platform_info *ctu; + struct rsnd_mix_platform_info *mix; struct rsnd_dvc_platform_info *dvc; }; @@ -100,6 +105,8 @@ struct rcar_snd_info { int src_info_nr; struct rsnd_ctu_platform_info *ctu_info; int ctu_info_nr; + struct rsnd_mix_platform_info *mix_info; + int mix_info_nr; struct rsnd_dvc_platform_info *dvc_info; int dvc_info_nr; struct rsnd_dai_platform_info *dai_info; diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7c4730a..8b25850 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 63ae7bb..927a7b0 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -605,23 +605,74 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - int src_id = rsnd_mod_id(src); - u32 path[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *cmd; + struct device *dev = rsnd_priv_to_dev(priv); + u32 data; /* Gen1 is not supported */ if (rsnd_is_gen1(priv)) return; - rsnd_mod_write(dvc, CMD_ROUTE_SLCT, path[src_id]); + if (!mix && !dvc) + return; + + if (mix) { + struct rsnd_dai *rdai; + int i; + u32 path[] = { + [0] = 0, + [1] = 1 << 0, + [2] = 0, + [3] = 0, + [4] = 0, + [5] = 1 << 8 + }; + + /* + * it is assuming that integrater is well understanding about + * data path. Here doesn't check impossible connection, + * like src2 + src5 + */ + data = 0; + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + + io = &rdai->capture; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + } + + /* + * We can't use ctu = rsnd_io_ctu() here. + * Since, ID of dvc/mix are 0 or 1 (= same as CMD number) + * but ctu IDs are 0 - 7 (= CTU00 - CTU13) + */ + cmd = mix; + } else { + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + data = path[rsnd_mod_id(src)]; + + cmd = dvc; + } + + dev_dbg(dev, "ctu/mix path = 0x%08x", data); + + rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data); + + rsnd_mod_write(cmd, CMD_CTRL, 0x10); } static int rsnd_path_init(struct rsnd_priv *priv, @@ -656,6 +707,11 @@ static int rsnd_path_init(struct rsnd_priv *priv, if (ret < 0) return ret; + /* MIX */ + ret = rsnd_path_add(priv, io, mix); + if (ret < 0) + return ret; + /* DVC */ ret = rsnd_path_add(priv, io, dvc); if (ret < 0) @@ -672,13 +728,14 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, struct device_node *ssi_node, *ssi_np; struct device_node *src_node, *src_np; struct device_node *ctu_node, *ctu_np; + struct device_node *mix_node, *mix_np; struct device_node *dvc_node, *dvc_np; struct device_node *playback, *capture; struct rsnd_dai_platform_info *dai_info; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = &pdev->dev; int nr, i; - int dai_i, ssi_i, src_i, ctu_i, dvc_i; + int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i; if (!of_data) return; @@ -705,6 +762,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); + mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); #define mod_parse(name) \ @@ -742,6 +800,7 @@ if (name##_node) { \ mod_parse(ssi); mod_parse(src); mod_parse(ctu); + mod_parse(mix); mod_parse(dvc); of_node_put(playback); @@ -1155,6 +1214,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_ssi_probe, rsnd_src_probe, rsnd_ctu_probe, + rsnd_mix_probe, rsnd_dvc_probe, rsnd_adg_probe, rsnd_dai_probe, @@ -1251,6 +1311,7 @@ static int rsnd_remove(struct platform_device *pdev) rsnd_ssi_remove, rsnd_src_remove, rsnd_ctu_remove, + rsnd_mix_remove, rsnd_dvc_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 229b68d..305b129 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -427,6 +427,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); int use_src = !!rsnd_io_to_mod_src(io); int use_cmd = !!rsnd_io_to_mod_dvc(io) || + !!rsnd_io_to_mod_mix(io) || !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); struct dma_addr { @@ -506,6 +507,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *mod_start, *mod_end; @@ -548,6 +550,9 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } else if (ctu) { mod[i] = ctu; ctu = NULL; + } else if (mix) { + mod[i] = mix; + mix = NULL; } else if (dvc) { mod[i] = dvc; dvc = NULL; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 41b75cd..f04d17b 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -242,6 +242,16 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), + RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), + RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), + RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), + RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40), + RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40), + RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40), + RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40), + RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40), + RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40), + RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40), RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c new file mode 100644 index 0000000..0d5c102 --- /dev/null +++ b/sound/soc/sh/rcar/mix.c @@ -0,0 +1,200 @@ +/* + * mix.c + * + * 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" + +#define MIX_NAME_SIZE 16 +#define MIX_NAME "mix" + +struct rsnd_mix { + struct rsnd_mix_platform_info *info; /* rcar_snd.h */ + struct rsnd_mod mod; +}; + +#define rsnd_mix_nr(priv) ((priv)->mix_nr) +#define for_each_rsnd_mix(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_mix_nr(priv)) && \ + ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ + i++) + + +static void rsnd_mix_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_SWRSR, 0); + rsnd_mod_write(mod, MIX_SWRSR, 1); +} + +#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1) +#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0) +static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, MIX_MIXIR, enable); +} + +static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + + /* Disable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 0); + + rsnd_mod_write(mod, MIX_MDBAR, 0); + rsnd_mod_write(mod, MIX_MDBBR, 0); + rsnd_mod_write(mod, MIX_MDBCR, 0); + rsnd_mod_write(mod, MIX_MDBDR, 0); + + /* Enable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 1); +} + +static int rsnd_mix_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_start(mod); + + rsnd_mix_soft_reset(mod); + + rsnd_mix_initialize_lock(mod); + + rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); + + rsnd_path_parse(priv, io); + + /* volume step */ + rsnd_mod_write(mod, MIX_MIXMR, 0); + rsnd_mod_write(mod, MIX_MVPDR, 0); + + rsnd_mix_volume_update(io, mod); + + rsnd_mix_initialize_unlock(mod); + + return 0; +} + +static int rsnd_mix_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_stop(mod); + + return 0; +} + +static struct rsnd_mod_ops rsnd_mix_ops = { + .name = MIX_NAME, + .init = rsnd_mix_init, + .quit = rsnd_mix_quit, +}; + +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) + id = 0; + + return &((struct rsnd_mix *)(priv->mix) + id)->mod; +} + +static void rsnd_of_parse_mix(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct rsnd_mix_platform_info *mix_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + goto rsnd_of_parse_mix_end; + + mix_info = devm_kzalloc(dev, + sizeof(struct rsnd_mix_platform_info) * nr, + GFP_KERNEL); + if (!mix_info) { + dev_err(dev, "mix info allocation error\n"); + goto rsnd_of_parse_mix_end; + } + + info->mix_info = mix_info; + info->mix_info_nr = nr; + +rsnd_of_parse_mix_end: + of_node_put(node); + +} + +int rsnd_mix_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mix *mix; + struct clk *clk; + char name[MIX_NAME_SIZE]; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) { + dev_warn(dev, "MIX is not supported on Gen1\n"); + return -EINVAL; + } + + rsnd_of_parse_mix(pdev, of_data, priv); + + nr = info->mix_info_nr; + if (!nr) + return 0; + + mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); + if (!mix) + return -ENOMEM; + + priv->mix_nr = nr; + priv->mix = mix; + + for_each_rsnd_mix(mix, priv, i) { + snprintf(name, MIX_NAME_SIZE, "%s.%d", + MIX_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + mix->info = &info->mix_info[i]; + + ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops, + clk, RSND_MOD_MIX, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_mix_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_mix *mix; + int i; + + for_each_rsnd_mix(mix, priv, i) { + rsnd_mod_quit(&mix->mod); + } +} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f2128a7..7a0e52b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -49,6 +49,16 @@ enum rsnd_reg { RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, + RSND_REG_MIX_SWRSR, + RSND_REG_MIX_MIXIR, + RSND_REG_MIX_ADINR, + RSND_REG_MIX_MIXMR, + RSND_REG_MIX_MVPDR, + RSND_REG_MIX_MDBAR, + RSND_REG_MIX_MDBBR, + RSND_REG_MIX_MDBCR, + RSND_REG_MIX_MDBDR, + RSND_REG_MIX_MDBER, RSND_REG_DVC_SWRSR, RSND_REG_DVC_DVUIR, RSND_REG_DVC_ADINR, @@ -222,6 +232,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, */ enum rsnd_mod_type { RSND_MOD_DVC = 0, + RSND_MOD_MIX, RSND_MOD_CTU, RSND_MOD_SRC, RSND_MOD_SSI, @@ -355,6 +366,7 @@ struct rsnd_dai_stream { #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) +#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) @@ -473,6 +485,12 @@ struct rsnd_priv { int ctu_nr; /* + * below value will be filled on rsnd_mix_probe() + */ + void *mix; + int mix_nr; + + /* * below value will be filled on rsnd_dvc_probe() */ void *dvc; @@ -589,6 +607,17 @@ void rsnd_ctu_remove(struct platform_device *pdev, struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); /* + * R-Car MIX + */ +int rsnd_mix_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); + +void rsnd_mix_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); + +/* * R-Car DVC */ int rsnd_dvc_probe(struct platform_device *pdev, -- cgit v0.10.2 From dd9283e23f674281c02cd8cbf894cb3132a4e3a6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 23:38:34 +0800 Subject: ASoC: cs4349: Fix max_register setting for cs4349_regmap The max_register should be the maximum valid register index rather than number of registers. Also remove unused defines. Signed-off-by: Axel Lin Acked-by: Tim Howe Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a8df8a74..9273b06 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -268,7 +268,7 @@ static struct regmap_config cs4349_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = CS4349_NUMREGS, + .max_register = CS4349_MISC, .reg_defaults = cs4349_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h index 3884a89..7effa0a 100644 --- a/sound/soc/codecs/cs4349.h +++ b/sound/soc/codecs/cs4349.h @@ -36,9 +36,6 @@ struct cs4349_platform_data { #define CS4349_RMPFLT 0x07 /* Ramp and Filter Control */ #define CS4349_MISC 0x08 /* Power Down,Freeze Control,Pop Stop*/ -#define CS4349_FIRSTREG 0x01 -#define CS4349_LASTREG 0x08 -#define CS4349_NUMREGS (CS4349_LASTREG - CS4349_FIRSTREG + 1) #define CS4349_I2C_INCR 0x80 -- cgit v0.10.2 From b08b338253e917be45ee19924b58dd0b1265473f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 23:43:02 +0800 Subject: ASoC: cs4349: Constify cs4349_regmap Signed-off-by: Axel Lin Acked-by: Tim Howe Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 9273b06..f4fccc6 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -264,7 +264,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { .num_dapm_routes = ARRAY_SIZE(cs4349_routes), }; -static struct regmap_config cs4349_regmap = { +static const struct regmap_config cs4349_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v0.10.2 From 653cdc13a340ad1cef29f1bab0d05d0771fa1d57 Mon Sep 17 00:00:00 2001 From: Reinhard Speyerer Date: Tue, 14 Jul 2015 22:55:06 +0200 Subject: USB: qcserial/option: make AT URCs work for Sierra Wireless MC7305/MC7355 Tests with a Sierra Wireless MC7355 have shown that 1199:9041 devices also require the option_send_setup() code to be used on the USB interface for the AT port to make unsolicited response codes work correctly. Move these devices from the qcserial driver to the option driver like it has been done for the 1199:68c0 devices in commit d80c0d14183516f184a5ac88e11008ee4c7d2a2e ("USB: qcserial/option: make AT URCs work for Sierra Wireless MC73xx"). Signed-off-by: Reinhard Speyerer Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 19b85ee..876423b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1099,6 +1099,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff), .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */ + { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff), + .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 9c63897..552dc9a 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -145,7 +145,6 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ - {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ {DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */ {DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */ -- cgit v0.10.2 From aeec6cdad6cda5fdf26f937c0d15f101539d8185 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 16 Jul 2015 16:56:14 +0530 Subject: ARC/time: Migrate to new 'set-state' interface Migrate arc driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Vineet Gupta Signed-off-by: Viresh Kumar Signed-off-by: Vineet Gupta diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 3364d2b..4294761 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -203,34 +203,24 @@ static int arc_clkevent_set_next_event(unsigned long delta, return 0; } -static void arc_clkevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int arc_clkevent_set_periodic(struct clock_event_device *dev) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* - * At X Hz, 1 sec = 1000ms -> X cycles; - * 10ms -> X / 100 cycles - */ - arc_timer_event_setup(arc_get_core_freq() / HZ); - break; - case CLOCK_EVT_MODE_ONESHOT: - break; - default: - break; - } - - return; + /* + * At X Hz, 1 sec = 1000ms -> X cycles; + * 10ms -> X / 100 cycles + */ + arc_timer_event_setup(arc_get_core_freq() / HZ); + return 0; } static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { - .name = "ARC Timer0", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .mode = CLOCK_EVT_MODE_UNUSED, - .rating = 300, - .irq = TIMER0_IRQ, /* hardwired, no need for resources */ - .set_next_event = arc_clkevent_set_next_event, - .set_mode = arc_clkevent_set_mode, + .name = "ARC Timer0", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .irq = TIMER0_IRQ, /* hardwired, no need for resources */ + .set_next_event = arc_clkevent_set_next_event, + .set_state_periodic = arc_clkevent_set_periodic, }; static irqreturn_t timer_irq_handler(int irq, void *dev_id) @@ -240,7 +230,7 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) * irq_set_chip_and_handler() asked for handle_percpu_devid_irq() */ struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC; + int irq_reenable = clockevent_state_periodic(evt); /* * Any write to CTRL reg ACks the interrupt, we rewrite the -- cgit v0.10.2 From d05a76ab4d9ece9bd987a8c29e3f384ec9f7b211 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 16 Jul 2015 21:45:38 +0300 Subject: ARCv2: add knob for DIV_REV in Kconfig Being highly configurable core ARC HS among other features might be configured with or without DIV_REM_OPTION (hardware divider). That option when enabled adds following instructions: div, divu, rem, remu. By default ARC HS38 has this option enabled. So we add here possibility to disable usage of hardware divider by compiler. Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 91cf405..f7cfa7d 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -379,6 +379,10 @@ config ARC_HAS_LL64 dest operands with 2 possible source operands. default y +config ARC_HAS_DIV_REM + bool "Insn: div, divu, rem, remu" + default y + config ARC_HAS_RTC bool "Local 64-bit r/o cycle counter" default n diff --git a/arch/arc/Makefile b/arch/arc/Makefile index 46d8731..8a27a48 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -36,8 +36,16 @@ cflags-$(atleast_gcc44) += -fsection-anchors cflags-$(CONFIG_ARC_HAS_LLSC) += -mlock cflags-$(CONFIG_ARC_HAS_SWAPE) += -mswape +ifdef CONFIG_ISA_ARCV2 + ifndef CONFIG_ARC_HAS_LL64 -cflags-$(CONFIG_ISA_ARCV2) += -mno-ll64 +cflags-y += -mno-ll64 +endif + +ifndef CONFIG_ARC_HAS_DIV_REM +cflags-y += -mno-div-rem +endif + endif cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables -- cgit v0.10.2 From 6da3700c98cdc8360f55c5510915efae1d66deea Mon Sep 17 00:00:00 2001 From: Pieter Hollants Date: Mon, 20 Jul 2015 11:56:17 +0200 Subject: USB: qcserial: Add support for Dell Wireless 5809e 4G Modem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added the USB IDs 0x413c:0x81b1 for the "Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card", a Dell-branded Sierra Wireless EM7305 LTE card in M.2 form factor, used eg. in Dell's Latitude E7540 Notebook series. "lsusb -v" output for this device: Bus 002 Device 003: ID 413c:81b1 Dell Computer Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x413c Dell Computer Corp. idProduct 0x81b1 bcdDevice 0.06 iManufacturer 1 Sierra Wireless, Incorporated iProduct 2 Dell Wireless 5809e Gobi™ 4G LTE Mobile Broadband Card iSerial 3 bNumConfigurations 2 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 204 bNumInterfaces 4 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 00 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000c 1x 12 bytes bInterval 9 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 00 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000c 1x 12 bytes bInterval 9 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 8 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 9 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 ** UNRECOGNIZED: 2c ff 42 49 53 54 00 01 07 f5 40 f6 00 00 00 00 01 f7 c4 09 02 f8 c4 09 03 f9 88 13 04 fa 10 27 05 fb 10 27 06 fc c4 09 07 fd c4 09 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 95 bNumInterfaces 2 bConfigurationValue 2 iConfiguration 0 bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 500mA Interface Association: bLength 8 bDescriptorType 11 bFirstInterface 12 bInterfaceCount 2 bFunctionClass 2 Communications bFunctionSubClass 14 bFunctionProtocol 0 iFunction 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 12 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 14 bInterfaceProtocol 0 iInterface 0 CDC Header: bcdCDC 1.10 CDC Union: bMasterInterface 12 bSlaveInterface 13 CDC MBIM: bcdMBIMVersion 1.00 wMaxControlMessage 4096 bNumberFilters 32 bMaxFilterSize 128 wMaxSegmentSize 1500 bmNetworkCapabilities 0x20 8-byte ntb input size CDC MBIM Extended: bcdMBIMExtendedVersion 1.00 bMaxOutstandingCommandMessages 64 wMTU 1500 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 9 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 13 bAlternateSetting 0 bNumEndpoints 0 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 2 iInterface 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 13 bAlternateSetting 1 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 bInterfaceProtocol 2 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 2 Device Status: 0x0000 (Bus Powered) Signed-off-by: Pieter Hollants Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 552dc9a..d156545 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -157,6 +157,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ /* Huawei devices */ {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */ -- cgit v0.10.2 From 929423fa83e5b75e94101b280738b9a5a376a0e1 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 20 Jul 2015 13:49:39 +0200 Subject: xen: release lock occasionally during ballooning When dom0 is being ballooned balloon_process() will hold the balloon mutex until it is finished. This will block e.g. creation of new domains as the device backends for the new domain need some autoballooned pages for the ring buffers. Avoid this by releasing the balloon mutex from time to time during ballooning. Adjust the comment above balloon_process() regarding multiple instances of balloon_process(). Instead of open coding it, just use cond_resched(). Signed-off-by: Juergen Gross Signed-off-by: David Vrabel diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index fd93369..bf4a23c 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) } /* - * We avoid multiple worker processes conflicting via the balloon mutex. + * As this is a work item it is guaranteed to run as a single instance only. * We may of course race updates of the target counts (which are protected * by the balloon lock), or with changes to the Xen hard limit, but we will * recover from these in time. @@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work) enum bp_state state = BP_DONE; long credit; - mutex_lock(&balloon_mutex); do { + mutex_lock(&balloon_mutex); + credit = current_credit(); if (credit > 0) { @@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work) state = update_schedule(state); -#ifndef CONFIG_PREEMPT - if (need_resched()) - schedule(); -#endif + mutex_unlock(&balloon_mutex); + + cond_resched(); + } while (credit && state == BP_DONE); /* Schedule more work if there is some still to be done. */ if (state == BP_EAGAIN) schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ); - - mutex_unlock(&balloon_mutex); } /* Resets the Xen limit, sets new target, and kicks off processing. */ -- cgit v0.10.2 From 21481f2cfef9a79d3676916ef9424b1a7794776c Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 20 Jul 2015 17:19:17 +0300 Subject: ARCv2: lib: memcpy: Missing PREFETCHW Signed-off-by: Vineet Gupta diff --git a/arch/arc/lib/memcpy-archs.S b/arch/arc/lib/memcpy-archs.S index 1b2b3ac..0cab0b8 100644 --- a/arch/arc/lib/memcpy-archs.S +++ b/arch/arc/lib/memcpy-archs.S @@ -206,7 +206,7 @@ unalignedOffby3: ld.ab r6, [r1, 4] prefetch [r1, 28] ;Prefetch the next read location ld.ab r8, [r1,4] - prefetch [r3, 32] ;Prefetch the next write location + prefetchw [r3, 32] ;Prefetch the next write location SHIFT_1 (r7, r6, 8) or r7, r7, r5 -- cgit v0.10.2 From 262137bca7cfbe690f8e904822b68f720998324a Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 20 Jul 2015 12:05:03 +0300 Subject: ARCv2: lib: memset: Don't assume 64-bit load/stores There are configurations which may not have LDD/STD Signed-off-by: Claudiu Zissulescu Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta diff --git a/arch/arc/lib/memset-archs.S b/arch/arc/lib/memset-archs.S index 92d573c..365b183 100644 --- a/arch/arc/lib/memset-archs.S +++ b/arch/arc/lib/memset-archs.S @@ -10,12 +10,6 @@ #undef PREALLOC_NOT_AVAIL -#ifdef PREALLOC_NOT_AVAIL -#define PREWRITE(A,B) prefetchw [(A),(B)] -#else -#define PREWRITE(A,B) prealloc [(A),(B)] -#endif - ENTRY(memset) prefetchw [r0] ; Prefetch the write location mov.f 0, r2 @@ -51,9 +45,15 @@ ENTRY(memset) ;;; Convert len to Dwords, unfold x8 lsr.f lp_count, lp_count, 6 + lpnz @.Lset64bytes ;; LOOP START - PREWRITE(r3, 64) ;Prefetch the next write location +#ifdef PREALLOC_NOT_AVAIL + prefetchw [r3, 64] ;Prefetch the next write location +#else + prealloc [r3, 64] +#endif +#ifdef CONFIG_ARC_HAS_LL64 std.ab r4, [r3, 8] std.ab r4, [r3, 8] std.ab r4, [r3, 8] @@ -62,16 +62,45 @@ ENTRY(memset) std.ab r4, [r3, 8] std.ab r4, [r3, 8] std.ab r4, [r3, 8] +#else + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] +#endif .Lset64bytes: lsr.f lp_count, r2, 5 ;Last remaining max 124 bytes lpnz .Lset32bytes ;; LOOP START prefetchw [r3, 32] ;Prefetch the next write location +#ifdef CONFIG_ARC_HAS_LL64 std.ab r4, [r3, 8] std.ab r4, [r3, 8] std.ab r4, [r3, 8] std.ab r4, [r3, 8] +#else + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] + st.ab r4, [r3, 4] +#endif .Lset32bytes: and.f lp_count, r2, 0x1F ;Last remaining 31 bytes -- cgit v0.10.2 From f136dce45116027fec65c342fbcb5aaa900729c6 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 20 Jul 2015 09:32:05 +0800 Subject: ASoC: rt5645: Remove return value in jack detect work "ASoC: rt5645: Check if codec is initialized in workqueue handler" adds a check if codec is NULL in rt5645_irq_detection, which returns an int. However, "ASoC: rt5645: Remove irq_jack_detection function" removes that function, and moves the code in jack_detect_work, which returns void. Remove the return value to fix compilation warning. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 19392b1..2ee4278 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2928,7 +2928,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) int val, btn_type, gpio_state = 0, report = 0; if (!rt5645->codec) - return -EINVAL; + return; switch (rt5645->pdata.jd_mode) { case 0: /* Not using rt5645 JD */ -- cgit v0.10.2 From 49bdb0440541ad1144ad08d5613f9a28bcd2a8dc Mon Sep 17 00:00:00 2001 From: zhengxing Date: Sun, 19 Jul 2015 19:33:48 +0800 Subject: ASoC: rockchip: Add machine driver for max98090 codec The driver is used for rockchip board using a max98090. Reviewed-by: Dylan Reid Signed-off-by: zhengxing Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt new file mode 100644 index 0000000..a805aa9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt @@ -0,0 +1,19 @@ +ROCKCHIP with MAX98090 CODEC + +Required properties: +- compatible: "rockchip,rockchip-audio-max98090" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the MAX98090 audio codec +- rockchip,headset-codec: The phandle of Ext chip for jack detection + +Example: + +sound { + compatible = "rockchip,rockchip-audio-max98090"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&max98090>; + rockchip,headset-codec = <&headsetcodec>; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index e181826..d123566 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -14,3 +14,13 @@ config SND_SOC_ROCKCHIP_I2S Say Y or M if you want to add support for I2S driver for Rockchip I2S device. The device supports upto maximum of 8 channels each for play and record. + +config SND_SOC_ROCKCHIP_MAX98090 + tristate "ASoC support for Rockchip boards using a MAX98090 codec" + depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_MAX98090 + select SND_SOC_TS3A227E + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using the MAX98090 codec, such as Veyron. diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index b921909..df3445b 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -2,3 +2,7 @@ snd-soc-i2s-objs := rockchip_i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o + +snd-soc-rockchip-max98090-objs := rockchip_max98090.o + +obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c new file mode 100644 index 0000000..acace20 --- /dev/null +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -0,0 +1,236 @@ +/* + * Rockchip machine ASoC driver for boards using a MAX90809 CODEC. + * + * Copyright (c) 2014, ROCKCHIP CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_i2s.h" +#include "../codecs/ts3a227e.h" + +#define DRV_NAME "rockchip-snd-max98090" + +static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headset Jack", + .mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + }, +}; + +static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route rk_audio_map[] = { + {"IN34", NULL, "Headset Mic"}, + {"IN34", NULL, "MICBIAS"}, + {"MICBIAS", NULL, "Headset Mic"}, + {"DMICL", NULL, "Int Mic"}, + {"Headphone", NULL, "HPL"}, + {"Headphone", NULL, "HPR"}, + {"Speaker", NULL, "SPKL"}, + {"Speaker", NULL, "SPKR"}, +}; + +static const struct snd_kcontrol_new rk_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int rk_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int mclk; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + mclk = 12288000; + break; + case 44100: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + return ret; +} + +static int rk_init(struct snd_soc_pcm_runtime *runtime) +{ + /* Enable Headset and 4 Buttons Jack detection */ + return snd_soc_card_jack_new(runtime->card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); +} + +static int rk_98090_headset_init(struct snd_soc_component *component) +{ + return ts3a227e_enable_jack_detect(component, &headset_jack); +} + +static struct snd_soc_ops rk_aif1_ops = { + .hw_params = rk_aif1_hw_params, +}; + +static struct snd_soc_aux_dev rk_98090_headset_dev = { + .name = "Headset Chip", + .init = rk_98090_headset_init, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "max98090", + .stream_name = "Audio", + .codec_dai_name = "HiFi", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set max98090 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "ROCKCHIP-I2S", + .dai_link = &rk_dailink, + .num_links = 1, + .aux_dev = &rk_98090_headset_dev, + .num_aux_devs = 1, + .dapm_widgets = rk_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets), + .dapm_routes = rk_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_audio_map), + .controls = rk_mc_controls, + .num_controls = ARRAY_SIZE(rk_mc_controls), +}; + +static int snd_rk_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_card *card = &snd_soc_card_rk; + struct device_node *np = pdev->dev.of_node; + + /* register the soc card */ + card->dev = &pdev->dev; + + rk_dailink.codec_of_node = of_parse_phandle(np, + "rockchip,audio-codec", 0); + if (!rk_dailink.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,audio-codec' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.cpu_of_node = of_parse_phandle(np, + "rockchip,i2s-controller", 0); + if (!rk_dailink.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,i2s-controller' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.platform_of_node = rk_dailink.cpu_of_node; + + rk_98090_headset_dev.codec_of_node = of_parse_phandle(np, + "rockchip,headset-codec", 0); + if (!rk_98090_headset_dev.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,headset-codec' missing/invalid\n"); + return -EINVAL; + } + + ret = snd_soc_of_parse_card_name(card, "rockchip,model"); + if (ret) { + dev_err(&pdev->dev, + "Soc parse card name failed %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, + "Soc register card failed %d\n", ret); + return ret; + } + + return ret; +} + +static const struct of_device_id rockchip_max98090_of_match[] = { + { .compatible = "rockchip,rockchip-audio-max98090", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_max98090_of_match); + +static struct platform_driver snd_rk_mc_driver = { + .probe = snd_rk_mc_probe, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_max98090_of_match, + }, +}; + +module_platform_driver(snd_rk_mc_driver); + +MODULE_AUTHOR("jianqun "); +MODULE_DESCRIPTION("Rockchip max98090 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v0.10.2 From 86059653ea7ca7b30ed25d6bec5807ba59a4f2e6 Mon Sep 17 00:00:00 2001 From: zhengxing Date: Sun, 19 Jul 2015 19:33:49 +0800 Subject: ASoC: rockchip: Add machine driver for rt5645/rt5650 codec The driver is used for rockchip board using a rt5645/rt5650. Reviewed-by: Dylan Reid Signed-off-by: zhengxing Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt new file mode 100644 index 0000000..411a62b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt @@ -0,0 +1,17 @@ +ROCKCHIP with RT5645/RT5650 CODECS + +Required properties: +- compatible: "rockchip,rockchip-audio-rt5645" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the RT5645/RT5650 audio codec + +Example: + +sound { + compatible = "rockchip,rockchip-audio-rt5645"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&rt5645>; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index d123566..58bae8e 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -24,3 +24,12 @@ config SND_SOC_ROCKCHIP_MAX98090 help Say Y or M here if you want to add support for SoC audio on Rockchip boards using the MAX98090 codec, such as Veyron. + +config SND_SOC_ROCKCHIP_RT5645 + tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" + depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_RT5645 + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using the RT5645/RT5650 codec, such as Veyron. diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index df3445b..1bc1dc3 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -4,5 +4,7 @@ snd-soc-i2s-objs := rockchip_i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o +snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o +obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c new file mode 100644 index 0000000..3c6bb1e --- /dev/null +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -0,0 +1,225 @@ +/* + * Rockchip machine ASoC driver for boards using a RT5645/RT5650 CODEC. + * + * Copyright (c) 2015, ROCKCHIP CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rockchip_i2s.h" + +#define DRV_NAME "rockchip-snd-rt5645" + +static struct snd_soc_jack headset_jack; + +/* Jack detect via rt5645 driver. */ +extern int rt5645_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, + struct snd_soc_jack *btn_jack); + +static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), +}; + +static const struct snd_soc_dapm_route rk_audio_map[] = { + /* Input Lines */ + {"DMIC L2", NULL, "Int Mic"}, + {"DMIC R2", NULL, "Int Mic"}, + {"RECMIXL", NULL, "Headset Mic"}, + {"RECMIXR", NULL, "Headset Mic"}, + + /* Output Lines */ + {"Headphones", NULL, "HPOR"}, + {"Headphones", NULL, "HPOL"}, + {"Speakers", NULL, "SPOL"}, + {"Speakers", NULL, "SPOR"}, +}; + +static const struct snd_kcontrol_new rk_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), +}; + +static int rk_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int mclk; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + mclk = 12288000; + break; + case 44100: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + return ret; +} + +static int rk_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + int ret; + + /* Enable Headset and 4 Buttons Jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, NULL, 0); + if (!ret) { + dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); + return ret; + } + + return rt5645_set_jack_detect(runtime->codec, + &headset_jack, + &headset_jack, + &headset_jack); +} + +static struct snd_soc_ops rk_aif1_ops = { + .hw_params = rk_aif1_hw_params, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "rt5645", + .stream_name = "rt5645 PCM", + .codec_dai_name = "rt5645-aif1", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set rt5645 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "I2S-RT5650", + .dai_link = &rk_dailink, + .num_links = 1, + .dapm_widgets = rk_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets), + .dapm_routes = rk_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_audio_map), + .controls = rk_mc_controls, + .num_controls = ARRAY_SIZE(rk_mc_controls), +}; + +static int snd_rk_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_card *card = &snd_soc_card_rk; + struct device_node *np = pdev->dev.of_node; + + /* register the soc card */ + card->dev = &pdev->dev; + + rk_dailink.codec_of_node = of_parse_phandle(np, + "rockchip,audio-codec", 0); + if (!rk_dailink.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,audio-codec' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.cpu_of_node = of_parse_phandle(np, + "rockchip,i2s-controller", 0); + if (!rk_dailink.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,i2s-controller' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.platform_of_node = rk_dailink.cpu_of_node; + + ret = snd_soc_of_parse_card_name(card, "rockchip,model"); + if (ret) { + dev_err(&pdev->dev, + "Soc parse card name failed %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, + "Soc register card failed %d\n", ret); + return ret; + } + + return ret; +} + +static const struct of_device_id rockchip_rt5645_of_match[] = { + { .compatible = "rockchip,rockchip-audio-rt5645", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match); + +static struct platform_driver snd_rk_mc_driver = { + .probe = snd_rk_mc_probe, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_rt5645_of_match, + }, +}; + +module_platform_driver(snd_rk_mc_driver); + +MODULE_AUTHOR("Xing Zheng "); +MODULE_DESCRIPTION("Rockchip rt5645 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v0.10.2 From cb2510dac7e1c5ac77652bb31e8c39ce2eef8bbe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 19 Jul 2015 12:15:17 +0200 Subject: ASoC: cs4349: Fix suspend/resume dev_get_drvdata() will not return the snd_soc_runtime to which this CODEC is attached, so the current code will result in undefined behavior. To fix this just use regmap_update_bits(cs4349->regmap, ...) directly instead of snd_soc_update_bits(rtd->codec, ...). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index f4fccc6..13ccbf7 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -328,10 +328,9 @@ static int cs4349_i2c_remove(struct i2c_client *client) static int cs4349_runtime_suspend(struct device *dev) { struct cs4349_private *cs4349 = dev_get_drvdata(dev); - struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); int ret; - ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 1); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 1); if (ret < 0) return ret; @@ -347,10 +346,9 @@ static int cs4349_runtime_suspend(struct device *dev) static int cs4349_runtime_resume(struct device *dev) { struct cs4349_private *cs4349 = dev_get_drvdata(dev); - struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); int ret; - ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 0); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 0); if (ret < 0) return ret; -- cgit v0.10.2 From dedae86d4da6c88ec2105e0bd038acc57c203bca Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 19 Jul 2015 12:15:18 +0200 Subject: ASoC: cs4349: Don't use rtd->codec rtd->codec does not necessarily point to the CODEC instance for which the callback was called (e.g. for CODEC<->CODEC or multi-CODEC links). Use dai->codec instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 13ccbf7..ab07167 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -94,8 +94,7 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); int mode, fmt, ret; -- cgit v0.10.2 From da304ac37efc1900892b5067c65f0ab8acfe3955 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 22:42:49 +0800 Subject: ASoC: cs4349: Fix setting digital interface format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mode Control - Register 02h Digital Interface Format (DIF[2:0]) Bits 6-4 DIF2 DIF1 DIF0 Description 0 0 0 Left-Justified, up to 24-bit data 0 0 1 I²S, up to 24-bit data 0 1 0 Right-Justified, 16-bit data 0 1 1 Right-Justified, 24-bit data 1 0 0 TDM slot 0 1 0 1 TDM slot 1 1 1 0 TDM slot 2 1 1 1 TDM slot 3 The DIF_MASK is 0x70, so current code does not correctly set the DIFx setting. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index ab07167..4885695 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -96,17 +96,16 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); - int mode, fmt, ret; + int fmt, ret; - mode = snd_soc_read(codec, CS4349_MODE); cs4349->rate = params_rate(params); switch (cs4349->mode) { case SND_SOC_DAIFMT_I2S: - mode |= MODE_FORMAT(DIF_I2S); + fmt = DIF_I2S; break; case SND_SOC_DAIFMT_LEFT_J: - mode |= MODE_FORMAT(DIF_LEFT_JST); + fmt = DIF_LEFT_JST; break; case SND_SOC_DAIFMT_RIGHT_J: switch (params_width(params)) { @@ -119,13 +118,13 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - mode |= MODE_FORMAT(fmt); break; default: return -EINVAL; } - ret = snd_soc_write(codec, CS4349_MODE, mode); + ret = snd_soc_update_bits(codec, CS4349_MODE, DIF_MASK, + MODE_FORMAT(fmt)); if (ret < 0) return ret; -- cgit v0.10.2 From 4313489c25622b05adac55dbb9590fb5674c3f45 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 19 Jul 2015 21:12:16 +0200 Subject: ASoC: ux500: adjust devm usage The explicit call to devm_regulator_put in the probe and remove functions does not seem to be necessary. In particular, the functions prcmu_qos_remove_requirement and ux500_msp_i2s_cleanup_msp in the remove function seem to do nothing that can interfere with devm_regulator_put, making it safe to allow devm_regulator_put to occur after the end of the remove function. Convert the calls to clk_get to devm_clk_get, and remove the corresponding calls to clk_put in the probe and remove functions. Replace various gotos by direct returns, and drop unneeded labels. Signed-off-by: Julia Lawall Reviewed-by: Ulf Hansson Signed-off-by: Mark Brown diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 978f2d7..f5df08d 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -773,20 +773,22 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); - drvdata->pclk = clk_get(&pdev->dev, "apb_pclk"); + drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(drvdata->pclk)) { ret = (int)PTR_ERR(drvdata->pclk); - dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n", + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get of pclk failed (%d)!\n", __func__, ret); - goto err_pclk; + return ret; } - drvdata->clk = clk_get(&pdev->dev, NULL); + drvdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { ret = (int)PTR_ERR(drvdata->clk); - dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n", + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get failed (%d)!\n", __func__, ret); - goto err_clk; + return ret; } ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp, @@ -795,7 +797,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: ERROR: Failed to init MSP-struct (%d)!", __func__, ret); - goto err_init_msp; + return ret; } dev_set_drvdata(&pdev->dev, drvdata); @@ -804,7 +806,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", __func__, drvdata->msp->id); - goto err_init_msp; + return ret; } ret = ux500_pcm_register_platform(pdev); @@ -819,13 +821,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) err_reg_plat: snd_soc_unregister_component(&pdev->dev); -err_init_msp: - clk_put(drvdata->clk); -err_clk: - clk_put(drvdata->pclk); -err_pclk: - devm_regulator_put(drvdata->reg_vape); - return ret; } @@ -837,12 +832,8 @@ static int ux500_msp_drv_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); - clk_put(drvdata->clk); - clk_put(drvdata->pclk); - ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); return 0; -- cgit v0.10.2 From 0443de7e7e559eab7df2566d0e46940f753db51d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 09:14:23 +0800 Subject: ASoC: cs4349: Set .writeable_reg for cs4349_regmap The first valid register index is 1 rather than 0, and the CS4349_CHIPID is readonly. So set .writeable_reg to avoid writing to these registers. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 4885695..a6604a3 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -54,14 +54,17 @@ struct cs4349_private { static bool cs4349_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS4349_CHIPID: - case CS4349_MODE: - case CS4349_VMI: - case CS4349_MUTE: - case CS4349_VOLA: - case CS4349_VOLB: - case CS4349_RMPFLT: - case CS4349_MISC: + case CS4349_CHIPID ... CS4349_MISC: + return true; + default: + return false; + } +} + +static bool cs4349_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4349_MODE ... CS4349_MISC: return true; default: return false; @@ -270,6 +273,7 @@ static const struct regmap_config cs4349_regmap = { .reg_defaults = cs4349_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, + .writeable_reg = cs4349_writeable_register, .cache_type = REGCACHE_RBTREE, }; -- cgit v0.10.2 From 44251551dfca2117e42349136b871b33c8419a59 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 09:15:38 +0800 Subject: ASoC: cs4349: Drop platform data support The struct cs4349_platform_data should be defined in a public header in include/sound/ rather than in sound/soc/codecs folder. In additional, the platform data support is not properly handled in this driver so remove it now. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a6604a3..2569010 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -45,7 +45,6 @@ static const struct reg_default cs4349_reg_defaults[] = { /* Private data for the CS4349 */ struct cs4349_private { struct regmap *regmap; - struct cs4349_platform_data pdata; struct gpio_desc *reset_gpio; unsigned int mode; int rate; @@ -281,8 +280,7 @@ static int cs4349_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cs4349_private *cs4349; - struct cs4349_platform_data *pdata = dev_get_platdata(&client->dev); - int ret = 0; + int ret; cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL); if (!cs4349) @@ -295,9 +293,6 @@ static int cs4349_i2c_probe(struct i2c_client *client, return ret; } - if (pdata) - cs4349->pdata = *pdata; - /* Reset the Device */ cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h index 7effa0a..d58c06a 100644 --- a/sound/soc/codecs/cs4349.h +++ b/sound/soc/codecs/cs4349.h @@ -19,13 +19,6 @@ #ifndef __CS4349_H__ #define __CS4349_H__ -struct cs4349_platform_data { - - /* GPIO for Reset */ - unsigned int gpio_nreset; - -}; - /* CS4349 registers addresses */ #define CS4349_CHIPID 0x01 /* Device and Rev ID, Read Only */ #define CS4349_MODE 0x02 /* Mode Control */ -- cgit v0.10.2 From 091571d071a435a517aec42c4f8c56883c5dc531 Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Fri, 17 Jul 2015 15:43:46 -0700 Subject: ASoC: cs4349: include gpio/consumer.h s390 allmodconfig: sound/soc/codecs/cs4349.c: In function 'cs4349_i2c_probe': sound/soc/codecs/cs4349.c:300: error: implicit declaration of function 'devm_gpiod_get_optional' sound/soc/codecs/cs4349.c:301: error: 'GPIOD_OUT_LOW' undeclared (first use in this function) sound/soc/codecs/cs4349.c:301: error: (Each undeclared identifier is reported only once sound/soc/codecs/cs4349.c:301: error: for each function it appears in.) sound/soc/codecs/cs4349.c:306: error: implicit declaration of function 'gpiod_set_value_cansleep' Signed-off-by: Andrew Morton Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 2569010..a7538ae 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From bf9185dda829b2aaf73e1e869891a968ff85e2ae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 20 Jul 2015 18:36:15 +0100 Subject: ASoC: sti-uniperf: Fix implicit inclusion of pinctrl Reported-by: Stephen Rothwell Signed-off-by: Mark Brown diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 83a301f..51f745c 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -6,6 +6,7 @@ */ #include +#include #include "uniperif.h" -- cgit v0.10.2 From c2227a39a078473115910512aa0f8d53bd915e60 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Tue, 7 Jul 2015 10:16:37 +0800 Subject: nfsd: Drop BUG_ON and ignore SECLABEL on absent filesystem On an absent filesystem (one served by another server), we need to be able to handle requests for certain attributest (like fs_locations, so the client can find out which server does have the filesystem), but others we can't. We forgot to take that into account when adding another attribute bitmask work for the SECURITY_LABEL attribute. There an export entry with the "refer" option can result in: [ 88.414272] kernel BUG at fs/nfsd/nfs4xdr.c:2249! [ 88.414828] invalid opcode: 0000 [#1] SMP [ 88.415368] Modules linked in: rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache nfsd xfs libcrc32c iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi iosf_mbi ppdev btrfs coretemp crct10dif_pclmul crc32_pclmul crc32c_intel xor ghash_clmulni_intel raid6_pq vmw_balloon parport_pc parport i2c_piix4 shpchp vmw_vmci acpi_cpufreq auth_rpcgss nfs_acl lockd grace sunrpc vmwgfx drm_kms_helper ttm drm mptspi mptscsih serio_raw mptbase e1000 scsi_transport_spi ata_generic pata_acpi [last unloaded: nfsd] [ 88.417827] CPU: 0 PID: 2116 Comm: nfsd Not tainted 4.0.7-300.fc22.x86_64 #1 [ 88.418448] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/20/2014 [ 88.419093] task: ffff880079146d50 ti: ffff8800785d8000 task.ti: ffff8800785d8000 [ 88.419729] RIP: 0010:[] [] nfsd4_encode_fattr+0x820/0x1f00 [nfsd] [ 88.420376] RSP: 0000:ffff8800785db998 EFLAGS: 00010206 [ 88.421027] RAX: 0000000000000001 RBX: 000000000018091a RCX: ffff88006668b980 [ 88.421676] RDX: 00000000fffef7fc RSI: 0000000000000000 RDI: ffff880078d05000 [ 88.422315] RBP: ffff8800785dbb58 R08: ffff880078d043f8 R09: ffff880078d4a000 [ 88.422968] R10: 0000000000010000 R11: 0000000000000002 R12: 0000000000b0a23a [ 88.423612] R13: ffff880078d05000 R14: ffff880078683100 R15: ffff88006668b980 [ 88.424295] FS: 0000000000000000(0000) GS:ffff88007c600000(0000) knlGS:0000000000000000 [ 88.424944] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 88.425597] CR2: 00007f40bc370f90 CR3: 0000000035af5000 CR4: 00000000001407f0 [ 88.426285] Stack: [ 88.426921] ffff8800785dbaa8 ffffffffa049e4af ffff8800785dba08 ffffffff813298f0 [ 88.427585] ffff880078683300 ffff8800769b0de8 0000089d00000001 0000000087f805e0 [ 88.428228] ffff880000000000 ffff880079434a00 0000000000000000 ffff88006668b980 [ 88.428877] Call Trace: [ 88.429527] [] ? exp_get_by_name+0x7f/0xb0 [nfsd] [ 88.430168] [] ? inode_doinit_with_dentry+0x210/0x6a0 [ 88.430807] [] ? d_lookup+0x2e/0x60 [ 88.431449] [] ? dput+0x33/0x230 [ 88.432097] [] ? mntput+0x24/0x40 [ 88.432719] [] ? path_put+0x22/0x30 [ 88.433340] [] ? nfsd_cross_mnt+0xb7/0x1c0 [nfsd] [ 88.433954] [] nfsd4_encode_dirent+0x1b0/0x3d0 [nfsd] [ 88.434601] [] ? nfsd4_encode_getattr+0x40/0x40 [nfsd] [ 88.435172] [] nfsd_readdir+0x1c1/0x2a0 [nfsd] [ 88.435710] [] ? nfsd_direct_splice_actor+0x20/0x20 [nfsd] [ 88.436447] [] nfsd4_encode_readdir+0x120/0x220 [nfsd] [ 88.437011] [] nfsd4_encode_operation+0x7d/0x190 [nfsd] [ 88.437566] [] nfsd4_proc_compound+0x24d/0x6f0 [nfsd] [ 88.438157] [] nfsd_dispatch+0xc3/0x220 [nfsd] [ 88.438680] [] svc_process_common+0x43b/0x690 [sunrpc] [ 88.439192] [] svc_process+0x103/0x1b0 [sunrpc] [ 88.439694] [] nfsd+0x117/0x190 [nfsd] [ 88.440194] [] ? nfsd_destroy+0x90/0x90 [nfsd] [ 88.440697] [] kthread+0xd8/0xf0 [ 88.441260] [] ? kthread_worker_fn+0x180/0x180 [ 88.441762] [] ret_from_fork+0x58/0x90 [ 88.442322] [] ? kthread_worker_fn+0x180/0x180 [ 88.442879] Code: 0f 84 93 05 00 00 83 f8 ea c7 85 a0 fe ff ff 00 00 27 30 0f 84 ba fe ff ff 85 c0 0f 85 a5 fe ff ff e9 e3 f9 ff ff 0f 1f 44 00 00 <0f> 0b 66 0f 1f 44 00 00 be 04 00 00 00 4c 89 ef 4c 89 8d 68 fe [ 88.444052] RIP [] nfsd4_encode_fattr+0x820/0x1f00 [nfsd] [ 88.444658] RSP [ 88.445232] ---[ end trace 6cb9d0487d94a29f ]--- Signed-off-by: Kinglong Mee Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5463385..75e0563 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2143,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID +#define WORD2_ABSENT_FS_ATTRS 0 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL static inline __be32 @@ -2171,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp, { return 0; } #endif -static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) +static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err) { /* As per referral draft: */ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS || @@ -2184,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) } *bmval0 &= WORD0_ABSENT_FS_ATTRS; *bmval1 &= WORD1_ABSENT_FS_ATTRS; + *bmval2 &= WORD2_ABSENT_FS_ATTRS; return 0; } @@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion)); if (exp->ex_fslocs.migrated) { - BUG_ON(bmval[2]); - status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err); + status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err); if (status) goto out; } @@ -2286,8 +2287,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #ifdef CONFIG_NFSD_V4_SECURITY_LABEL - if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || - bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { + if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) || + bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { err = security_inode_getsecctx(d_inode(dentry), &context, &contextlen); contextsupport = (err == 0); -- cgit v0.10.2 From 1ca4b88e7de23f6f86d2009101fe42d5b9dbf3de Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 9 Jul 2015 17:38:26 +0800 Subject: nfsd: Fix a file leak on nfsd4_layout_setlease failure If nfsd4_layout_setlease fails, nfsd will not put ls->ls_file. Fix commit c5c707f96f "nfsd: implement pNFS layout recalls". Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 6904213..ebf90e4 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -212,6 +212,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, BUG_ON(!ls->ls_file); if (nfsd4_layout_setlease(ls)) { + fput(ls->ls_file); put_nfs4_file(fp); kmem_cache_free(nfs4_layout_stateid_cache, ls); return NULL; -- cgit v0.10.2 From cba77f03f2c7b6cc0b0a44a3c679e0abade7da62 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Sat, 11 Jul 2015 21:19:19 -0400 Subject: locking/pvqspinlock: Fix kernel panic in locking-selftest Enabling locking-selftest in a VM guest may cause the following kernel panic: kernel BUG at .../kernel/locking/qspinlock_paravirt.h:137! This is due to the fact that the pvqspinlock unlock function is expecting either a _Q_LOCKED_VAL or _Q_SLOW_VAL in the lock byte. This patch prevents that bug report by ignoring it when debug_locks_silent is set. Otherwise, a warning will be printed if it contains an unexpected value. With this patch applied, the kernel locking-selftest completed without any noise. Tested-by: Masami Hiramatsu Signed-off-by: Waiman Long Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1436663959-53092-1-git-send-email-Waiman.Long@hp.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h index 04ab181..df19ae4 100644 --- a/kernel/locking/qspinlock_paravirt.h +++ b/kernel/locking/qspinlock_paravirt.h @@ -4,6 +4,7 @@ #include #include +#include /* * Implement paravirt qspinlocks; the general idea is to halt the vcpus instead @@ -286,15 +287,23 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock) { struct __qspinlock *l = (void *)lock; struct pv_node *node; + u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0); /* * We must not unlock if SLOW, because in that case we must first * unhash. Otherwise it would be possible to have multiple @lock * entries, which would be BAD. */ - if (likely(cmpxchg(&l->locked, _Q_LOCKED_VAL, 0) == _Q_LOCKED_VAL)) + if (likely(lockval == _Q_LOCKED_VAL)) return; + if (unlikely(lockval != _Q_SLOW_VAL)) { + if (debug_locks_silent) + return; + WARN(1, "pvqspinlock: lock %p has corrupted value 0x%x!\n", lock, atomic_read(&lock->val)); + return; + } + /* * Since the above failed to release, this must be the SLOW path. * Therefore start by looking up the blocked node and unhashing it. -- cgit v0.10.2 From 48725e9cc841da395bfd74e7691bba91613d3517 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2015 00:03:35 +0000 Subject: ASoC: rsnd: tidyup parameter assignment position 84e95355602c("ASoC: rsnd: show debug message for SSI/SRC/DVC connection") added debug message on rsnd_dai_connect(), but the relationship of parameter check was absurdity. This patch tidyup it. It is reported via Smatch/Dan Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 927a7b0..f3feed5 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -332,12 +332,15 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) static int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_priv *priv; + struct device *dev; if (!mod) return -EIO; + priv = rsnd_mod_to_priv(mod); + dev = rsnd_priv_to_dev(priv); + io->mod[mod->type] = mod; dev_dbg(dev, "%s[%d] is connected to io (%s)\n", -- cgit v0.10.2 From 6eb1c2a63d0415bd66c9c866b7d405662f50d5e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Jul 2015 11:55:27 +0300 Subject: ASoC: max98925: reading beyond the end of the array Debug prints are seldom useful and this one has an annoying thing where it reads one space beyond the end of the array on error. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index eddf8bc..0883d877 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -271,8 +271,6 @@ static inline int max98925_rate_value(struct snd_soc_codec *codec, break; } } - dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n", - __func__, rate_table[i].rate, *value); return ret; } -- cgit v0.10.2 From a4642e99694a912b32952317e8f4c253ed6be4a9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Jul 2015 11:57:36 +0300 Subject: ASoC: sti: error handling bug in sti_uniperiph_cpu_dai_of() There is a stray '!' which means the condition is never true. Fixes: f3bd847eb0a7 ('ASoC: sti: Add uniperipheral dai driver') Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 51f745c..dffabf3 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -175,7 +175,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, UNIPERIF_FIFO_DATA_OFFSET(uni); uni->irq = platform_get_irq(priv->pdev, 0); - if (!uni->irq < 0) { + if (uni->irq < 0) { dev_err(dev, "Failed to get IRQ resource"); return -ENXIO; } -- cgit v0.10.2 From c4a42915d84ad4b5b5e13aeed5da67f458e22399 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 21 Jul 2015 18:32:58 +0200 Subject: ASoC: kirkwood: prevent double streaming The kirkwood audio subsystem presents 2 PCM's for one source. Streaming on a second PCM while the first one is active cuts this last one. Then, ending the last stream gives a kernel trap in free_irq(). Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 4cf2245..dbfdfe9 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -148,10 +148,14 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) dram = mv_mbus_dram_info(); addr = substream->dma_buffer.addr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (priv->substream_play) + return -EBUSY; priv->substream_play = substream; kirkwood_dma_conf_mbus_windows(priv->io, KIRKWOOD_PLAYBACK_WIN, addr, dram); } else { + if (priv->substream_rec) + return -EBUSY; priv->substream_rec = substream; kirkwood_dma_conf_mbus_windows(priv->io, KIRKWOOD_RECORD_WIN, addr, dram); -- cgit v0.10.2 From b97e26980f6c13afad4c249b60a8dca7f5f86116 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 18:11:07 +0200 Subject: ASoC: dapm: Add helper function to free a widget snd_soc_tplg_widget_remove_all() has a verbatim copy of an older version of the widget freeing code from dapm_free_widgets(). Add a new helper function that takes care of freeing a widget and use it in both places. This removes the duplicated code and also makes sure that future changes to the widget freeing code only have to be made in one location. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 37d95a8..cadc7fc 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -397,6 +397,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); /* dapm events */ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e0de807..24ea692 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2312,30 +2312,36 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) kfree(path); } +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p, *next_p; + + list_del(&w->list); + /* + * remove source and sink paths associated to this widget. + * While removing the path, remove reference to it from both + * source and sink widgets so that path is removed only once. + */ + list_for_each_entry_safe(p, next_p, &w->sources, list_sink) + dapm_free_path(p); + + list_for_each_entry_safe(p, next_p, &w->sinks, list_source) + dapm_free_path(p); + + kfree(w->kcontrols); + kfree(w->name); + kfree(w); +} + /* free all dapm widgets and resources */ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) { struct snd_soc_dapm_widget *w, *next_w; - struct snd_soc_dapm_path *p, *next_p; list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { if (w->dapm != dapm) continue; - list_del(&w->list); - /* - * remove source and sink paths associated to this widget. - * While removing the path, remove reference to it from both - * source and sink widgets so that path is removed only once. - */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) - dapm_free_path(p); - - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) - dapm_free_path(p); - - kfree(w->kcontrols); - kfree(w->name); - kfree(w); + snd_soc_dapm_free_widget(w); } } diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index d096068..56dd108 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1734,7 +1734,6 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, u32 index) { struct snd_soc_dapm_widget *w, *next_w; - struct snd_soc_dapm_path *p, *next_p; list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { @@ -1746,31 +1745,9 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, if (w->dobj.index != index && w->dobj.index != SND_SOC_TPLG_INDEX_ALL) continue; - - list_del(&w->list); - - /* - * remove source and sink paths associated to this widget. - * While removing the path, remove reference to it from both - * source and sink widgets so that path is removed only once. - */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) { - list_del(&p->list_sink); - list_del(&p->list_source); - list_del(&p->list); - kfree(p); - } - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) { - list_del(&p->list_sink); - list_del(&p->list_source); - list_del(&p->list); - kfree(p); - } /* check and free and dynamic widget kcontrols */ snd_soc_tplg_widget_remove(w); - kfree(w->kcontrols); - kfree(w->name); - kfree(w); + snd_soc_dapm_free_widget(w); } } EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all); -- cgit v0.10.2 From 480689617510381391b3d906549477b948d9c4bc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 18:11:08 +0200 Subject: ASoC: dapm: Avoid duplicating immutable strings When creating a new widget from a template the name string of the template is duplicated for the newly created widget. This is necessary because in some cases the string might be stored on the stack or other volatile memory locations. But most of the time the string is static const data, which means it is possible to use it directly without having to worry that it might get freed or changed. Use kstrdup_const() to handle duplicating the string. This function is capable of detecting whether a string is immutable and if it is returns the input without duplicating it. This will slightly reduce the runtime memory footprint of DAPM and also speed up initialization. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 24ea692..cb4bc1c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2329,7 +2329,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) dapm_free_path(p); kfree(w->kcontrols); - kfree(w->name); + kfree_const(w->name); kfree(w); } @@ -3350,7 +3350,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, if (prefix) w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); else - w->name = kasprintf(GFP_KERNEL, "%s", widget->name); + w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { kfree(w); return NULL; -- cgit v0.10.2 From 2f01a33bd26545c16fea7592697f7f15c416402b Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 21 Jul 2015 09:51:29 +0800 Subject: usb: chipidea: ehci_init_driver is intended to call one time The ehci_init_driver is used to initialize hcd APIs for each ehci controller driver, it is designed to be called only one time and before driver register is called. The current design will cause ehci_init_driver is called multiple times at probe process, it will cause hc_driver's initialization affect current running hcd. We run out NULL pointer dereference problem when one hcd is started by module_init, and the other is started by otg thread at SMP platform. The reason for this problem is ehci_init_driver will do memory copy for current uniform hc_driver, and this memory copy will do memset (as 0) first, so when the first hcd is running usb_add_hcd, and the second hcd may clear the uniform hc_driver's space (at ehci_init_driver), then the first hcd will meet NULL pointer at the same time. See below two logs: LOG_1: ci_hdrc ci_hdrc.0: EHCI Host Controller ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1 ci_hdrc ci_hdrc.1: doesn't support gadget Unable to handle kernel NULL pointer dereference at virtual address 00000014 pgd = 80004000 [00000014] *pgd=00000000 Internal error: Oops: 805 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 108 Comm: kworker/u8:2 Not tainted 3.14.38-222193-g24b2734-dirty #25 Workqueue: ci_otg ci_otg_work task: d839ec00 ti: d8400000 task.ti: d8400000 PC is at ehci_run+0x4c/0x284 LR is at _raw_spin_unlock_irqrestore+0x28/0x54 pc : [<8041f9a0>] lr : [<8070ea84>] psr: 60000113 sp : d8401e30 ip : 00000000 fp : d8004400 r10: 00000001 r9 : 00000001 r8 : 00000000 r7 : 00000000 r6 : d8419940 r5 : 80dd24c0 r4 : d8419800 r3 : 8001d060 r2 : 00000000 r1 : 00000001 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 1000404a DAC: 00000015 Process kworker/u8:2 (pid: 108, stack limit = 0xd8400238) Stack: (0xd8401e30 to 0xd8402000) 1e20: d87523c0 d8401e48 66667562 d8419800 1e40: 00000000 00000000 d8419800 00000000 00000000 00000000 d84198b0 8040fcdc 1e60: 00000000 80dd320c d8477610 d8419c00 d803d010 d8419800 00000000 00000000 1e80: d8004400 00000000 d8400008 80431494 80431374 d803d100 d803d010 d803d1ac 1ea0: 00000000 80432428 804323d4 d803d100 00000001 80435eb8 80e0d0bc d803d100 1ec0: 00000006 80436458 00000000 d803d100 80e92ec8 80436f44 d803d010 d803d100 1ee0: d83fde00 8043292c d8752710 d803d1f4 d803d010 8042ddfc 8042ddb8 d83f3b00 1f00: d803d1f4 80042b60 00000000 00000003 00000001 00000001 80054598 d83f3b00 1f20: d8004400 d83f3b18 d8004414 d8400000 80e3957b 00000089 d8004400 80043814 1f40: d839ec00 00000000 d83fcd80 d83f3b00 800436e4 00000000 00000000 00000000 1f60: 00000000 80048f34 00000000 00000000 00000000 d83f3b00 00000000 00000000 1f80: d8401f80 d8401f80 00000000 00000000 d8401f90 d8401f90 d8401fac d83fcd80 1fa0: 80048e68 00000000 00000000 8000e538 00000000 00000000 00000000 00000000 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 [<8041f9a0>] (ehci_run) from [<8040fcdc>] (usb_add_hcd+0x248/0x6e8) [<8040fcdc>] (usb_add_hcd) from [<80431494>] (host_start+0x120/0x2e4) [<80431494>] (host_start) from [<80432428>] (ci_otg_start_host+0x54/0xbc) [<80432428>] (ci_otg_start_host) from [<80435eb8>] (otg_set_protocol+0xa4/0xd0) [<80435eb8>] (otg_set_protocol) from [<80436458>] (otg_set_state+0x574/0xc58) [<80436458>] (otg_set_state) from [<80436f44>] (otg_statemachine+0x408/0x46c) [<80436f44>] (otg_statemachine) from [<8043292c>] (ci_otg_fsm_work+0x3c/0x190) [<8043292c>] (ci_otg_fsm_work) from [<8042ddfc>] (ci_otg_work+0x44/0x1c4) [<8042ddfc>] (ci_otg_work) from [<80042b60>] (process_one_work+0xf4/0x35c) [<80042b60>] (process_one_work) from [<80043814>] (worker_thread+0x130/0x3bc) [<80043814>] (worker_thread) from [<80048f34>] (kthread+0xcc/0xe4) [<80048f34>] (kthread) from [<8000e538>] (ret_from_fork+0x14/0x3c) Code: e5953018 e3530000 0a000000 e12fff33 (e5878014) LOG_2: ci_hdrc ci_hdrc.0: EHCI Host Controller ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1 ci_hdrc ci_hdrc.1: doesn't support gadget Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = 80004000 [00000000] *pgd=00000000 In Online 00:00ternal e Offline rror: Oops: 80000005 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 108 Comm: kworker/u8:2 Not tainted 3.14.38-02007-g24b2734-dirty #127 Workque Online 00:00ue: ci_o Offline tg ci_otg_work Online 00:00task: d8 Offline 39ec00 ti: d83ea000 task.ti: d83ea000 PC is at 0x0 LR is at usb_add_hcd+0x248/0x6e8 pc : [<00000000>] lr : [<8040f644>] psr: 60000113 sp : d83ebe60 ip : 00000000 fp : d8004400 r10: 00000001 r9 : 00000001 r8 : d85fd4b0 r7 : 00000000 r6 : 00000000 r5 : 00000000 r4 : d85fd400 r3 : 00000000 r2 : d85fd4f4 r1 : 80410178 r0 : d85fd400 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 1000404a DAC: 00000015 Process kworker/u8:2 (pid: 108, stack limit = 0xd83ea238) Stack: (0xd83ebe60 to 0xd83ec000) be60: 00000000 80dd920c d8654e10 d85fd800 d803e010 d85fd400 00000000 00000000 be80: d8004400 00000000 d83ea008 80430e34 80430d14 d803e100 d803e010 d803e1ac bea0: 00000000 80431dc8 80431d74 d803e100 00000001 80435858 80e130bc d803e100 bec0: 00000006 80435df8 00000000 d803e100 80e98ec8 804368e4 d803e010 d803e100 bee0: d86e8100 804322cc d86cf050 d803e1f4 d803e010 8042d79c 8042d758 d83cf900 bf00: d803e1f4 80042b78 00000000 00000003 00000001 00000001 800545e8 d83cf900 bf20: d8004400 d83cf918 d8004414 d83ea000 80e3f57b 00000089 d8004400 8004382c bf40: d839ec00 00000000 d8393780 d83cf900 800436fc 00000000 00000000 00000000 bf60: 00000000 80048f50 80e019f4 00000000 0000264c d83cf900 00000000 00000000 bf80: d83ebf80 d83ebf80 00000000 00000000 d83ebf90 d83ebf90 d83ebfac d8393780 bfa0: 80048e84 00000000 00000000 8000e538 00000000 00000000 00000000 00000000 bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 ee66e85d 133ebd03 [<804 Online 00:000f644>] Offline (usb_add_hcd) from [<80430e34>] (host_start+0x120/0x2e4) [<80430e34>] (host_start) from [<80431dc8>] (ci_otg_start_host+0x54/0xbc) [<80431dc8>] (ci_otg_start_host) from [<80435858>] (otg_set_protocol+0xa4/0xd0) [<80435858>] (otg_set_protocol) from [<80435df8>] (otg_set_state+0x574/0xc58) [<80435df8>] (otg_set_state) from [<804368e4>] (otg_statemachine+0x408/0x46c) [<804368e4>] (otg_statemachine) from [<804322cc>] (ci_otg_fsm_work+0x3c/0x190) [<804322cc>] (ci_otg_fsm_work) from [<8042d79c>] (ci_otg_work+0x44/0x1c4) [<8042d79c>] (ci_otg_work) from [<80042b78>] (process_one_work+0xf4/0x35c) [<80042b78>] (process_one_work) from [<8004382c>] (worker_thread+0x130/0x3bc) [<8004382c>] (worker_thread) from [<80048f50>] (kthread+0xcc/0xe4) [<80048f50>] (kthread) from [<8000e538>] (ret_from_fork+0x14/0x3c) Code: bad PC value Cc: Jun Li Cc: Cc: Alan Stern Acked-by: Alan Stern Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 74fea4f..3ad48e1 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -1024,7 +1024,18 @@ static struct platform_driver ci_hdrc_driver = { }, }; -module_platform_driver(ci_hdrc_driver); +static int __init ci_hdrc_platform_register(void) +{ + ci_hdrc_host_driver_init(); + return platform_driver_register(&ci_hdrc_driver); +} +module_init(ci_hdrc_platform_register); + +static void __exit ci_hdrc_platform_unregister(void) +{ + platform_driver_unregister(&ci_hdrc_driver); +} +module_exit(ci_hdrc_platform_unregister); MODULE_ALIAS("platform:ci_hdrc"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 6cf87b8..7161439 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -249,9 +249,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci) rdrv->name = "host"; ci->roles[CI_ROLE_HOST] = rdrv; + return 0; +} + +void ci_hdrc_host_driver_init(void) +{ ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides); orig_bus_suspend = ci_ehci_hc_driver.bus_suspend; ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend; - - return 0; } diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h index 5707bf3..0f12f13 100644 --- a/drivers/usb/chipidea/host.h +++ b/drivers/usb/chipidea/host.h @@ -5,6 +5,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci); void ci_hdrc_host_destroy(struct ci_hdrc *ci); +void ci_hdrc_host_driver_init(void); #else @@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci) } +static void ci_hdrc_host_driver_init(void) +{ + +} + #endif #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ -- cgit v0.10.2 From 6a75c0b62b0981c3a34d3336725b0840747e7680 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 22 Jul 2015 09:59:47 +0800 Subject: ASoC: cs4349: Remove unneeded NULL test for cs4349->reset_gpio It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a7538ae..852be85 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -300,8 +300,7 @@ static int cs4349_i2c_probe(struct i2c_client *client, if (IS_ERR(cs4349->reset_gpio)) return PTR_ERR(cs4349->reset_gpio); - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); i2c_set_clientdata(client, cs4349); @@ -316,8 +315,7 @@ static int cs4349_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); /* Hold down reset */ - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); return 0; } @@ -335,8 +333,7 @@ static int cs4349_runtime_suspend(struct device *dev) regcache_cache_only(cs4349->regmap, true); /* Hold down reset */ - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); return 0; } @@ -350,8 +347,7 @@ static int cs4349_runtime_resume(struct device *dev) if (ret < 0) return ret; - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); regcache_cache_only(cs4349->regmap, false); regcache_sync(cs4349->regmap); -- cgit v0.10.2 From ec12693e5d03c7e6399ba1e9150908527b809f33 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 22 Jul 2015 10:22:33 +0800 Subject: ASoC: cs4349: Fix up setting PWR_DWN bit The PWR_DWN is Bit 7, so current code does not set the PWR_DWN bit. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 852be85..0d010c2 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -326,7 +326,7 @@ static int cs4349_runtime_suspend(struct device *dev) struct cs4349_private *cs4349 = dev_get_drvdata(dev); int ret; - ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 1); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, PWR_DWN); if (ret < 0) return ret; -- cgit v0.10.2 From 775b07de4fa470ac10cd74f1b1a8d441b4f5838d Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Wed, 22 Jul 2015 17:39:35 +0800 Subject: ASoC: mediatek: Add suspend/resume callbacks This adds suspend/resume callbacks, which are common for each DAI. To be able to continue the last playback/capture after resume when suspend was done during a playback/capture, in the callbacks we do backup/restore of registers which were set before prepare stage. Registers to be backup/restore are defined in a backup list array. Signed-off-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index a88b175..cc4393c 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -98,12 +98,4 @@ struct mtk_afe_memif { const struct mtk_afe_irq_data *irqdata; }; -struct mtk_afe { - /* address for ioremap audio hardware register */ - void __iomem *base_addr; - struct device *dev; - struct regmap *regmap; - struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; - struct clk *clocks[MTK_CLK_NUM]; -}; #endif diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 5b74afb..ef252a6 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -45,18 +45,21 @@ /* Memory interface */ #define AFE_DL1_BASE 0x0040 #define AFE_DL1_CUR 0x0044 +#define AFE_DL1_END 0x0048 #define AFE_DL2_BASE 0x0050 #define AFE_DL2_CUR 0x0054 #define AFE_AWB_BASE 0x0070 #define AFE_AWB_CUR 0x007c #define AFE_VUL_BASE 0x0080 #define AFE_VUL_CUR 0x008c +#define AFE_VUL_END 0x0088 #define AFE_DAI_BASE 0x0090 #define AFE_DAI_CUR 0x009c #define AFE_MOD_PCM_BASE 0x0330 #define AFE_MOD_PCM_CUR 0x033c #define AFE_HDMI_OUT_BASE 0x0374 #define AFE_HDMI_OUT_CUR 0x0378 +#define AFE_HDMI_OUT_END 0x037c #define AFE_ADDA2_TOP_CON0 0x0600 @@ -127,6 +130,34 @@ enum afe_tdm_ch_start { AFE_TDM_CH_ZERO, }; +static const unsigned int mtk_afe_backup_list[] = { + AUDIO_TOP_CON0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN7, + AFE_CONN8, + AFE_DAC_CON1, + AFE_DL1_BASE, + AFE_DL1_END, + AFE_VUL_BASE, + AFE_VUL_END, + AFE_HDMI_OUT_BASE, + AFE_HDMI_OUT_END, + AFE_HDMI_CONN0, + AFE_DAC_CON0, +}; + +struct mtk_afe { + /* address for ioremap audio hardware register */ + void __iomem *base_addr; + struct device *dev; + struct regmap *regmap; + struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; + struct clk *clocks[MTK_CLK_NUM]; + unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)]; + bool suspended; +}; + static const struct snd_pcm_hardware mtk_afe_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), @@ -722,11 +753,53 @@ static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = { }; +static int mtk_afe_runtime_suspend(struct device *dev); +static int mtk_afe_runtime_resume(struct device *dev); + +static int mtk_afe_dai_suspend(struct snd_soc_dai *dai) +{ + struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + int i; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || afe->suspended) + return 0; + + for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) + regmap_read(afe->regmap, mtk_afe_backup_list[i], + &afe->backup_regs[i]); + + afe->suspended = true; + mtk_afe_runtime_suspend(afe->dev); + return 0; +} + +static int mtk_afe_dai_resume(struct snd_soc_dai *dai) +{ + struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + int i = 0; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || !afe->suspended) + return 0; + + mtk_afe_runtime_resume(afe->dev); + + for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) + regmap_write(afe->regmap, mtk_afe_backup_list[i], + afe->backup_regs[i]); + + afe->suspended = false; + return 0; +} + static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { /* FE DAIs: memory intefaces to CPU */ { .name = "DL1", /* downlink 1 */ .id = MTK_AFE_MEMIF_DL1, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .playback = { .stream_name = "DL1", .channels_min = 1, @@ -738,6 +811,8 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { }, { .name = "VUL", /* voice uplink */ .id = MTK_AFE_MEMIF_VUL, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .capture = { .stream_name = "VUL", .channels_min = 1, @@ -774,6 +849,8 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { { .name = "HDMI", .id = MTK_AFE_MEMIF_HDMI, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .playback = { .stream_name = "HDMI", .channels_min = 2, -- cgit v0.10.2 From 6dd3f13e4239a8c2b1e60687d7321bc0df614f33 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Thu, 16 Jul 2015 18:23:53 +0200 Subject: kbuild: Do not pick up ARCH_{CPP,A,C}FLAGS from the environment Initialize the ARCH_* overrides before including the arch Makefile, to avoid picking up the values from the environment. The variables can still be overriden on the make command line, but this won't happen by accident. Signed-off-by: Michal Marek diff --git a/Makefile b/Makefile index 13270c0..dc868bc 100644 --- a/Makefile +++ b/Makefile @@ -597,6 +597,11 @@ endif # $(dot-config) # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux +# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default +# values of the respective KBUILD_* variables +ARCH_CPPFLAGS := +ARCH_AFLAGS := +ARCH_CFLAGS := include arch/$(SRCARCH)/Makefile KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) -- cgit v0.10.2 From 3d1450d54a4fc277fc4598acf2335f74b66b08fc Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 7 Jul 2015 20:26:07 +0200 Subject: Makefile: Force gzip and xz on module install Running `make modules_install` ordinarily will overwrite existing modules. This is the desired behavior, and is how pretty much every other `make install` target works. However, if CONFIG_MODULE_COMPRESS is enabled, modules are passed through gzip and xz which then do the file writing. Both gzip and xz will error out if the file already exists, unless -f is passed. This patch adds -f so that the behavior is uniform. Signed-off-by: Jason A. Donenfeld Signed-off-by: Michal Marek diff --git a/Makefile b/Makefile index dc868bc..c5234fe 100644 --- a/Makefile +++ b/Makefile @@ -852,10 +852,10 @@ export mod_strip_cmd mod_compress_cmd = true ifdef CONFIG_MODULE_COMPRESS ifdef CONFIG_MODULE_COMPRESS_GZIP - mod_compress_cmd = gzip -n + mod_compress_cmd = gzip -n -f endif # CONFIG_MODULE_COMPRESS_GZIP ifdef CONFIG_MODULE_COMPRESS_XZ - mod_compress_cmd = xz + mod_compress_cmd = xz -f endif # CONFIG_MODULE_COMPRESS_XZ endif # CONFIG_MODULE_COMPRESS export mod_compress_cmd -- cgit v0.10.2 From 450ed0db011d200a691591a75fdbcd7cae1a9b4a Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 16 Jul 2015 21:45:17 +0300 Subject: ARCv2: allow selection of page size for MMUv4 MMUv4 also supports the configurable page size as MMUv3. Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index f7cfa7d..a5fccdf 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -313,11 +313,11 @@ config ARC_PAGE_SIZE_8K config ARC_PAGE_SIZE_16K bool "16KB" - depends on ARC_MMU_V3 + depends on ARC_MMU_V3 || ARC_MMU_V4 config ARC_PAGE_SIZE_4K bool "4KB" - depends on ARC_MMU_V3 + depends on ARC_MMU_V3 || ARC_MMU_V4 endchoice -- cgit v0.10.2 From 6f043b50da8e03bdcc5703fd37ea45bc6892432f Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 21 Jul 2015 22:07:47 -0700 Subject: crypto: qat - Fix invalid synchronization between register/unregister sym algs The synchronization method used atomic was bogus. Use a proper synchronization with mutex. Cc: stable@vger.kernel.org Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index 067402c..df427c0 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -73,7 +73,8 @@ ICP_QAT_HW_CIPHER_KEY_CONVERT, \ ICP_QAT_HW_CIPHER_DECRYPT) -static atomic_t active_dev; +static DEFINE_MUTEX(algs_lock); +static unsigned int active_devs; struct qat_alg_buf { uint32_t len; @@ -1280,7 +1281,10 @@ static struct crypto_alg qat_algs[] = { { int qat_algs_register(void) { - if (atomic_add_return(1, &active_dev) == 1) { + int ret = 0; + + mutex_lock(&algs_lock); + if (++active_devs == 1) { int i; for (i = 0; i < ARRAY_SIZE(qat_algs); i++) @@ -1289,21 +1293,25 @@ int qat_algs_register(void) CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC : CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; - return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs)); + ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs)); } - return 0; + mutex_unlock(&algs_lock); + return ret; } int qat_algs_unregister(void) { - if (atomic_sub_return(1, &active_dev) == 0) - return crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs)); - return 0; + int ret = 0; + + mutex_lock(&algs_lock); + if (--active_devs == 0) + ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs)); + mutex_unlock(&algs_lock); + return ret; } int qat_algs_init(void) { - atomic_set(&active_dev, 0); crypto_get_default_rng(); return 0; } -- cgit v0.10.2 From f898c522f0e9ac9f3177d0762b76e2ab2d2cf9c0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2015 18:05:35 +0800 Subject: crypto: ixp4xx - Remove bogus BUG_ON on scattered dst buffer This patch removes a bogus BUG_ON in the ablkcipher path that triggers when the destination buffer is different from the source buffer and is scattered. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 7ba495f..402631a 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -905,7 +905,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt) crypt->mode |= NPE_OP_NOT_IN_PLACE; /* This was never tested by Intel * for more than one dst buffer, I think. */ - BUG_ON(req->dst->length < nbytes); req_ctx->dst = NULL; if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, flags, DMA_FROM_DEVICE)) -- cgit v0.10.2 From 4c38b9c30f78d44c576ca3049577fbd4d5c2acc6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:28:50 +0800 Subject: ASoC: cs35l32: Fix define for CS35L32_SDOUT_3ST According to the datasheet, the CS35L32_SDOUT_3ST is BIT(3). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h index 31ab804..1d6c250 100644 --- a/sound/soc/codecs/cs35l32.h +++ b/sound/soc/codecs/cs35l32.h @@ -80,7 +80,7 @@ struct cs35l32_platform_data { #define CS35L32_GAIN_MGR_MASK 0x08 #define CS35L32_ADSP_SHARE_MASK 0x08 #define CS35L32_ADSP_DATACFG_MASK 0x30 -#define CS35L32_SDOUT_3ST 0x80 +#define CS35L32_SDOUT_3ST 0x08 #define CS35L32_BATT_REC_MASK 0x0E #define CS35L32_BATT_THRESH_MASK 0x30 -- cgit v0.10.2 From d5a78c8ea050e9c81db1e25a4916d8d9168dfb2e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:29:57 +0800 Subject: ASoC: cs35l32: Remove unneeded NULL test for cs35l32->reset_gpio It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025..f5f86b2 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -441,8 +441,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, if (IS_ERR(cs35l32->reset_gpio)) return PTR_ERR(cs35l32->reset_gpio); - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); /* initialize codec */ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); @@ -536,8 +535,7 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client) snd_soc_unregister_codec(&i2c_client->dev); /* Hold down reset */ - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); return 0; } @@ -551,8 +549,7 @@ static int cs35l32_runtime_suspend(struct device *dev) regcache_mark_dirty(cs35l32->regmap); /* Hold down reset */ - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); /* remove power */ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), @@ -575,8 +572,7 @@ static int cs35l32_runtime_resume(struct device *dev) return ret; } - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); regcache_cache_only(cs35l32->regmap, false); regcache_sync(cs35l32->regmap); -- cgit v0.10.2 From 8626e5eb6c33b78ba7a5eb7cfbc5109896f443ef Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:26:57 +0800 Subject: ASoC: cs42l73: Fix mask for setting CS42L73_SP_3ST bit CS42L73_SP_3ST is BIT(7), so the mask field is wrong. Fix it. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index b7853b9..efd924a 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1236,8 +1236,8 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate) struct snd_soc_codec *codec = dai->codec; int id = dai->id; - return snd_soc_update_bits(codec, CS42L73_SPC(id), - 0x7F, tristate << 7); + return snd_soc_update_bits(codec, CS42L73_SPC(id), CS42L73_SP_3ST, + tristate << 7); } static const struct snd_pcm_hw_constraint_list constraints_12_24 = { -- cgit v0.10.2 From f285f1610341af4181791938777e0affb5531278 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:32:04 +0800 Subject: ASoC: rt5677: Remove NULL test for desc before gpiod_set_value_cansleep call It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 13b871f..62230e0 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4763,10 +4763,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4780,10 +4778,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4794,10 +4790,8 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 1); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); -- cgit v0.10.2 From 95f1044f5674b53f67e0933abff228c594792f4c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 22:56:04 +0800 Subject: ASoC: tas2552: Fix off-by-one for max_register setting The latest valid register is TAS2552_VBAT_DATA. Signed-off-by: Axel Lin Acked-by: Dan Murphy Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h index 5746f8f..e34752b 100644 --- a/sound/soc/codecs/tas2552.h +++ b/sound/soc/codecs/tas2552.h @@ -42,7 +42,7 @@ #define TAS2552_BOOST_APT_CTRL 0x14 #define TAS2552_VER_NUM 0x16 #define TAS2552_VBAT_DATA 0x19 -#define TAS2552_MAX_REG 0x20 +#define TAS2552_MAX_REG TAS2552_VBAT_DATA /* CFG1 Register Masks */ #define TAS2552_DEV_RESET (1 << 0) -- cgit v0.10.2 From 9425e9d8c77dd9f40c5f199127a63be2e2b7c1f4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:13:36 +0800 Subject: ASoC: tas5086: Improve the logic for de-emphasis sampling rate selection Slightly improve the logic for de-emphasis sampling rate selection by break out the loop if the rate is matched. Signed-off-by: Axel Lin Acked-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 32942be..16a6c64 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -266,10 +266,14 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int i, val = 0; - if (priv->deemph) - for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) - if (tas5086_deemph[i] == priv->rate) + if (priv->deemph) { + for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) { + if (tas5086_deemph[i] == priv->rate) { val = i; + break; + } + } + } return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1, TAS5086_DEEMPH_MASK, val); -- cgit v0.10.2 From 5f1d980ee9b6353f18765bfa6774a5a08d6cb944 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:00 +0200 Subject: ALSA: ac97: Add helper function to reset the AC97 device There is currently a lot of code duplication in ASoC drivers regarding the reset handling of devices. This patch introduces a new generic reset function in the generic AC'97 framework that can be used to replace most the custom reset functions. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 0e9d75b..74bc8547 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -584,6 +584,8 @@ static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, void snd_ac97_suspend(struct snd_ac97 *ac97); void snd_ac97_resume(struct snd_ac97 *ac97); #endif +int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id, + unsigned int id_mask); /* quirk types */ enum { diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 2b50cbe..55791a0 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -18,6 +18,68 @@ #include /* + * snd_ac97_check_id() - Reads and checks the vendor ID of the device + * @ac97: The AC97 device to check + * @id: The ID to compare to + * @id_mask: Mask that is applied to the device ID before comparing to @id + * + * If @id is 0 this function returns true if the read device vendor ID is + * a valid ID. If @id is non 0 this functions returns true if @id + * matches the read vendor ID. Otherwise the function returns false. + */ +static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id, + unsigned int id_mask) +{ + ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16; + ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2); + + if (ac97->id == 0x0 || ac97->id == 0xffffffff) + return false; + + if (id != 0 && id != (ac97->id & id_mask)) + return false; + + return true; +} + +/** + * snd_ac97_reset() - Reset AC'97 device + * @ac97: The AC'97 device to reset + * @try_warm: Try a warm reset first + * @id: Expected device vendor ID + * @id_mask: Mask that is applied to the device ID before comparing to @id + * + * This function resets the AC'97 device. If @try_warm is true the function + * first performs a warm reset. If the warm reset is successful the function + * returns 1. Otherwise or if @try_warm is false the function issues cold reset + * followed by a warm reset. If this is successful the function returns 0, + * otherwise a negative error code. If @id is 0 any valid device ID will be + * accepted, otherwise only the ID that matches @id and @id_mask is accepted. + */ +int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id, + unsigned int id_mask) +{ + struct snd_ac97_bus_ops *ops = ac97->bus->ops; + + if (try_warm && ops->warm_reset) { + ops->warm_reset(ac97); + if (snd_ac97_check_id(ac97, id, id_mask)) + return 1; + } + + if (ops->reset) + ops->reset(ac97); + if (ops->warm_reset) + ops->warm_reset(ac97); + + if (snd_ac97_check_id(ac97, id, id_mask)) + return 0; + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(snd_ac97_reset); + +/* * Let drivers decide whether they want to support given codec from their * probe method. Drivers have direct access to the struct snd_ac97 * structure and may decide based on the id field amongst other things. -- cgit v0.10.2 From 7361fbeaeaab5282bbfc88f1f6fe4cf034f7623c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:01 +0200 Subject: ASoC: ac97: Add support for resetting device before registration AC97 devices need to be initially reset before they can be used. Currently each driver does this on its own. Add support for resetting the device to core in snd_soc_new_ac97_codec(). If the caller supplies a device ID and device ID mask the function will reset the device and verify that it has the correct ID, if it does not a error is returned. This will allow to remove custom code with similar functionality from individual drivers. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf..42d144a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -526,7 +526,8 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, #ifdef CONFIG_SND_SOC_AC97_BUS struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec); -struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec); +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + unsigned int id, unsigned int id_mask); void snd_soc_free_ac97_codec(struct snd_ac97 *ac97); int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 3cc69a6..d9cb81d 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -240,7 +240,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) u16 vendor_id2; u16 ext_status; - ac97 = snd_soc_new_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, 0, 0); if (IS_ERR(ac97)) { ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index ed4cca7..c602830 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -332,7 +332,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) struct snd_ac97 *ac97; int ret = 0; - ac97 = snd_soc_new_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, 0, 0); if (IS_ERR(ac97)) return PTR_ERR(ac97); diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 08d7259..d40efc9 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -85,10 +85,19 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_codec); /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec + * @id: The expected device ID + * @id_mask: Mask that is applied to the device ID before comparing with @id * * Initialises AC97 codec resources for use by ad-hoc devices only. + * + * If @id is not 0 this function will reset the device, then read the ID from + * the device and check if it matches the expected ID. If it doesn't match an + * error will be returned and device will not be registered. + * + * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success. */ -struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + unsigned int id, unsigned int id_mask) { struct snd_ac97 *ac97; int ret; @@ -97,13 +106,24 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) if (IS_ERR(ac97)) return ac97; - ret = device_add(&ac97->dev); - if (ret) { - put_device(&ac97->dev); - return ERR_PTR(ret); + if (id) { + ret = snd_ac97_reset(ac97, false, id, id_mask); + if (ret < 0) { + dev_err(codec->dev, "Failed to reset AC97 device: %d\n", + ret); + goto err_put_device; + } } + ret = device_add(&ac97->dev); + if (ret) + goto err_put_device; + return ac97; + +err_put_device: + put_device(&ac97->dev); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); -- cgit v0.10.2 From 3ab3dbdfb91b70ef6bf4eb9b544bf54ff1dff51a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:02 +0200 Subject: ASoC: ad1980: Use core AC'97 reset helper Use the new snd_ac97_reset() helper function to perform the reset and verify the device ID. Unfortunately the reset can't be done in snd_soc_new_ac97_codec() due to the special requirements in order to support the non-standard 16-bit slot mode of the ad1980. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index d9cb81d..9ef20db 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -202,19 +202,21 @@ static struct snd_soc_dai_driver ad1980_dai = { .formats = SND_SOC_STD_AC97_FMTS, }, }; +#define AD1980_VENDOR_ID 0x41445300 +#define AD1980_VENDOR_MASK 0xffffff00 + static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); unsigned int retry_cnt = 0; + int ret; do { - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(ac97); - if (snd_soc_read(codec, AC97_RESET) == 0x0090) - return 1; - } + ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID, + AD1980_VENDOR_MASK); + if (ret >= 0) + return 0; - soc_ac97_ops->reset(ac97); /* * Set bit 16slot in register 74h, then every slot will has only * 16 bits. This command is sent out in 20bit mode, in which @@ -223,8 +225,6 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) */ snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900); - if (snd_soc_read(codec, AC97_RESET) == 0x0090) - return 0; } while (retry_cnt++ < 10); dev_err(codec->dev, "Failed to reset: AC97 link error\n"); @@ -260,22 +260,10 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) if (ret < 0) goto reset_err; - /* Read out vendor ID to make sure it is ad1980 */ - if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { - ret = -ENODEV; - goto reset_err; - } - vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2); - - if (vendor_id2 != 0x5370) { - if (vendor_id2 != 0x5374) { - ret = -ENODEV; - goto reset_err; - } else { - dev_warn(codec->dev, - "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); - } + if (vendor_id2 == 0x5374) { + dev_warn(codec->dev, + "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); } /* unmute captures and playbacks volume */ -- cgit v0.10.2 From 017e800af9f91861dcd6e4fd8a29418de86fd884 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:03 +0200 Subject: ASoC: stac9766: Use core reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index c602830..0945c51 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -28,6 +28,9 @@ #include "stac9766.h" +#define STAC9766_VENDOR_ID 0x83847666 +#define STAC9766_VENDOR_ID_MASK 0xffffffff + /* * STAC9766 register cache */ @@ -239,45 +242,12 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(ac97); - if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) - return 1; - } - - soc_ac97_ops->reset(ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(ac97); - if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) - return -EIO; - return 0; -} - static int stac9766_codec_resume(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 id, reset; - reset = 0; - /* give the codec an AC97 warm reset to start the link */ -reset: - if (reset > 5) { - dev_err(codec->dev, "Failed to resume\n"); - return -EIO; - } - ac97->bus->ops->warm_reset(ac97); - id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2); - if (id != 0x4c13) { - stac9766_reset(codec, 0); - reset++; - goto reset; - } - - return 0; + return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID, + STAC9766_VENDOR_ID_MASK); } static const struct snd_soc_dai_ops stac9766_dai_ops_analog = { @@ -330,28 +300,15 @@ static struct snd_soc_dai_driver stac9766_dai[] = { static int stac9766_codec_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; - int ret = 0; - ac97 = snd_soc_new_ac97_codec(codec, 0, 0); + ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, + STAC9766_VENDOR_ID_MASK); if (IS_ERR(ac97)) return PTR_ERR(ac97); snd_soc_codec_set_drvdata(codec, ac97); - /* do a cold reset for the controller and then try - * a warm reset followed by an optional cold reset for codec */ - stac9766_reset(codec, 0); - ret = stac9766_reset(codec, 1); - if (ret < 0) { - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - goto codec_err; - } - return 0; - -codec_err: - snd_soc_free_ac97_codec(ac97); - return ret; } static int stac9766_codec_remove(struct snd_soc_codec *codec) -- cgit v0.10.2 From 6e0b73a0a172f4d881092e388b3a3ad57ca80107 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:04 +0200 Subject: ASoC: wm9705: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 5cc457e..744842c 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -22,6 +22,9 @@ #include "wm9705.h" +#define WM9705_VENDOR_ID 0x574d4c05 +#define WM9705_VENDOR_ID_MASK 0xffffffff + /* * WM9705 register cache */ @@ -293,21 +296,6 @@ static struct snd_soc_dai_driver wm9705_dai[] = { } }; -static int wm9705_reset(struct snd_soc_codec *codec) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - - if (soc_ac97_ops->reset) { - soc_ac97_ops->reset(ac97); - if (ac97_read(codec, 0) == wm9705_reg[0]) - return 0; /* Success */ - } - - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - - return -EIO; -} - #ifdef CONFIG_PM static int wm9705_soc_suspend(struct snd_soc_codec *codec) { @@ -324,7 +312,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) int i, ret; u16 *cache = codec->reg_cache; - ret = wm9705_reset(codec); + ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID, + WM9705_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -342,30 +331,17 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) static int wm9705_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; - int ret = 0; - ac97 = snd_soc_alloc_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID, + WM9705_VENDOR_ID_MASK); if (IS_ERR(ac97)) { - ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec\n"); - return ret; + return PTR_ERR(ac97); } - ret = wm9705_reset(codec); - if (ret) - goto err_put_device; - - ret = device_add(&ac97->dev); - if (ret) - goto err_put_device; - snd_soc_codec_set_drvdata(codec, ac97); return 0; - -err_put_device: - put_device(&ac97->dev); - return ret; } static int wm9705_soc_remove(struct snd_soc_codec *codec) -- cgit v0.10.2 From a575be4cbb951244f93342487c2537f729f2239d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:05 +0200 Subject: ASoC: wm9712: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 1fda104..488a922 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -23,6 +23,9 @@ #include #include "wm9712.h" +#define WM9712_VENDOR_ID 0x574d4c12 +#define WM9712_VENDOR_ID_MASK 0xffffffff + struct wm9712_priv { struct snd_ac97 *ac97; unsigned int hp_mixer[2]; @@ -613,35 +616,14 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(wm9712->ac97); - if (ac97_read(codec, 0) == wm9712_reg[0]) - return 1; - } - - soc_ac97_ops->reset(wm9712->ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(wm9712->ac97); - if (ac97_read(codec, 0) != wm9712_reg[0]) - goto err; - return 0; - -err: - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - return -EIO; -} - static int wm9712_soc_resume(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); int i, ret; u16 *cache = codec->reg_cache; - ret = wm9712_reset(codec, 1); + ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID, + WM9712_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -663,31 +645,20 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) static int wm9712_soc_probe(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - int ret = 0; + int ret; - wm9712->ac97 = snd_soc_alloc_ac97_codec(codec); + wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, + WM9712_VENDOR_ID_MASK); if (IS_ERR(wm9712->ac97)) { ret = PTR_ERR(wm9712->ac97); dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); return ret; } - ret = wm9712_reset(codec, 0); - if (ret < 0) - goto err_put_device; - - ret = device_add(&wm9712->ac97->dev); - if (ret) - goto err_put_device; - /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); return 0; - -err_put_device: - put_device(&wm9712->ac97->dev); - return ret; } static int wm9712_soc_remove(struct snd_soc_codec *codec) -- cgit v0.10.2 From 310398f5e4618e9a0f6fd0c4b152401daf06c215 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:06 +0200 Subject: ASoC: wm9713: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 89cd2d6..955e651 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -29,6 +29,9 @@ #include "wm9713.h" +#define WM9713_VENDOR_ID 0x574d4c13 +#define WM9713_VENDOR_ID_MASK 0xffffffff + struct wm9713_priv { struct snd_ac97 *ac97; u32 pll_in; /* PLL input frequency */ @@ -1123,28 +1126,6 @@ static struct snd_soc_dai_driver wm9713_dai[] = { }, }; -int wm9713_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(wm9713->ac97); - if (ac97_read(codec, 0) == wm9713_reg[0]) - return 1; - } - - soc_ac97_ops->reset(wm9713->ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(wm9713->ac97); - if (ac97_read(codec, 0) != wm9713_reg[0]) { - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL_GPL(wm9713_reset); - static int wm9713_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -1196,7 +1177,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) int i, ret; u16 *cache = codec->reg_cache; - ret = wm9713_reset(codec, 1); + ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID, + WM9713_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -1222,32 +1204,18 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - int ret = 0, reg; + int reg; - wm9713->ac97 = snd_soc_alloc_ac97_codec(codec); + wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID, + WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) return PTR_ERR(wm9713->ac97); - /* do a cold reset for the controller and then try - * a warm reset followed by an optional cold reset for codec */ - wm9713_reset(codec, 0); - ret = wm9713_reset(codec, 1); - if (ret < 0) - goto err_put_device; - - ret = device_add(&wm9713->ac97->dev); - if (ret) - goto err_put_device; - /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); return 0; - -err_put_device: - put_device(&wm9713->ac97->dev); - return ret; } static int wm9713_soc_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index 793da86..53df11b 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h @@ -45,6 +45,4 @@ #define WM9713_DAI_AC97_AUX 1 #define WM9713_DAI_PCM_VOICE 2 -int wm9713_reset(struct snd_soc_codec *codec, int try_warm); - #endif -- cgit v0.10.2 From 473eb87adcf69204cd7e8fb5b0e4956edd6feae3 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 21 Jul 2015 23:53:55 +0530 Subject: ASoC: Intel: Skylake: Add NHLT support to get BE config The Non-HD Audio Endpoint Description table contains the link configuration information for the DSP. This is specific to Non HDA links only, like I2s and PDM Skylake driver will use NHLT table to retrieve the configuration based on the link type, format, channel and rate. This configuration is passed to DSP FW Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 1fccb37..b35faef 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,4 +1,4 @@ -snd-soc-skl-objs := skl.o skl-pcm.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c new file mode 100644 index 0000000..5c0895e --- /dev/null +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -0,0 +1,141 @@ +/* + * skl-nhlt.c - Intel SKL Platform NHLT parsing + * + * Copyright (C) 2015 Intel Corp + * Author: Sanjiv Kumar + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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 "skl.h" + +/* Unique identification for getting NHLT blobs */ +static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, + 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; + +#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" + +void __iomem *skl_nhlt_init(struct device *dev) +{ + acpi_handle handle; + union acpi_object *obj; + struct nhlt_resource_desc *nhlt_ptr = NULL; + + if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { + dev_err(dev, "Requested NHLT device not found\n"); + return NULL; + } + + obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); + if (obj && obj->type == ACPI_TYPE_BUFFER) { + nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; + + return ioremap_cache(nhlt_ptr->min_addr, nhlt_ptr->length); + } + + dev_err(dev, "device specific method to extract NHLT blob failed\n"); + return NULL; +} + +void skl_nhlt_free(void __iomem *addr) +{ + iounmap(addr); + addr = NULL; +} + +static struct nhlt_specific_cfg *skl_get_specific_cfg( + struct device *dev, struct nhlt_fmt *fmt, + u8 no_ch, u8 rate, u16 bps) +{ + struct nhlt_specific_cfg *sp_config; + struct wav_fmt *wfmt; + struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; + int i; + + dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); + + for (i = 0; i < fmt->fmt_count; i++) { + wfmt = &fmt_config->fmt_ext.fmt; + dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, + wfmt->bits_per_sample, wfmt->samples_per_sec); + if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate && + wfmt->bits_per_sample == bps) { + sp_config = &fmt_config->config; + + return sp_config; + } + + fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + + fmt_config->config.size); + } + + return NULL; +} + +static void dump_config(struct device *dev, u32 instance_id, u8 linktype, + u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) +{ + dev_dbg(dev, "Input configuration\n"); + dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); + dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); + dev_dbg(dev, "bits_per_sample=%d\n", bps); +} + +static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, + u32 instance_id, u8 link_type, u8 dirn) +{ + dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n", + epnt->virtual_bus_id, epnt->linktype, epnt->direction); + + if ((epnt->virtual_bus_id == instance_id) && + (epnt->linktype == link_type) && + (epnt->direction == dirn)) + return true; + else + return false; +} + +struct nhlt_specific_cfg +*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, + u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn) +{ + struct nhlt_fmt *fmt; + struct nhlt_endpoint *epnt; + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct device *dev = bus->dev; + struct nhlt_specific_cfg *sp_config; + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + u16 bps = num_ch * s_fmt; + u8 j; + + dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); + + epnt = (struct nhlt_endpoint *)nhlt->desc; + + dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); + + for (j = 0; j < nhlt->endpoint_count; j++) { + if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { + fmt = (struct nhlt_fmt *)(epnt->config.caps + + epnt->config.size); + sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps); + if (sp_config) + return sp_config; + } + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return NULL; +} diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h new file mode 100644 index 0000000..b0e2e4d --- /dev/null +++ b/sound/soc/intel/skylake/skl-nhlt.h @@ -0,0 +1,116 @@ +/* + * skl-nhlt.h - Intel HDA Platform NHLT header + * + * Copyright (C) 2015 Intel Corp + * Author: Sanjiv Kumar + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +#ifndef __SKL_NHLT_H__ +#define __SKL_NHLT_H__ + +struct acpi_desc_header { + u32 signature; + u32 length; + u8 revision; + u8 checksum; + u8 oem_id[6]; + u64 oem_table_id; + u32 oem_revision; + u32 creator_id; + u32 creator_revision; +} __packed; + +struct wav_fmt { + u16 fmt_tag; + u16 channels; + u32 samples_per_sec; + u32 avg_bytes_per_sec; + u16 block_align; + u16 bits_per_sample; + u16 cb_size; +} __packed; + +struct wav_fmt_ext { + struct wav_fmt fmt; + union samples { + u16 valid_bits_per_sample; + u16 samples_per_block; + u16 reserved; + } sample; + u32 channel_mask; + u8 sub_fmt[16]; +} __packed; + +enum nhlt_link_type { + NHLT_LINK_HDA = 0, + NHLT_LINK_DSP = 1, + NHLT_LINK_DMIC = 2, + NHLT_LINK_SSP = 3, + NHLT_LINK_INVALID +}; + +enum nhlt_device_type { + NHLT_DEVICE_BT = 0, + NHLT_DEVICE_DMIC = 1, + NHLT_DEVICE_I2S = 4, + NHLT_DEVICE_INVALID +}; + +struct nhlt_specific_cfg { + u32 size; + u8 caps[0]; +} __packed; + +struct nhlt_fmt_cfg { + struct wav_fmt_ext fmt_ext; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_fmt { + u8 fmt_count; + struct nhlt_fmt_cfg fmt_config[0]; +} __packed; + +struct nhlt_endpoint { + u32 length; + u8 linktype; + u8 instance_id; + u16 vendor_id; + u16 device_id; + u16 revision_id; + u32 subsystem_id; + u8 device_type; + u8 direction; + u8 virtual_bus_id; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_acpi_table { + struct acpi_desc_header header; + u8 endpoint_count; + struct nhlt_endpoint desc[0]; +} __packed; + +struct nhlt_resource_desc { + u32 extra; + u16 flags; + u64 addr_spc_gra; + u64 min_addr; + u64 max_addr; + u64 addr_trans_offset; + u64 length; +} __packed; + +#endif diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index cc0f3e2..31dafa8 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include "skl-nhlt.h" #define SKL_SUSPEND_DELAY 2000 @@ -53,6 +54,8 @@ struct skl { unsigned int init_failed:1; /* delayed init failed */ struct platform_device *dmic_dev; + + void __iomem *nhlt; /* nhlt ptr */ }; #define skl_to_ebus(s) (&(s)->ebus) @@ -68,4 +71,8 @@ struct skl_dma_params { int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); +void __iomem *skl_nhlt_init(struct device *dev); +void skl_nhlt_free(void __iomem *addr); +struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, + u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); #endif /* __SOUND_SOC_SKL_H */ -- cgit v0.10.2 From d255b09555e8ea0e517a4d3368ec60097ac9cf96 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 21 Jul 2015 23:53:56 +0530 Subject: ASoC: Intel: Skylake: Add dsp and ipc init helpers This helper function will be used by the Skylake driver for dsp and ipc initialization if processing pipe capability is supported. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index b35faef..27db221 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,4 +1,4 @@ -snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c new file mode 100644 index 0000000..7c07b76 --- /dev/null +++ b/sound/soc/intel/skylake/skl-messages.c @@ -0,0 +1,133 @@ +/* + * skl-message.c - HDA DSP interface for FW registration, Pipe and Module + * configurations + * + * Copyright (C) 2015 Intel Corp + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" +#include "skl.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static int skl_alloc_dma_buf(struct device *dev, + struct snd_dma_buffer *dmab, size_t size) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + if (!bus) + return -ENODEV; + + return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, size, dmab); +} + +static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + if (!bus) + return -ENODEV; + + bus->io_ops->dma_free_pages(bus, dmab); + + return 0; +} + +int skl_init_dsp(struct skl *skl) +{ + void __iomem *mmio_base; + struct hdac_ext_bus *ebus = &skl->ebus; + struct hdac_bus *bus = ebus_to_hbus(ebus); + int irq = bus->irq; + struct skl_dsp_loader_ops loader_ops; + int ret; + + loader_ops.alloc_dma_buf = skl_alloc_dma_buf; + loader_ops.free_dma_buf = skl_free_dma_buf; + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); + + /* read the BAR of the ADSP MMIO */ + mmio_base = pci_ioremap_bar(skl->pci, 4); + if (mmio_base == NULL) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + ret = skl_sst_dsp_init(bus->dev, mmio_base, irq, + loader_ops, &skl->skl_sst); + + dev_dbg(bus->dev, "dsp registration status=%d\n", ret); + + return ret; +} + +void skl_free_dsp(struct skl *skl) +{ + struct hdac_ext_bus *ebus = &skl->ebus; + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl_sst *ctx = skl->skl_sst; + + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); + + skl_sst_dsp_cleanup(bus->dev, ctx); + if (ctx->dsp->addr.lpe) + iounmap(ctx->dsp->addr.lpe); +} + +int skl_suspend_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + int ret; + + /* if ppcap is not supported return 0 */ + if (!skl->ebus.ppcap) + return 0; + + ret = skl_dsp_sleep(ctx->dsp); + if (ret < 0) + return ret; + + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, false); + + return 0; +} + +int skl_resume_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + + /* if ppcap is not supported return 0 */ + if (!skl->ebus.ppcap) + return 0; + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); + + return skl_dsp_wake(ctx->dsp); +} diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 31dafa8..f7fdbb0 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -56,6 +56,7 @@ struct skl { struct platform_device *dmic_dev; void __iomem *nhlt; /* nhlt ptr */ + struct skl_sst *skl_sst; /* sst skl ctx */ }; #define skl_to_ebus(s) (&(s)->ebus) @@ -75,4 +76,9 @@ void __iomem *skl_nhlt_init(struct device *dev); void skl_nhlt_free(void __iomem *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); + +int skl_init_dsp(struct skl *skl); +void skl_free_dsp(struct skl *skl); +int skl_suspend_dsp(struct skl *skl); +int skl_resume_dsp(struct skl *skl); #endif /* __SOUND_SOC_SKL_H */ -- cgit v0.10.2 From 213213d9d68e5fcb81a513a7d07ed6ee01294dea Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 22 Jul 2015 13:09:15 +0800 Subject: ASoC: rl6231: add pll preset table Currently, rl6231_pll_calc provide a working PLL parameters for given freq_in and freq_out. However, in some cases it is not the perfect parameter. For example if freq_in = 19200000 and freq_out = 24576000, the calculated parameter will gengrate 24.5647 MHz which is not exactly the same as what we need. But the PLL can output 24.576 MHz as exactly what we expect if we set the best PLL parameter. To improve it, we put the best match parameters in a preset table. We can search the preset table first, if there is no preset parameter for the given freq_in and freq_out, we can still calculate a working PLL parameter. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 56650d6..96f3e90 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -43,6 +43,19 @@ int rl6231_calc_dmic_clk(int rate) } EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk); +struct pll_calc_map { + unsigned int pll_in; + unsigned int pll_out; + int k; + int n; + int m; + bool m_bp; +}; + +static const struct pll_calc_map pll_preset_table[] = { + {19200000, 24576000, 3, 30, 3, false}, +}; + /** * rl6231_pll_calc - Calcualte PLL M/N/K code. * @freq_in: external clock provided to codec. @@ -57,7 +70,7 @@ int rl6231_pll_calc(const unsigned int freq_in, const unsigned int freq_out, struct rl6231_pll_code *pll_code) { int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX; - int k, red, n_t, pll_out, in_t, out_t; + int i, k, red, n_t, pll_out, in_t, out_t; int n = 0, m = 0, m_t = 0; int red_t = abs(freq_out - freq_in); bool bypass = false; @@ -65,6 +78,18 @@ int rl6231_pll_calc(const unsigned int freq_in, if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in) return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) { + if (freq_in == pll_preset_table[i].pll_in && + freq_out == pll_preset_table[i].pll_out) { + k = pll_preset_table[i].k; + m = pll_preset_table[i].m; + n = pll_preset_table[i].n; + bypass = pll_preset_table[i].m_bp; + pr_debug("Use preset PLL parameter table\n"); + goto code_find; + } + } + k = 100000000 / freq_out - 2; if (k > RL6231_PLL_K_MAX) k = RL6231_PLL_K_MAX; -- cgit v0.10.2 From 36e914cc4bb5d1842e7c8a2e2b9b4f2935771c14 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 23 Jul 2015 22:09:15 +0530 Subject: ASoC: xtensa: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 1cfb19e..039f65e 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -474,11 +474,6 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) card->dev, size, size); } -static void xtfpga_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static const struct snd_pcm_ops xtfpga_pcm_ops = { .open = xtfpga_pcm_open, .close = xtfpga_pcm_close, @@ -490,7 +485,6 @@ static const struct snd_pcm_ops xtfpga_pcm_ops = { static const struct snd_soc_platform_driver xtfpga_soc_platform = { .pcm_new = xtfpga_pcm_new, - .pcm_free = xtfpga_pcm_free, .ops = &xtfpga_pcm_ops, }; -- cgit v0.10.2 From 111509294b9efafe0353423c8180e03db810bdb5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Sun, 14 Jun 2015 15:41:49 +0100 Subject: mfd: arizona: Fix race between runtime suspend and IRQs The function arizona_irq_thread (the threaded handler for the arizona IRQs) calls pm_runtime_get_sync at the start to ensure that the chip is active as we handle the IRQ. If the chip is part way through a runtime suspend when an IRQ arrives the PM core will wait for the suspend to complete, before resuming. However, since commit 4f0216409f7c ("mfd: arizona: Add better support for system suspend") the runtime suspend function may call disable_irq, if the chip is going to fully power off, which will try to wait for any outstanding IRQs to complete. This results in deadlock as the IRQ thread is waiting for the PM operation to complete and the PM thread is waiting for the IRQ to complete. To avoid this situation we use disable_irq_nosync, which allows the suspending thread to finish the suspend without waiting for the IRQ to complete. This is safe because if an IRQ is being processed it can only be blocked at the pm_runtime_get_sync at the start of the handler otherwise it wouldn't be possible to suspend. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bebf58a..e60bcd9 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -651,7 +651,7 @@ static int arizona_runtime_suspend(struct device *dev) arizona->has_fully_powered_off = true; - disable_irq(arizona->irq); + disable_irq_nosync(arizona->irq); arizona_enable_reset(arizona); regulator_bulk_disable(arizona->num_core_supplies, arizona->core_supplies); -- cgit v0.10.2 From 72e43164fd472f6c2659c8313b87da962322dbcf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Sun, 14 Jun 2015 15:41:50 +0100 Subject: mfd: arizona: Fix initialisation of the PM runtime The PM runtime core by default assumes a chip is suspended when runtime PM is enabled. Currently the arizona driver enables runtime PM when the chip is fully active and then disables the DCVDD regulator at the end of arizona_dev_init. This however has several problems, firstly the if we reach the end of arizona_dev_init, we did not properly follow all the proceedures for shutting down the chip, and most notably we never marked the chip as cache only so any writes occurring between then and the next PM runtime resume will be lost. Secondly, if we are already resumed when we reach the end of dev_init, then at best we get unbalanced regulator enable/disables at work we lose DCVDD whilst we need it. Additionally, since the commit 4f0216409f7c ("mfd: arizona: Add better support for system suspend"), the PM runtime operations may disable/enable the IRQ, so the IRQs must now be enabled before we call any PM operations. This patch adds a call to pm_runtime_set_active to inform the PM core that the device is starting up active and moves the PM enabling to around the IRQ initialisation to avoid any PM callbacks happening until the IRQs are initialised. Cc: stable@vger.kernel.org # v3.5+ Signed-off-by: Charles Keepax Signed-off-by: Lee Jones diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index e60bcd9..a72ddb29 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -1141,10 +1141,6 @@ int arizona_dev_init(struct arizona *arizona) arizona->pdata.gpio_defaults[i]); } - pm_runtime_set_autosuspend_delay(arizona->dev, 100); - pm_runtime_use_autosuspend(arizona->dev); - pm_runtime_enable(arizona->dev); - /* Chip default */ if (!arizona->pdata.clk32k_src) arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; @@ -1245,11 +1241,17 @@ int arizona_dev_init(struct arizona *arizona) arizona->pdata.spk_fmt[i]); } + pm_runtime_set_active(arizona->dev); + pm_runtime_enable(arizona->dev); + /* Set up for interrupts */ ret = arizona_irq_init(arizona); if (ret != 0) goto err_reset; + pm_runtime_set_autosuspend_delay(arizona->dev, 100); + pm_runtime_use_autosuspend(arizona->dev); + arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", arizona_clkgen_err, arizona); arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", @@ -1278,10 +1280,6 @@ int arizona_dev_init(struct arizona *arizona) goto err_irq; } -#ifdef CONFIG_PM - regulator_disable(arizona->dcvdd); -#endif - return 0; err_irq: -- cgit v0.10.2 From d12bbcd3ea4402704d13f687601dc5af1361a548 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 25 Jun 2015 02:20:42 +0200 Subject: platform/chrome: Don't make CHROME_PLATFORMS depends on X86 || ARM The Chrome platform support depends on X86 || ARM because there are only Chromebooks using those architectures. But only some drivers depend on a given architecture, and the ones that do already have a dependency on their specific Kconfig symbol entries. An option is to also make CHROME_PLATFORMS depends on || COMPILE_TEST but is more future proof to remove the dependency and let the drivers be built in all architectures if possible to have more build coverage. Acked-by: Olof Johansson Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index cb13299..3271cd1 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -4,7 +4,6 @@ menuconfig CHROME_PLATFORMS bool "Platform support for Chrome hardware" - depends on X86 || ARM ---help--- Say Y here to get to see options for platform support for various Chromebooks and Chromeboxes. This option alone does -- cgit v0.10.2 From fb9caeedafe61599371d057696bff3baef01f455 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 25 Jun 2015 02:20:44 +0200 Subject: mfd: Remove MFD_CROS_EC_SPI depends on OF The ChromeOS EC SPI transport driver has a dependency on OF because it uses some OF helpers from the header. But there isn't a need for an explicit dependency since the header has stub functions if CONFIG_OF is not defined. Also, MFD_CROS_EC_SPI already depends on MFD_CROS_EC which in turn has a dependency on OF so in practice can't be selected without CONFIG_OF. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6538159..3f68dd2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -115,7 +115,7 @@ config MFD_CROS_EC_I2C config MFD_CROS_EC_SPI tristate "ChromeOS Embedded Controller (SPI)" - depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF + depends on MFD_CROS_EC && CROS_EC_PROTO && SPI ---help--- If you say Y here, you get support for talking to the ChromeOS EC -- cgit v0.10.2 From 48f403be3eb9b603cfaf946ca7a0c76272750469 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:23:35 +0800 Subject: ASoC: pcm1681: Improve the logic for de-emphasis sampling rate selection Slightly improve the logic for de-emphasis sampling rate selection by break out the loop if the rate is matched. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index e7ba557..490970e 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -95,17 +95,22 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec) struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); int i = 0, val = -1, enable = 0; - if (priv->deemph) - for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) - if (pcm1681_deemph[i] == priv->rate) + if (priv->deemph) { + for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) { + if (pcm1681_deemph[i] == priv->rate) { val = i; + break; + } + } + } if (val != -1) { regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, PCM1681_DEEMPH_RATE_MASK, val << 3); enable = 1; - } else + } else { enable = 0; + } /* enable/disable deemphasis functionality */ return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, -- cgit v0.10.2 From 97a747117d95b54fe3ce21d43e04499a1671fff6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 24 Jul 2015 11:17:28 +0800 Subject: ASoC: sta529: Remove redundant I2C_FUNC_SMBUS_BYTE_DATA functionality check This checking is done by regmap_get_i2c_bus() which is called in devm_regmap_init_i2c(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 4f70378..2519c7f 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -339,9 +339,6 @@ static int sta529_i2c_probe(struct i2c_client *i2c, struct sta529 *sta529; int ret; - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL); if (!sta529) return -ENOMEM; -- cgit v0.10.2 From eeffd4b442eb2aa25257d8c6631b17cba685ccac Mon Sep 17 00:00:00 2001 From: Harsha Priya Date: Thu, 23 Jul 2015 19:11:54 +0000 Subject: ASoC: ssm4567: Added ACPI entry for SSM4567 codec Added INT343B ACPI ID for the SSM4567 codec Signed-off-by: Harsha Priya Signed-off-by: M Naveen Signed-off-by: M R Sathya Prakash Acked-by: Anatol Pomozov Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 938d2cb..af536ae 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -10,6 +10,7 @@ * Licensed under the GPL-2. */ +#include #include #include #include @@ -450,10 +451,21 @@ static const struct i2c_device_id ssm4567_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); +#ifdef CONFIG_ACPI + +static const struct acpi_device_id ssm4567_acpi_match[] = { + { "INT343B", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match); + +#endif + static struct i2c_driver ssm4567_driver = { .driver = { .name = "ssm4567", .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, .probe = ssm4567_i2c_probe, .remove = ssm4567_i2c_remove, -- cgit v0.10.2 From d50babbe300eedf33ea5b00a12c5df3a05bd96c7 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Wed, 22 Jul 2015 14:40:08 +0800 Subject: xen-blkfront: introduce blkfront_gather_backend_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a bug when migrate from !feature-persistent host to feature-persistent host, because domU still thinks new host/backend doesn't support persistent. Dmesg like: backed has not unmapped grant: 839 backed has not unmapped grant: 773 backed has not unmapped grant: 773 backed has not unmapped grant: 773 backed has not unmapped grant: 839 The fix is to recheck feature-persistent of new backend in blkif_recover(). See: https://lkml.org/lkml/2015/5/25/469 As Roger suggested, we can split the part of blkfront_connect that checks for optional features, like persistent grants, indirect descriptors and flush/barrier features to a separate function and call it from both blkfront_connect and blkif_recover Acked-by: Roger Pau Monné Signed-off-by: Bob Liu Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index fc770b7..f45f4e6 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock); ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) static int blkfront_setup_indirect(struct blkfront_info *info); +static int blkfront_gather_backend_features(struct blkfront_info *info); static int get_id_from_freelist(struct blkfront_info *info) { @@ -1525,7 +1526,7 @@ static int blkif_recover(struct blkfront_info *info) info->shadow_free = info->ring.req_prod_pvt; info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff; - rc = blkfront_setup_indirect(info); + rc = blkfront_gather_backend_features(info); if (rc) { kfree(copy); return rc; @@ -1726,20 +1727,13 @@ static void blkfront_setup_discard(struct blkfront_info *info) static int blkfront_setup_indirect(struct blkfront_info *info) { - unsigned int indirect_segments, segs; + unsigned int segs; int err, i; - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-max-indirect-segments", "%u", &indirect_segments, - NULL); - if (err) { - info->max_indirect_segments = 0; + if (info->max_indirect_segments == 0) segs = BLKIF_MAX_SEGMENTS_PER_REQUEST; - } else { - info->max_indirect_segments = min(indirect_segments, - xen_blkif_max_segments); + else segs = info->max_indirect_segments; - } err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info)); if (err) @@ -1803,6 +1797,68 @@ out_of_memory: } /* + * Gather all backend feature-* + */ +static int blkfront_gather_backend_features(struct blkfront_info *info) +{ + int err; + int barrier, flush, discard, persistent; + unsigned int indirect_segments; + + info->feature_flush = 0; + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-barrier", "%d", &barrier, + NULL); + + /* + * If there's no "feature-barrier" defined, then it means + * we're dealing with a very old backend which writes + * synchronously; nothing to do. + * + * If there are barriers, then we use flush. + */ + if (!err && barrier) + info->feature_flush = REQ_FLUSH | REQ_FUA; + /* + * And if there is "feature-flush-cache" use that above + * barriers. + */ + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-flush-cache", "%d", &flush, + NULL); + + if (!err && flush) + info->feature_flush = REQ_FLUSH; + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-discard", "%d", &discard, + NULL); + + if (!err && discard) + blkfront_setup_discard(info); + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-persistent", "%u", &persistent, + NULL); + if (err) + info->feature_persistent = 0; + else + info->feature_persistent = persistent; + + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "feature-max-indirect-segments", "%u", &indirect_segments, + NULL); + if (err) + info->max_indirect_segments = 0; + else + info->max_indirect_segments = min(indirect_segments, + xen_blkif_max_segments); + + return blkfront_setup_indirect(info); +} + +/* * Invoked when the backend is finally 'ready' (and has told produced * the details about the physical device - #sectors, size, etc). */ @@ -1813,7 +1869,6 @@ static void blkfront_connect(struct blkfront_info *info) unsigned int physical_sector_size; unsigned int binfo; int err; - int barrier, flush, discard, persistent; switch (info->connected) { case BLKIF_STATE_CONNECTED: @@ -1870,48 +1925,7 @@ static void blkfront_connect(struct blkfront_info *info) if (err != 1) physical_sector_size = sector_size; - info->feature_flush = 0; - - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-barrier", "%d", &barrier, - NULL); - - /* - * If there's no "feature-barrier" defined, then it means - * we're dealing with a very old backend which writes - * synchronously; nothing to do. - * - * If there are barriers, then we use flush. - */ - if (!err && barrier) - info->feature_flush = REQ_FLUSH | REQ_FUA; - /* - * And if there is "feature-flush-cache" use that above - * barriers. - */ - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-flush-cache", "%d", &flush, - NULL); - - if (!err && flush) - info->feature_flush = REQ_FLUSH; - - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-discard", "%d", &discard, - NULL); - - if (!err && discard) - blkfront_setup_discard(info); - - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-persistent", "%u", &persistent, - NULL); - if (err) - info->feature_persistent = 0; - else - info->feature_persistent = persistent; - - err = blkfront_setup_indirect(info); + err = blkfront_gather_backend_features(info); if (err) { xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s", info->xbdev->otherend); -- cgit v0.10.2 From 7b0767502b5db11cb1f0daef2d01f6d71b1192dc Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Wed, 22 Jul 2015 14:40:09 +0800 Subject: xen-blkfront: don't add indirect pages to list when !feature_persistent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should consider info->feature_persistent when adding indirect page to list info->indirect_pages, else the BUG_ON() in blkif_free() would be triggered. When we are using persistent grants the indirect_pages list should always be empty because blkfront has pre-allocated enough persistent pages to fill all requests on the ring. CC: stable@vger.kernel.org Acked-by: Roger Pau Monné Signed-off-by: Bob Liu Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index f45f4e6..44b33d3 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1135,8 +1135,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, * Add the used indirect page back to the list of * available pages for indirect grefs. */ - indirect_page = pfn_to_page(s->indirect_grants[i]->pfn); - list_add(&indirect_page->lru, &info->indirect_pages); + if (!info->feature_persistent) { + indirect_page = pfn_to_page(s->indirect_grants[i]->pfn); + list_add(&indirect_page->lru, &info->indirect_pages); + } s->indirect_grants[i]->gref = GRANT_INVALID_REF; list_add_tail(&s->indirect_grants[i]->node, &info->grants); } -- cgit v0.10.2 From 53bc7dc004fecf39e0ba70f2f8d120a1444315d3 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Wed, 22 Jul 2015 14:40:10 +0800 Subject: xen-blkback: replace work_pending with work_busy in purge_persistent_gnt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BUG_ON() in purge_persistent_gnt() will be triggered when previous purge work haven't finished. There is a work_pending() before this BUG_ON, but it doesn't account if the work is still currently running. CC: stable@vger.kernel.org Acked-by: Roger Pau Monné Signed-off-by: Bob Liu Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 9121a2c..73c0404 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -382,8 +382,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif) return; } - if (work_pending(&blkif->persistent_purge_work)) { - pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n"); + if (work_busy(&blkif->persistent_purge_work)) { + pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n"); return; } -- cgit v0.10.2 From 80deaf09cb3fb3939c1d2b84610ae411cd7c6001 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 12:32:52 +0800 Subject: ASoC: cs4265: CS4265_INT_STATUS is readable register CS4265_INT_STATUS was missed in cs4265_readable_register, fix it. The register 0x01 ~ 0x12 are readable, use CS4265_CHIP_ID ... CS4265_SPDIF_CTL2 syntax for better readability. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d7ec4756..688c500 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -60,23 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = { static bool cs4265_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS4265_PWRCTL: - case CS4265_DAC_CTL: - case CS4265_ADC_CTL: - case CS4265_MCLK_FREQ: - case CS4265_SIG_SEL: - case CS4265_CHB_PGA_CTL: - case CS4265_CHA_PGA_CTL: - case CS4265_ADC_CTL2: - case CS4265_DAC_CHA_VOL: - case CS4265_DAC_CHB_VOL: - case CS4265_DAC_CTL2: - case CS4265_SPDIF_CTL1: - case CS4265_SPDIF_CTL2: - case CS4265_INT_MASK: - case CS4265_STATUS_MODE_MSB: - case CS4265_STATUS_MODE_LSB: - case CS4265_CHIP_ID: + case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2: return true; default: return false; -- cgit v0.10.2 From 0a3dcb509ae7701ba3eaf470cad91827821daf41 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 24 Jul 2015 16:11:25 +0800 Subject: ASoC: Use params_width() at appropriate places Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad6642..a29e499 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -432,7 +432,7 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream, 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))) { + switch (params_width(params)) { case 16: regmap_update_bits(max98925->regmap, MAX98925_FORMAT, diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index de16429..047c489 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1117,7 +1117,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, params_rate(params), params_channels(params)); - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 16: alen = PCM512x_ALEN_16; break; @@ -1132,7 +1132,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(codec->dev, "Bad frame size: %d\n", - snd_pcm_format_width(params_format(params))); + params_width(params)); return -EINVAL; } diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c830832..c51bc18 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1702,7 +1702,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, int *bclk_rates; /* Data sizes if not using TDM */ - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (wl < 0) return wl; fl = snd_soc_params_to_frame_size(params); diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd8..05d25a6 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1408,7 +1408,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream, base = dai->driver->base; /* Data sizes if not using TDM */ - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (wl < 0) return wl; fl = snd_soc_params_to_frame_size(params); diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ece9b44..501c334 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -265,7 +265,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream, } /* Set word length */ - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 16: iface = 0; break; @@ -280,7 +280,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(codec->dev, "Unsupported sample size: %i\n", - snd_pcm_format_width(params_format(params))); + params_width(params)); return -EINVAL; } diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f..04b25cb 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -1780,7 +1780,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream, wm8996->rx_rate[dai->id] = params_rate(params); /* Needs looking at for TDM */ - bits = snd_pcm_format_width(params_format(params)); + bits = params_width(params); if (bits < 0) return bits; aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits; -- cgit v0.10.2 From 00a2916f7f82c348a2a94dbb572874173bc308a3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 27 Jul 2015 10:35:07 +0200 Subject: perf: Fix running time accounting A recent fix to the shadow timestamp inadvertly broke the running time accounting. We must not update the running timestamp if we fail to schedule the event, the event will not have ran. This can (and did) result in negative total runtime because the stopped timestamp was before the running timestamp (we 'started' but never stopped the event -- because it never really started we didn't have to stop it either). Reported-and-Tested-by: Vince Weaver Fixes: 72f669c0086f ("perf: Update shadow timestamp before add event") Signed-off-by: Peter Zijlstra (Intel) Cc: stable@vger.kernel.org # 4.1 Cc: Shaohua Li Signed-off-by: Thomas Gleixner diff --git a/kernel/events/core.c b/kernel/events/core.c index d3dae34..10d076b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1868,8 +1868,6 @@ event_sched_in(struct perf_event *event, perf_pmu_disable(event->pmu); - event->tstamp_running += tstamp - event->tstamp_stopped; - perf_set_shadow_time(event, ctx, tstamp); perf_log_itrace_start(event); @@ -1881,6 +1879,8 @@ event_sched_in(struct perf_event *event, goto out; } + event->tstamp_running += tstamp - event->tstamp_stopped; + if (!is_software_event(event)) cpuctx->active_oncpu++; if (!ctx->nr_active++) -- cgit v0.10.2 From 02c3b4c75994888e58a6e6e8176640cde9822597 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Fri, 24 Jul 2015 16:09:36 -0400 Subject: usb: gadget: bdc: fix a driver crash on disconnect ep_dequeue() in bdc_ep.c was capturing the hw dequeue pointer incorrectly by reading the wrong register for the upper 32 bits. Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index b04980c..1efa612 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -779,7 +779,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) /* The current hw dequeue pointer */ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0)); deq_ptr_64 = tmp_32; - tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1)); + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0)); deq_ptr_64 |= ((u64)tmp_32 << 32); /* we have the dma addr of next bd that will be fetched by hardware */ -- cgit v0.10.2 From c41b7767673cb76adeb2b5fde220209f717ea13c Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 27 Jul 2015 14:51:47 +0800 Subject: usb: gadget: f_uac2: fix calculation of uac2->p_interval The p_interval should be less if the 'bInterval' at the descriptor is larger, eg, if 'bInterval' is 5 for HS, the p_interval should be 8000 / 16 = 500. It fixes the patch 9bb87f168931 ("usb: gadget: f_uac2: send reasonably sized packets") Cc: # v3.18+ Fixes: 9bb87f168931 ("usb: gadget: f_uac2: send reasonably sized packets") Acked-by: Daniel Mack Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6d3eb8b..5318615 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -1162,14 +1162,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) factor = 1000; } else { ep_desc = &hs_epin_desc; - factor = 125; + factor = 8000; } /* pre-compute some values for iso_complete() */ uac2->p_framesize = opts->p_ssize * num_channels(opts->p_chmask); rate = opts->p_srate * uac2->p_framesize; - uac2->p_interval = (1 << (ep_desc->bInterval - 1)) * factor; + uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1)); uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval, prm->max_psize); -- cgit v0.10.2 From 774cf72f8ad971031428f8057d2947c8780a7b8c Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 24 Jul 2015 09:48:40 +0200 Subject: usb: gadget: f_hid: actually limit the number of instances There is a predefined maximum number of hid instances, currently 4. A chrdev region is allocated accordingly, but with configfs the user can create as many hid function directories as they like. To make the number of hid instances consistent with the number of allocated minors, the limit is enforced at directory creation time. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index f7f35a3..6df9715 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -699,6 +699,10 @@ static inline int hidg_get_minor(void) int ret; ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL); + if (ret >= HIDG_MINORS) { + ida_simple_remove(&hidg_ida, ret); + ret = -ENODEV; + } return ret; } -- cgit v0.10.2 From 4248bd7d3e2c7c87ff695d812018b8c22b5a5ab1 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 24 Jul 2015 09:48:41 +0200 Subject: usb: gadget: f_printer: actually limit the number of instances There is a predefined maximum number of printer instances, currently 4. A chrdev region is allocated accordingly, but with configfs the user can create as many printer function directories as they like. To make the number of printer instances consistent with the number of allocated minors, the limit is enforced at directory creation time. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 44173df..357f63f 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1248,7 +1248,15 @@ static struct config_item_type printer_func_type = { static inline int gprinter_get_minor(void) { - return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); + int ret; + + ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL); + if (ret >= PRINTER_MINORS) { + ida_simple_remove(&printer_ida, ret); + ret = -ENODEV; + } + + return ret; } static inline void gprinter_put_minor(int minor) -- cgit v0.10.2 From 17fb874dee093139923af8ed36061faa92cc8e79 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 24 Jul 2015 13:13:30 +0200 Subject: hwrng: core - correct error check of kthread_run call The kthread_run() function can return two different error values but the hwrng core only checks for -ENOMEM. If the other error value -EINTR is returned it is assigned to hwrng_fill and later used on a kthread_stop() call which naturally crashes. Cc: stable@vger.kernel.org Signed-off-by: Martin Schwidefsky Signed-off-by: Herbert Xu diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index da8faf7..5643b65 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -429,7 +429,7 @@ static int hwrng_fillfn(void *unused) static void start_khwrngd(void) { hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); - if (hwrng_fill == ERR_PTR(-ENOMEM)) { + if (IS_ERR(hwrng_fill)) { pr_err("hwrng_fill thread creation failed"); hwrng_fill = NULL; } -- cgit v0.10.2 From 74472233233f577eaa0ca6d6e17d9017b6e53150 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 27 Jul 2015 08:56:05 +0200 Subject: USB: sierra: add 1199:68AB device ID Add support for the Sierra Wireless AR8550 device with USB descriptor 0x1199, 0x68AB. It is common with MC879x modules 1199:683c/683d which also are composite devices with 7 interfaces (0..6) and also MDM62xx based as the AR8550. The major difference are only the interface attributes 02/02/01 on interfaces 3 and 4 on the AR8550. They are vendor specific ff/ff/ff on MC879x modules. lsusb reports: Bus 001 Device 004: ID 1199:68ab Sierra Wireless, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1199 Sierra Wireless, Inc. idProduct 0x68ab bcdDevice 0.06 iManufacturer 3 Sierra Wireless, Incorporated iProduct 2 AR8550 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 198 bNumInterfaces 7 bConfigurationValue 1 iConfiguration 1 Sierra Configuration bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 1 AT-commands (v.25ter) iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x89 EP 9 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 6 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8a EP 10 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8b EP 11 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0001 Self Powered Signed-off-by: Dirk Behme Cc: Lars Melin Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 46179a0..07d1ecd 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF), .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, + { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */ /* AT&T Direct IP LTE modems */ { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist -- cgit v0.10.2 From c9fdec9f3970eeaa1b176422f46167f5f5158804 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 20 Jul 2015 12:14:39 +0300 Subject: iwlwifi: pcie: fix prepare card flow When the card is not owned by the PCIe bus, we need to acquire ownership first. This flow is implemented in iwl_pcie_prepare_card_hw. Because of a hardware bug, we need to disable link power management before we can request ownership otherwise the other user of the device won't get notified that we are requesting the device which will prevent us from acquire ownership. Same holds for the down flow where we need to make sure that any other potential user is notified that the driver is going down. CC: [4.1] Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 6203c4a..9e144e7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_WAKE_ME); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE | CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(1); + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + } mdelay(5); } @@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) if (ret >= 0) return 0; + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + msleep(1); + for (iter = 0; iter < 10; iter++) { /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) do { ret = iwl_pcie_set_hw_ready(trans); - if (ret >= 0) - return 0; + if (ret >= 0) { + ret = 0; + goto out; + } usleep_range(200, 1000); t += 200; @@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) IWL_ERR(trans, "Couldn't prepare the card\n"); +out: + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + return ret; } -- cgit v0.10.2 From dc9f69b907f3853952d3ffb7918d05a662146712 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 7 Jul 2015 16:53:42 +0300 Subject: iwlwifi: mvm: Fix regular scan priority The code checks the total number of iterations to differentiate between regular scan and scheduled scan. However, regular scan has a total of one iteration, not zero. As a result, regular scan will have lower priority than it should have, and in case scheduled scan is already running when regular scan is requested, regular scan will be delayed until scheduled scan is aborted. Fix that by checking for total iterations number of one as an identifier for regular scan. Fixes: 133c8259f885 ("iwlwifi: mvm: rename generic_scan_cmd functions to dwell") Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5000bfcd..5514ad6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1023,7 +1023,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->scan_priority = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); - if (iwl_mvm_scan_total_iterations(params) == 0) + if (iwl_mvm_scan_total_iterations(params) == 1) cmd->ooc_priority = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); else -- cgit v0.10.2 From 5497628576a3c5f3dbab224fa5a5d027f43d8b50 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 27 Jul 2015 16:24:51 -0700 Subject: perf stat: Fix transaction lenght metrics The transaction length metrics in perf stat -T broke recently. It would not match the metric correctly and always print K/sec. This was caused by a incorrect update of the cycles_in_tx statistics. Update the correct variable. Also the check for zero division was reversed, which resulted in K/sec being printed for no transactions. Fix this also up. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1438039491-22091-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 53e8bb7..2a5d8d7 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -85,7 +85,7 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[ctx][cpu], count[0]); else if (perf_stat_evsel__is(counter, CYCLES_IN_TX)) - update_stats(&runtime_transaction_stats[ctx][cpu], count[0]); + update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]); else if (perf_stat_evsel__is(counter, TRANSACTION_START)) update_stats(&runtime_transaction_stats[ctx][cpu], count[0]); else if (perf_stat_evsel__is(counter, ELISION_START)) @@ -398,20 +398,18 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, " # %5.2f%% aborted cycles ", 100.0 * ((total2-avg) / total)); } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) && - avg > 0 && runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); - if (total) + if (avg) ratio = total / avg; fprintf(out, " # %8.0f cycles / transaction ", ratio); } else if (perf_stat_evsel__is(evsel, ELISION_START) && - avg > 0 && runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); - if (total) + if (avg) ratio = total / avg; fprintf(out, " # %8.0f cycles / elision ", ratio); -- cgit v0.10.2 From 3661df179bfbd1bb21cf2c782d3c5c084ebe3cf4 Mon Sep 17 00:00:00 2001 From: Hariprasad S Date: Mon, 27 Jul 2015 14:08:14 +0530 Subject: iw_cxgb4: gracefully handle unknown CQE status errors c4iw_poll_cq_on() shouldn't fail the poll operation just because the CQE status is unknown. Rather, it should map this to the "fatal error" status and log the anomaly. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index c7aab48..92d5183 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -814,7 +814,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) printk(KERN_ERR MOD "Unexpected cqe_status 0x%x for QPID=0x%0x\n", CQE_STATUS(&cqe), CQE_QPID(&cqe)); - ret = -EINVAL; + wc->status = IB_WC_FATAL_ERR; } } out: -- cgit v0.10.2 From 0927beeca5f9d1a7978f8da9c9d28647859816d3 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Tue, 28 Jul 2015 15:10:13 +0100 Subject: perf tools: Fix test build error when bindir contains double slash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building with a prefix ending with a slash, for example: $ make prefix=/usr/local/ one of the perf tests fail to compile due to BUILD_STR macro mishandling bindir_SQ string containing with two slashes: -DBINDIR="BUILD_STR(/usr/local//bin)" with the following error: CC tests/attr.o tests/attr.c: In function ‘test__attr’: tests/attr.c:168:50: error: expected ‘)’ before ‘;’ token snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR); ^ tests/attr.c:176:1: error: expected ‘;’ before ‘}’ token } ^ tests/attr.c:176:1: error: control reaches end of non-void function [-Werror=return-type] } ^ cc1: all warnings being treated as errors This patch works around the problem by "cleaning" the bindir string using make's abspath function. Signed-off-by: Pawel Moll Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1438092613-21014-1-git-send-email-pawel.moll@arm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 094ddae..d31fac1 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -638,7 +638,7 @@ ifndef DESTDIR prefix ?= $(HOME) endif bindir_relative = bin -bindir = $(prefix)/$(bindir_relative) +bindir = $(abspath $(prefix)/$(bindir_relative)) mandir = share/man infodir = share/info perfexecdir = libexec/perf-core -- cgit v0.10.2 From 8b34fe593ec6392aaef74c244fe2c091f424dee8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 14 Jul 2015 13:03:33 -0700 Subject: ata: ahci_brcmstb: Fix warnings with CONFIG_PM_SLEEP=n When CONFIG_PM_SLEEP is disabled, brcm_ahci_{suspend,resume} are not used, which causes such a build warning to occur: CC drivers/ata/ahci_brcmstb.o drivers/ata/ahci_brcmstb.c:212:12: warning: 'brcm_ahci_suspend' defined but not used [-Wunused-function] static int brcm_ahci_suspend(struct device *dev) ^ drivers/ata/ahci_brcmstb.c:224:12: warning: 'brcm_ahci_resume' defined but not used [-Wunused-function] static int brcm_ahci_resume(struct device *dev) ^ LD drivers/ata/built-in.o Fixes: 766a2d979632 ("ata: add Broadcom AHCI SATA3 driver for STB chips") Signed-off-by: Florian Fainelli Acked-by: Brian Norris Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index ce1e3a8..42b6cf4 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -209,6 +209,7 @@ static void brcm_sata_init(struct brcm_ahci_priv *priv) priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL); } +#ifdef CONFIG_PM_SLEEP static int brcm_ahci_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); @@ -231,6 +232,7 @@ static int brcm_ahci_resume(struct device *dev) brcm_sata_phys_enable(priv); return ahci_platform_resume(dev); } +#endif static struct scsi_host_template ahci_platform_sht = { AHCI_SHT(DRV_NAME), -- cgit v0.10.2 From fe0d34d242fa1e0dec059e774d146a705420bc9a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 29 Jul 2015 05:52:14 +0930 Subject: module: weaken locking assertion for oops path. We don't actually hold the module_mutex when calling find_module_all from module_kallsyms_lookup_name: that's because it's used by the oops code and we don't want to deadlock. However, access to the list read-only is safe if preempt is disabled, so we can weaken the assertion. Keep a strong version for external callers though. Fixes: 0be964be0d45 ("module: Sanitize RCU usage and locking") Reported-by: He Kuang Cc: stable@kernel.org Acked-by: Peter Zijlstra (Intel) Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index 4d2b82e..b86b7bf 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -602,13 +602,16 @@ const struct kernel_symbol *find_symbol(const char *name, } EXPORT_SYMBOL_GPL(find_symbol); -/* Search for module by name: must hold module_mutex. */ +/* + * Search for module by name: must hold module_mutex (or preempt disabled + * for read-only access). + */ static struct module *find_module_all(const char *name, size_t len, bool even_unformed) { struct module *mod; - module_assert_mutex(); + module_assert_mutex_or_preempt(); list_for_each_entry(mod, &modules, list) { if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) @@ -621,6 +624,7 @@ static struct module *find_module_all(const char *name, size_t len, struct module *find_module(const char *name) { + module_assert_mutex(); return find_module_all(name, strlen(name), false); } EXPORT_SYMBOL_GPL(find_module); -- cgit v0.10.2 From e350f8045f642dfc4c28a81c57d2103e1f7ceead Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 11 Jun 2015 20:19:25 +0900 Subject: extcon: palmas: Fix NULL pointer error This patch fixes NULL pointer error by removing the unneeded kfree() call of edev->name because extcon-palmas no longer allocate the memory for edev->name. Fixes: d71aadda19f8 ("extcon: Remove the optional name of extcon device") Signed-off-by: Chanwoo Choi Reviewed-by: Krzysztof Kozlowski diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 080d5cc..eebdf2a 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -200,7 +200,6 @@ static int palmas_usb_probe(struct platform_device *pdev) status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { dev_err(&pdev->dev, "failed to register extcon device\n"); - kfree(palmas_usb->edev->name); return status; } @@ -214,7 +213,6 @@ static int palmas_usb_probe(struct platform_device *pdev) if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->id_irq, status); - kfree(palmas_usb->edev->name); return status; } } @@ -229,7 +227,6 @@ static int palmas_usb_probe(struct platform_device *pdev) if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", palmas_usb->vbus_irq, status); - kfree(palmas_usb->edev->name); return status; } } @@ -239,15 +236,6 @@ static int palmas_usb_probe(struct platform_device *pdev) return 0; } -static int palmas_usb_remove(struct platform_device *pdev) -{ - struct palmas_usb *palmas_usb = platform_get_drvdata(pdev); - - kfree(palmas_usb->edev->name); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int palmas_usb_suspend(struct device *dev) { @@ -288,7 +276,6 @@ static const struct of_device_id of_palmas_match_tbl[] = { static struct platform_driver palmas_usb_driver = { .probe = palmas_usb_probe, - .remove = palmas_usb_remove, .driver = { .name = "palmas-usb", .of_match_table = of_palmas_match_tbl, -- cgit v0.10.2 From 4a8e70f5d0d80675fc17b9ba1e62db8ca6b91775 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 29 Jul 2015 13:16:06 +0300 Subject: HID: uclogic: fix limit in uclogic_tablet_enable() The limit should be ARRAY_SIZE(params) (5 elements) here instead of sizeof(params) (20 bytes). Fixes: 08177f40bd00 ('HID: uclogic: merge hid-huion driver in hid-uclogic') Signed-off-by: Dan Carpenter Reviewed-by: Nikolai Kondrashov Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index 9416731..b905d50 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -858,7 +858,7 @@ static int uclogic_tablet_enable(struct hid_device *hdev) for (p = drvdata->rdesc; p <= drvdata->rdesc + drvdata->rsize - 4;) { if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && - p[3] < sizeof(params)) { + p[3] < ARRAY_SIZE(params)) { v = params[p[3]]; put_unaligned(cpu_to_le32(v), (s32 *)p); p += 4; -- cgit v0.10.2 From f8163c8673efaabb361281a2759b3167d181ecf6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 25 Jul 2015 10:23:40 +0800 Subject: ASoC: rt5677: Return error if devm_gpiod_get_optional return ERR_PTR If devm_gpiod_get_optional() return ERR_PTR, it means something wrong so request gpio fails. We had better return error in such case. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 62230e0..3f890a6 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5133,14 +5133,14 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (IS_ERR(rt5677->pow_ldo2)) { ret = PTR_ERR(rt5677->pow_ldo2); dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); - rt5677->pow_ldo2 = 0; + return ret; } rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, "realtek,reset", GPIOD_OUT_HIGH); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); - rt5677->reset_pin = 0; + return ret; } if (rt5677->pow_ldo2 || rt5677->reset_pin) { -- cgit v0.10.2 From 82cf77a1bd61d981184a355742a9b5c78f286f97 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 25 Jul 2015 15:32:16 +0800 Subject: ASoC: tas2552: Remove unneeded NULL test for tas2552->enable_gpio It's safe to call gpiod_set_value() with NULL desc. Signed-off-by: Axel Lin Acked-by: Dan Murphy Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d..d6ec004 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -493,8 +493,7 @@ static int tas2552_runtime_suspend(struct device *dev) regcache_cache_only(tas2552->regmap, true); regcache_mark_dirty(tas2552->regmap); - if (tas2552->enable_gpio) - gpiod_set_value(tas2552->enable_gpio, 0); + gpiod_set_value(tas2552->enable_gpio, 0); return 0; } @@ -503,8 +502,7 @@ static int tas2552_runtime_resume(struct device *dev) { struct tas2552_data *tas2552 = dev_get_drvdata(dev); - if (tas2552->enable_gpio) - gpiod_set_value(tas2552->enable_gpio, 1); + gpiod_set_value(tas2552->enable_gpio, 1); tas2552_sw_shutdown(tas2552, 0); @@ -585,8 +583,7 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) return ret; } - if (tas2552->enable_gpio) - gpiod_set_value(tas2552->enable_gpio, 1); + gpiod_set_value(tas2552->enable_gpio, 1); ret = pm_runtime_get_sync(codec->dev); if (ret < 0) { @@ -610,8 +607,7 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) return 0; probe_fail: - if (tas2552->enable_gpio) - gpiod_set_value(tas2552->enable_gpio, 0); + gpiod_set_value(tas2552->enable_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), tas2552->supplies); @@ -624,8 +620,7 @@ static int tas2552_codec_remove(struct snd_soc_codec *codec) pm_runtime_put(codec->dev); - if (tas2552->enable_gpio) - gpiod_set_value(tas2552->enable_gpio, 0); + gpiod_set_value(tas2552->enable_gpio, 0); return 0; }; -- cgit v0.10.2 From 787126ebdb9821f1a19b1dfd1ab1bbb74b8c80b8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 26 Jul 2015 19:04:58 +0200 Subject: ASoC: dapm: Drop always true checks list_first_entry() always returns non NULL and since the code previously checked that list is not empty it will also be a valid pointer. Furthermore a path has always a sink or a source widget. So both checks are redundant and can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index cb4bc1c..f80b7de 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3482,11 +3482,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, list_source); - if (WARN_ON(!source_p || !sink_p) || - WARN_ON(!sink_p->source || !source_p->sink) || - WARN_ON(!source_p->source || !sink_p->sink)) - return -EINVAL; - source = source_p->source->priv; sink = sink_p->sink->priv; -- cgit v0.10.2 From 1ce43acff0c078fd560ee0f2a4ae10b8da28e388 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 26 Jul 2015 19:04:59 +0200 Subject: ASoC: dapm: Simplify list creation in dapm_dai_get_connected_widgets() When running dapm_dai_get_connected_widgets() currently in is_connected_{input,output}_ep() for each widget that gets added the array is resized and the code also loops over all existing entries to avoid adding a widget multiple times. The former can be avoided by collecting the widgets in a linked list and only once we have all widgets allocate the array. The later can be avoided by changing when the widget is added. Currently it is added when walking the neighbor lists of a widget. Since a widget can be neighbors with multiple other widgets it could get added twice and hence the check is necessary. But the main body of is_connected_{input,output}_ep is guaranteed to be only executed at most once per widget. So adding the widget to the list at the beginning of the function automatically makes sure that each widget gets only added once. The only difference is that using this method the starting point itself will also end up on the list, but it can easily be skipped when creating the array. Overall this reduces the code size and speeds things slightly up. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f80b7de..4586f95c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1032,43 +1032,27 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) } } -/* add widget to list if it's not already in the list */ -static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, - struct snd_soc_dapm_widget *w) +static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, + struct list_head *widgets) { - struct snd_soc_dapm_widget_list *wlist; - int wlistsize, wlistentries, i; - - if (*list == NULL) - return -EINVAL; - - wlist = *list; + struct snd_soc_dapm_widget *w; + struct list_head *it; + unsigned int size = 0; + unsigned int i = 0; - /* is this widget already in the list */ - for (i = 0; i < wlist->num_widgets; i++) { - if (wlist->widgets[i] == w) - return 0; - } + list_for_each(it, widgets) + size++; - /* allocate some new space */ - wlistentries = wlist->num_widgets + 1; - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - wlistentries * sizeof(struct snd_soc_dapm_widget *); - *list = krealloc(wlist, wlistsize, GFP_KERNEL); - if (*list == NULL) { - dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n", - w->name); + *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL); + if (*list == NULL) return -ENOMEM; - } - wlist = *list; - /* insert the widget */ - dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n", - w->name, wlist->num_widgets); + list_for_each_entry(w, widgets, work_list) + (*list)->widgets[i++] = w; - wlist->widgets[wlist->num_widgets] = w; - wlist->num_widgets++; - return 1; + (*list)->num_widgets = i; + + return 0; } /* @@ -1076,7 +1060,7 @@ static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, * output widget. Returns number of complete paths. */ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1086,6 +1070,10 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, DAPM_UPDATE_STAT(widget, path_checks); + /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_sink && widget->connected) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -1104,22 +1092,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->sink); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_output_ep(path->sink, list); - path->walking = 0; } } @@ -1134,7 +1107,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, * input widget. Returns number of complete paths. */ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1144,6 +1117,10 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, DAPM_UPDATE_STAT(widget, path_checks); + /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_source && widget->connected) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -1162,22 +1139,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->source); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_input_ep(path->source, list); - path->walking = 0; } } @@ -1204,7 +1166,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, { struct snd_soc_card *card = dai->component->card; struct snd_soc_dapm_widget *w; + LIST_HEAD(widgets); int paths; + int ret; mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); @@ -1218,9 +1182,16 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, } if (stream == SNDRV_PCM_STREAM_PLAYBACK) - paths = is_connected_output_ep(dai->playback_widget, list); + paths = is_connected_output_ep(dai->playback_widget, &widgets); else - paths = is_connected_input_ep(dai->capture_widget, list); + paths = is_connected_input_ep(dai->capture_widget, &widgets); + + /* Drop starting point */ + list_del(widgets.next); + + ret = dapm_widget_list_create(list, &widgets); + if (ret) + return ret; trace_snd_soc_dapm_connected(paths, stream); mutex_unlock(&card->dapm_mutex); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 256b9c9..7aed170 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1231,24 +1231,17 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list, } int dpcm_path_get(struct snd_soc_pcm_runtime *fe, - int stream, struct snd_soc_dapm_widget_list **list_) + int stream, struct snd_soc_dapm_widget_list **list) { struct snd_soc_dai *cpu_dai = fe->cpu_dai; - struct snd_soc_dapm_widget_list *list; int paths; - list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + - sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); - if (list == NULL) - return -ENOMEM; - /* get number of valid DAI paths and their widgets */ - paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); + paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list); dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback"); - *list_ = list; return paths; } -- cgit v0.10.2 From e63bfd45aba4269811662de0954785622a2ac928 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 26 Jul 2015 19:05:00 +0200 Subject: ASoC: dapm: Add widget path iterators Add helper iterator macros for iterating over the source and sink paths of widget. This will make it easier to change the implementation later on. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cadc7fc..4973083 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -673,4 +673,22 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; } +/** + * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a + * widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_sink_path(w, p) \ + list_for_each_entry(p, &w->sinks, list_source) + +/** + * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to + * a widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_source_path(w, p) \ + list_for_each_entry(p, &w->sources, list_sink) + #endif diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 31e9b9e..1399e34 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1298,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->playback_widget->name); w = dai->playback_widget; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue; @@ -1317,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->capture_widget->name); w = dai->capture_widget; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4586f95c..ac506cf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -193,7 +193,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list); list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; sink = p->sink; @@ -232,7 +232,7 @@ static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list); list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; source = p->source; @@ -894,7 +894,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) /* add kcontrol */ for (i = 0; i < w->num_kcontrols; i++) { /* match name */ - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { /* mixer/mux paths name must match control name */ if (path->name != (char *)w->kcontrol_news[i].name) continue; @@ -958,12 +958,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return ret; if (w->id == snd_soc_dapm_mux) { - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } } else { - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } @@ -1079,7 +1079,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, return widget->outputs; } - list_for_each_entry(path, &widget->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks); if (path->weak || path->is_supply) @@ -1126,7 +1126,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, return widget->inputs; } - list_for_each_entry(path, &widget->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks); if (path->weak || path->is_supply) @@ -1292,7 +1292,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) DAPM_UPDATE_STAT(w, power_checks); /* Check if one of our outputs is connected */ - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { DAPM_UPDATE_STAT(w, neighbour_checks); if (path->weak) @@ -1716,12 +1716,12 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, /* If we changed our power state perhaps our neigbours changed * also. */ - list_for_each_entry(path, &w->sources, list_sink) + snd_soc_dapm_widget_for_each_source_path(w, path) dapm_widget_set_peer_power(path->source, power, path->connect); /* Supplies can't affect their outputs, only their inputs */ if (!w->is_supply) { - list_for_each_entry(path, &w->sinks, list_source) + snd_soc_dapm_widget_for_each_sink_path(w, path) dapm_widget_set_peer_power(path->sink, power, path->connect); } @@ -1958,7 +1958,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname, w->active ? "active" : "inactive"); - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->source)) continue; @@ -1968,7 +1968,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, p->name ? p->name : "static", p->source->name); } - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue; @@ -2426,7 +2426,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_source = 1; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->source->id == snd_soc_dapm_micbias || p->source->id == snd_soc_dapm_mic || p->source->id == snd_soc_dapm_line || @@ -2441,7 +2441,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_sink = 1; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->sink->id == snd_soc_dapm_spk || p->sink->id == snd_soc_dapm_hp || p->sink->id == snd_soc_dapm_line || @@ -2841,7 +2841,7 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", route->source, route->sink); - list_for_each_entry(path, &source->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(source, path) { if (path->sink == sink) { path->weak = 1; count++; -- cgit v0.10.2 From f102aa1414d9aa28491414cf4103bad1ddb3ea1f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 28 Jul 2015 13:29:00 +0800 Subject: ASoC: max98088: Get rid of max98088_access table The max98088_access table is used for look up readable/writable/volatile attributes of registers. The readable/writable/volatile registers are mostly in continuous ranges, so we can replace the max98088_access table entirely by using case range. Below is a summary of the readable/writeable/volatile registers: readable registers: 0x00 ~ 0xC9, 0xFF writeable registers: 0x03 ~ 0xC9 volatile registers: 0x00 ~ 0x03, 0xFF Note, 0x00 should be read-only according to the datasheet. This patch reworks the implement for .readable and .volatile and also add implementation for .writable callback. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index d0f4534..419c65f 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -258,292 +258,36 @@ static const struct reg_default max98088_reg[] = { { 0xc9, 0x00 }, /* C9 DAI2 biquad */ }; -static struct { - int readable; - int writable; - int vol; -} max98088_access[M98088_REG_CNT] = { - { 0xFF, 0xFF, 1 }, /* 00 IRQ status */ - { 0xFF, 0x00, 1 }, /* 01 MIC status */ - { 0xFF, 0x00, 1 }, /* 02 jack status */ - { 0x1F, 0x1F, 1 }, /* 03 battery voltage */ - { 0xFF, 0xFF, 0 }, /* 04 */ - { 0xFF, 0xFF, 0 }, /* 05 */ - { 0xFF, 0xFF, 0 }, /* 06 */ - { 0xFF, 0xFF, 0 }, /* 07 */ - { 0xFF, 0xFF, 0 }, /* 08 */ - { 0xFF, 0xFF, 0 }, /* 09 */ - { 0xFF, 0xFF, 0 }, /* 0A */ - { 0xFF, 0xFF, 0 }, /* 0B */ - { 0xFF, 0xFF, 0 }, /* 0C */ - { 0xFF, 0xFF, 0 }, /* 0D */ - { 0xFF, 0xFF, 0 }, /* 0E */ - { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */ - - { 0xFF, 0xFF, 0 }, /* 10 master clock */ - { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */ - { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */ - { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */ - { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */ - { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */ - { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */ - { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */ - { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */ - { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */ - { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */ - { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */ - { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */ - { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */ - { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */ - { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */ - - { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */ - { 0xFF, 0xFF, 0 }, /* 21 data config */ - { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */ - { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */ - { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */ - { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */ - { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */ - { 0xFF, 0xFF, 0 }, /* 27 HP control */ - { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */ - { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */ - { 0xFF, 0xFF, 0 }, /* 2A REC control */ - { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */ - { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */ - { 0xFF, 0xFF, 0 }, /* 2D SPK control */ - { 0xFF, 0xFF, 0 }, /* 2E sidetone */ - { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */ - - { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */ - { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */ - { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */ - { 0xFF, 0xFF, 0 }, /* 33 left ADC level */ - { 0xFF, 0xFF, 0 }, /* 34 right ADC level */ - { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */ - { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */ - { 0xFF, 0xFF, 0 }, /* 37 INA level */ - { 0xFF, 0xFF, 0 }, /* 38 INB level */ - { 0xFF, 0xFF, 0 }, /* 39 left HP volume */ - { 0xFF, 0xFF, 0 }, /* 3A right HP volume */ - { 0xFF, 0xFF, 0 }, /* 3B left REC volume */ - { 0xFF, 0xFF, 0 }, /* 3C right REC volume */ - { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */ - { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */ - { 0xFF, 0xFF, 0 }, /* 3F MIC config */ - - { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */ - { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */ - { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */ - { 0xFF, 0xFF, 0 }, /* 43 ALC */ - { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */ - { 0xFF, 0xFF, 0 }, /* 45 power limiter config */ - { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */ - { 0xFF, 0xFF, 0 }, /* 47 audio input */ - { 0xFF, 0xFF, 0 }, /* 48 microphone */ - { 0xFF, 0xFF, 0 }, /* 49 level control */ - { 0xFF, 0xFF, 0 }, /* 4A bypass switches */ - { 0xFF, 0xFF, 0 }, /* 4B jack detect */ - { 0xFF, 0xFF, 0 }, /* 4C input enable */ - { 0xFF, 0xFF, 0 }, /* 4D output enable */ - { 0xFF, 0xFF, 0 }, /* 4E bias control */ - { 0xFF, 0xFF, 0 }, /* 4F DAC power */ - - { 0xFF, 0xFF, 0 }, /* 50 DAC power */ - { 0xFF, 0xFF, 0 }, /* 51 system */ - { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */ - - { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */ - - { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */ - { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */ - - { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */ - { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */ - { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */ - - { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */ - { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */ - - { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */ - { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */ - { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */ - - { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */ - { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */ - { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */ - - { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */ - { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */ - { 0x00, 0x00, 0 }, /* CA */ - { 0x00, 0x00, 0 }, /* CB */ - { 0x00, 0x00, 0 }, /* CC */ - { 0x00, 0x00, 0 }, /* CD */ - { 0x00, 0x00, 0 }, /* CE */ - { 0x00, 0x00, 0 }, /* CF */ - - { 0x00, 0x00, 0 }, /* D0 */ - { 0x00, 0x00, 0 }, /* D1 */ - { 0x00, 0x00, 0 }, /* D2 */ - { 0x00, 0x00, 0 }, /* D3 */ - { 0x00, 0x00, 0 }, /* D4 */ - { 0x00, 0x00, 0 }, /* D5 */ - { 0x00, 0x00, 0 }, /* D6 */ - { 0x00, 0x00, 0 }, /* D7 */ - { 0x00, 0x00, 0 }, /* D8 */ - { 0x00, 0x00, 0 }, /* D9 */ - { 0x00, 0x00, 0 }, /* DA */ - { 0x00, 0x00, 0 }, /* DB */ - { 0x00, 0x00, 0 }, /* DC */ - { 0x00, 0x00, 0 }, /* DD */ - { 0x00, 0x00, 0 }, /* DE */ - { 0x00, 0x00, 0 }, /* DF */ - - { 0x00, 0x00, 0 }, /* E0 */ - { 0x00, 0x00, 0 }, /* E1 */ - { 0x00, 0x00, 0 }, /* E2 */ - { 0x00, 0x00, 0 }, /* E3 */ - { 0x00, 0x00, 0 }, /* E4 */ - { 0x00, 0x00, 0 }, /* E5 */ - { 0x00, 0x00, 0 }, /* E6 */ - { 0x00, 0x00, 0 }, /* E7 */ - { 0x00, 0x00, 0 }, /* E8 */ - { 0x00, 0x00, 0 }, /* E9 */ - { 0x00, 0x00, 0 }, /* EA */ - { 0x00, 0x00, 0 }, /* EB */ - { 0x00, 0x00, 0 }, /* EC */ - { 0x00, 0x00, 0 }, /* ED */ - { 0x00, 0x00, 0 }, /* EE */ - { 0x00, 0x00, 0 }, /* EF */ - - { 0x00, 0x00, 0 }, /* F0 */ - { 0x00, 0x00, 0 }, /* F1 */ - { 0x00, 0x00, 0 }, /* F2 */ - { 0x00, 0x00, 0 }, /* F3 */ - { 0x00, 0x00, 0 }, /* F4 */ - { 0x00, 0x00, 0 }, /* F5 */ - { 0x00, 0x00, 0 }, /* F6 */ - { 0x00, 0x00, 0 }, /* F7 */ - { 0x00, 0x00, 0 }, /* F8 */ - { 0x00, 0x00, 0 }, /* F9 */ - { 0x00, 0x00, 0 }, /* FA */ - { 0x00, 0x00, 0 }, /* FB */ - { 0x00, 0x00, 0 }, /* FC */ - { 0x00, 0x00, 0 }, /* FD */ - { 0x00, 0x00, 0 }, /* FE */ - { 0xFF, 0x00, 1 }, /* FF */ -}; - static bool max98088_readable_register(struct device *dev, unsigned int reg) { - return max98088_access[reg].readable; + switch (reg) { + case M98088_REG_00_IRQ_STATUS ... 0xC9: + case M98088_REG_FF_REV_ID: + return true; + default: + return false; + } +} + +static bool max98088_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case M98088_REG_03_BATTERY_VOLTAGE ... 0xC9: + return true; + default: + return false; + } } static bool max98088_volatile_register(struct device *dev, unsigned int reg) { - return max98088_access[reg].vol; + switch (reg) { + case M98088_REG_00_IRQ_STATUS ... M98088_REG_03_BATTERY_VOLTAGE: + case M98088_REG_FF_REV_ID: + return true; + default: + return false; + } } static const struct regmap_config max98088_regmap = { @@ -551,6 +295,7 @@ static const struct regmap_config max98088_regmap = { .val_bits = 8, .readable_reg = max98088_readable_register, + .writeable_reg = max98088_writeable_register, .volatile_reg = max98088_volatile_register, .max_register = 0xff, -- cgit v0.10.2 From 5549ce82e29c6c1a45ad36a871096ae7c53e53b9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 28 Jul 2015 13:30:14 +0800 Subject: ASoC: max98095: Get rid of max98095_access table The max98095_access table is used for look up readable/writable attributes of registers. The readable/writable/volatile registers are mostly in continuous ranges, so we can replace the max98095_access table entirely by using case range. Below is a summary of the readable/writeable/volatile registers: readable registers: 0x01 ~ 0x97, 0xFF writeable registers: 0x0F ~ 0x97 volatile registers: 0x00 ~ 0x0E, 0x98 ~ 0xFF This patch reworks the implement for .readable and .volatile and also add implementation for .writable callback. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 66afd2b..078533e 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -202,300 +202,36 @@ static const struct reg_default max98095_reg_def[] = { { 0xff, 0x00 }, /* FF */ }; -static struct { - int readable; - int writable; -} max98095_access[M98095_REG_CNT] = { - { 0x00, 0x00 }, /* 00 */ - { 0xFF, 0x00 }, /* 01 */ - { 0xFF, 0x00 }, /* 02 */ - { 0xFF, 0x00 }, /* 03 */ - { 0xFF, 0x00 }, /* 04 */ - { 0xFF, 0x00 }, /* 05 */ - { 0xFF, 0x00 }, /* 06 */ - { 0xFF, 0x00 }, /* 07 */ - { 0xFF, 0x00 }, /* 08 */ - { 0xFF, 0x00 }, /* 09 */ - { 0xFF, 0x00 }, /* 0A */ - { 0xFF, 0x00 }, /* 0B */ - { 0xFF, 0x00 }, /* 0C */ - { 0xFF, 0x00 }, /* 0D */ - { 0xFF, 0x00 }, /* 0E */ - { 0xFF, 0x9F }, /* 0F */ - { 0xFF, 0xFF }, /* 10 */ - { 0xFF, 0xFF }, /* 11 */ - { 0xFF, 0xFF }, /* 12 */ - { 0xFF, 0xFF }, /* 13 */ - { 0xFF, 0xFF }, /* 14 */ - { 0xFF, 0xFF }, /* 15 */ - { 0xFF, 0xFF }, /* 16 */ - { 0xFF, 0xFF }, /* 17 */ - { 0xFF, 0xFF }, /* 18 */ - { 0xFF, 0xFF }, /* 19 */ - { 0xFF, 0xFF }, /* 1A */ - { 0xFF, 0xFF }, /* 1B */ - { 0xFF, 0xFF }, /* 1C */ - { 0xFF, 0xFF }, /* 1D */ - { 0xFF, 0x77 }, /* 1E */ - { 0xFF, 0x77 }, /* 1F */ - { 0xFF, 0x77 }, /* 20 */ - { 0xFF, 0x77 }, /* 21 */ - { 0xFF, 0x77 }, /* 22 */ - { 0xFF, 0x77 }, /* 23 */ - { 0xFF, 0xFF }, /* 24 */ - { 0xFF, 0x7F }, /* 25 */ - { 0xFF, 0x31 }, /* 26 */ - { 0xFF, 0xFF }, /* 27 */ - { 0xFF, 0xFF }, /* 28 */ - { 0xFF, 0xFF }, /* 29 */ - { 0xFF, 0xF7 }, /* 2A */ - { 0xFF, 0x2F }, /* 2B */ - { 0xFF, 0xEF }, /* 2C */ - { 0xFF, 0xFF }, /* 2D */ - { 0xFF, 0xFF }, /* 2E */ - { 0xFF, 0xFF }, /* 2F */ - { 0xFF, 0xFF }, /* 30 */ - { 0xFF, 0xFF }, /* 31 */ - { 0xFF, 0xFF }, /* 32 */ - { 0xFF, 0xFF }, /* 33 */ - { 0xFF, 0xF7 }, /* 34 */ - { 0xFF, 0x2F }, /* 35 */ - { 0xFF, 0xCF }, /* 36 */ - { 0xFF, 0xFF }, /* 37 */ - { 0xFF, 0xFF }, /* 38 */ - { 0xFF, 0xFF }, /* 39 */ - { 0xFF, 0xFF }, /* 3A */ - { 0xFF, 0xFF }, /* 3B */ - { 0xFF, 0xFF }, /* 3C */ - { 0xFF, 0xFF }, /* 3D */ - { 0xFF, 0xF7 }, /* 3E */ - { 0xFF, 0x2F }, /* 3F */ - { 0xFF, 0xCF }, /* 40 */ - { 0xFF, 0xFF }, /* 41 */ - { 0xFF, 0x77 }, /* 42 */ - { 0xFF, 0xFF }, /* 43 */ - { 0xFF, 0xFF }, /* 44 */ - { 0xFF, 0xFF }, /* 45 */ - { 0xFF, 0xFF }, /* 46 */ - { 0xFF, 0xFF }, /* 47 */ - { 0xFF, 0xFF }, /* 48 */ - { 0xFF, 0x0F }, /* 49 */ - { 0xFF, 0xFF }, /* 4A */ - { 0xFF, 0xFF }, /* 4B */ - { 0xFF, 0x3F }, /* 4C */ - { 0xFF, 0x3F }, /* 4D */ - { 0xFF, 0x3F }, /* 4E */ - { 0xFF, 0xFF }, /* 4F */ - { 0xFF, 0x7F }, /* 50 */ - { 0xFF, 0x7F }, /* 51 */ - { 0xFF, 0x0F }, /* 52 */ - { 0xFF, 0x3F }, /* 53 */ - { 0xFF, 0x3F }, /* 54 */ - { 0xFF, 0x3F }, /* 55 */ - { 0xFF, 0xFF }, /* 56 */ - { 0xFF, 0xFF }, /* 57 */ - { 0xFF, 0xBF }, /* 58 */ - { 0xFF, 0x1F }, /* 59 */ - { 0xFF, 0xBF }, /* 5A */ - { 0xFF, 0x1F }, /* 5B */ - { 0xFF, 0xBF }, /* 5C */ - { 0xFF, 0x3F }, /* 5D */ - { 0xFF, 0x3F }, /* 5E */ - { 0xFF, 0x7F }, /* 5F */ - { 0xFF, 0x7F }, /* 60 */ - { 0xFF, 0x47 }, /* 61 */ - { 0xFF, 0x9F }, /* 62 */ - { 0xFF, 0x9F }, /* 63 */ - { 0xFF, 0x9F }, /* 64 */ - { 0xFF, 0x9F }, /* 65 */ - { 0xFF, 0x9F }, /* 66 */ - { 0xFF, 0xBF }, /* 67 */ - { 0xFF, 0xBF }, /* 68 */ - { 0xFF, 0xFF }, /* 69 */ - { 0xFF, 0xFF }, /* 6A */ - { 0xFF, 0x7F }, /* 6B */ - { 0xFF, 0xF7 }, /* 6C */ - { 0xFF, 0xFF }, /* 6D */ - { 0xFF, 0xFF }, /* 6E */ - { 0xFF, 0x1F }, /* 6F */ - { 0xFF, 0xF7 }, /* 70 */ - { 0xFF, 0xFF }, /* 71 */ - { 0xFF, 0xFF }, /* 72 */ - { 0xFF, 0x1F }, /* 73 */ - { 0xFF, 0xF7 }, /* 74 */ - { 0xFF, 0xFF }, /* 75 */ - { 0xFF, 0xFF }, /* 76 */ - { 0xFF, 0x1F }, /* 77 */ - { 0xFF, 0xF7 }, /* 78 */ - { 0xFF, 0xFF }, /* 79 */ - { 0xFF, 0xFF }, /* 7A */ - { 0xFF, 0x1F }, /* 7B */ - { 0xFF, 0xF7 }, /* 7C */ - { 0xFF, 0xFF }, /* 7D */ - { 0xFF, 0xFF }, /* 7E */ - { 0xFF, 0x1F }, /* 7F */ - { 0xFF, 0xF7 }, /* 80 */ - { 0xFF, 0xFF }, /* 81 */ - { 0xFF, 0xFF }, /* 82 */ - { 0xFF, 0x1F }, /* 83 */ - { 0xFF, 0x7F }, /* 84 */ - { 0xFF, 0x0F }, /* 85 */ - { 0xFF, 0xD8 }, /* 86 */ - { 0xFF, 0xFF }, /* 87 */ - { 0xFF, 0xEF }, /* 88 */ - { 0xFF, 0xFE }, /* 89 */ - { 0xFF, 0xFE }, /* 8A */ - { 0xFF, 0xFF }, /* 8B */ - { 0xFF, 0xFF }, /* 8C */ - { 0xFF, 0x3F }, /* 8D */ - { 0xFF, 0xFF }, /* 8E */ - { 0xFF, 0x3F }, /* 8F */ - { 0xFF, 0x8F }, /* 90 */ - { 0xFF, 0xFF }, /* 91 */ - { 0xFF, 0x3F }, /* 92 */ - { 0xFF, 0xFF }, /* 93 */ - { 0xFF, 0xFF }, /* 94 */ - { 0xFF, 0x0F }, /* 95 */ - { 0xFF, 0x3F }, /* 96 */ - { 0xFF, 0x8C }, /* 97 */ - { 0x00, 0x00 }, /* 98 */ - { 0x00, 0x00 }, /* 99 */ - { 0x00, 0x00 }, /* 9A */ - { 0x00, 0x00 }, /* 9B */ - { 0x00, 0x00 }, /* 9C */ - { 0x00, 0x00 }, /* 9D */ - { 0x00, 0x00 }, /* 9E */ - { 0x00, 0x00 }, /* 9F */ - { 0x00, 0x00 }, /* A0 */ - { 0x00, 0x00 }, /* A1 */ - { 0x00, 0x00 }, /* A2 */ - { 0x00, 0x00 }, /* A3 */ - { 0x00, 0x00 }, /* A4 */ - { 0x00, 0x00 }, /* A5 */ - { 0x00, 0x00 }, /* A6 */ - { 0x00, 0x00 }, /* A7 */ - { 0x00, 0x00 }, /* A8 */ - { 0x00, 0x00 }, /* A9 */ - { 0x00, 0x00 }, /* AA */ - { 0x00, 0x00 }, /* AB */ - { 0x00, 0x00 }, /* AC */ - { 0x00, 0x00 }, /* AD */ - { 0x00, 0x00 }, /* AE */ - { 0x00, 0x00 }, /* AF */ - { 0x00, 0x00 }, /* B0 */ - { 0x00, 0x00 }, /* B1 */ - { 0x00, 0x00 }, /* B2 */ - { 0x00, 0x00 }, /* B3 */ - { 0x00, 0x00 }, /* B4 */ - { 0x00, 0x00 }, /* B5 */ - { 0x00, 0x00 }, /* B6 */ - { 0x00, 0x00 }, /* B7 */ - { 0x00, 0x00 }, /* B8 */ - { 0x00, 0x00 }, /* B9 */ - { 0x00, 0x00 }, /* BA */ - { 0x00, 0x00 }, /* BB */ - { 0x00, 0x00 }, /* BC */ - { 0x00, 0x00 }, /* BD */ - { 0x00, 0x00 }, /* BE */ - { 0x00, 0x00 }, /* BF */ - { 0x00, 0x00 }, /* C0 */ - { 0x00, 0x00 }, /* C1 */ - { 0x00, 0x00 }, /* C2 */ - { 0x00, 0x00 }, /* C3 */ - { 0x00, 0x00 }, /* C4 */ - { 0x00, 0x00 }, /* C5 */ - { 0x00, 0x00 }, /* C6 */ - { 0x00, 0x00 }, /* C7 */ - { 0x00, 0x00 }, /* C8 */ - { 0x00, 0x00 }, /* C9 */ - { 0x00, 0x00 }, /* CA */ - { 0x00, 0x00 }, /* CB */ - { 0x00, 0x00 }, /* CC */ - { 0x00, 0x00 }, /* CD */ - { 0x00, 0x00 }, /* CE */ - { 0x00, 0x00 }, /* CF */ - { 0x00, 0x00 }, /* D0 */ - { 0x00, 0x00 }, /* D1 */ - { 0x00, 0x00 }, /* D2 */ - { 0x00, 0x00 }, /* D3 */ - { 0x00, 0x00 }, /* D4 */ - { 0x00, 0x00 }, /* D5 */ - { 0x00, 0x00 }, /* D6 */ - { 0x00, 0x00 }, /* D7 */ - { 0x00, 0x00 }, /* D8 */ - { 0x00, 0x00 }, /* D9 */ - { 0x00, 0x00 }, /* DA */ - { 0x00, 0x00 }, /* DB */ - { 0x00, 0x00 }, /* DC */ - { 0x00, 0x00 }, /* DD */ - { 0x00, 0x00 }, /* DE */ - { 0x00, 0x00 }, /* DF */ - { 0x00, 0x00 }, /* E0 */ - { 0x00, 0x00 }, /* E1 */ - { 0x00, 0x00 }, /* E2 */ - { 0x00, 0x00 }, /* E3 */ - { 0x00, 0x00 }, /* E4 */ - { 0x00, 0x00 }, /* E5 */ - { 0x00, 0x00 }, /* E6 */ - { 0x00, 0x00 }, /* E7 */ - { 0x00, 0x00 }, /* E8 */ - { 0x00, 0x00 }, /* E9 */ - { 0x00, 0x00 }, /* EA */ - { 0x00, 0x00 }, /* EB */ - { 0x00, 0x00 }, /* EC */ - { 0x00, 0x00 }, /* ED */ - { 0x00, 0x00 }, /* EE */ - { 0x00, 0x00 }, /* EF */ - { 0x00, 0x00 }, /* F0 */ - { 0x00, 0x00 }, /* F1 */ - { 0x00, 0x00 }, /* F2 */ - { 0x00, 0x00 }, /* F3 */ - { 0x00, 0x00 }, /* F4 */ - { 0x00, 0x00 }, /* F5 */ - { 0x00, 0x00 }, /* F6 */ - { 0x00, 0x00 }, /* F7 */ - { 0x00, 0x00 }, /* F8 */ - { 0x00, 0x00 }, /* F9 */ - { 0x00, 0x00 }, /* FA */ - { 0x00, 0x00 }, /* FB */ - { 0x00, 0x00 }, /* FC */ - { 0x00, 0x00 }, /* FD */ - { 0x00, 0x00 }, /* FE */ - { 0xFF, 0x00 }, /* FF */ -}; - static bool max98095_readable(struct device *dev, unsigned int reg) { - if (reg >= M98095_REG_CNT) - return 0; - return max98095_access[reg].readable != 0; + switch (reg) { + case M98095_001_HOST_INT_STS ... M98095_097_PWR_SYS: + case M98095_0FF_REV_ID: + return true; + default: + return false; + } } -static bool max98095_volatile(struct device *dev, unsigned int reg) +static bool max98095_writeable(struct device *dev, unsigned int reg) { - if (reg > M98095_REG_MAX_CACHED) - return 1; - switch (reg) { - case M98095_000_HOST_DATA: - case M98095_001_HOST_INT_STS: - case M98095_002_HOST_RSP_STS: - case M98095_003_HOST_CMD_STS: - case M98095_004_CODEC_STS: - case M98095_005_DAI1_ALC_STS: - case M98095_006_DAI2_ALC_STS: - case M98095_007_JACK_AUTO_STS: - case M98095_008_JACK_MANUAL_STS: - case M98095_009_JACK_VBAT_STS: - case M98095_00A_ACC_ADC_STS: - case M98095_00B_MIC_NG_AGC_STS: - case M98095_00C_SPK_L_VOLT_STS: - case M98095_00D_SPK_R_VOLT_STS: - case M98095_00E_TEMP_SENSOR_STS: - return 1; + case M98095_00F_HOST_CFG ... M98095_097_PWR_SYS: + return true; + default: + return false; } +} - return 0; +static bool max98095_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case M98095_000_HOST_DATA ... M98095_00E_TEMP_SENSOR_STS: + case M98095_REG_MAX_CACHED + 1 ... M98095_0FF_REV_ID: + return true; + default: + return false; + } } static const struct regmap_config max98095_regmap = { @@ -508,6 +244,7 @@ static const struct regmap_config max98095_regmap = { .cache_type = REGCACHE_RBTREE, .readable_reg = max98095_readable, + .writeable_reg = max98095_writeable, .volatile_reg = max98095_volatile, }; -- cgit v0.10.2 From 85e7118412fea31464b62d00bcf4a65fa8904dcc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 28 Jul 2015 13:39:01 +0800 Subject: ASoC: wm8983: Get rid of wm8983_access_masks table The max8983_access table is used for look up readable/writable attributes of registers. The writable registers are mostly in continuous ranges, so we can replace max8983_access table by using case range. The read fields are all 0, so just drop implement of .readable callback. Also set .max_register setting. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2fdd2c6..84c8586 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -84,66 +84,6 @@ static const struct reg_default wm8983_defaults[] = { { 0x3D, 0x0000 }, /* R61 - BIAS CTRL */ }; -static const struct wm8983_reg_access { - u16 read; /* Mask of readable bits */ - u16 write; /* Mask of writable bits */ -} wm8983_access_masks[WM8983_MAX_REGISTER + 1] = { - [0x00] = { 0x0000, 0x01FF }, /* R0 - Software Reset */ - [0x01] = { 0x0000, 0x01FF }, /* R1 - Power management 1 */ - [0x02] = { 0x0000, 0x01FF }, /* R2 - Power management 2 */ - [0x03] = { 0x0000, 0x01EF }, /* R3 - Power management 3 */ - [0x04] = { 0x0000, 0x01FF }, /* R4 - Audio Interface */ - [0x05] = { 0x0000, 0x003F }, /* R5 - Companding control */ - [0x06] = { 0x0000, 0x01FD }, /* R6 - Clock Gen control */ - [0x07] = { 0x0000, 0x000F }, /* R7 - Additional control */ - [0x08] = { 0x0000, 0x003F }, /* R8 - GPIO Control */ - [0x09] = { 0x0000, 0x0070 }, /* R9 - Jack Detect Control 1 */ - [0x0A] = { 0x0000, 0x004F }, /* R10 - DAC Control */ - [0x0B] = { 0x0000, 0x01FF }, /* R11 - Left DAC digital Vol */ - [0x0C] = { 0x0000, 0x01FF }, /* R12 - Right DAC digital vol */ - [0x0D] = { 0x0000, 0x00FF }, /* R13 - Jack Detect Control 2 */ - [0x0E] = { 0x0000, 0x01FB }, /* R14 - ADC Control */ - [0x0F] = { 0x0000, 0x01FF }, /* R15 - Left ADC Digital Vol */ - [0x10] = { 0x0000, 0x01FF }, /* R16 - Right ADC Digital Vol */ - [0x12] = { 0x0000, 0x017F }, /* R18 - EQ1 - low shelf */ - [0x13] = { 0x0000, 0x017F }, /* R19 - EQ2 - peak 1 */ - [0x14] = { 0x0000, 0x017F }, /* R20 - EQ3 - peak 2 */ - [0x15] = { 0x0000, 0x017F }, /* R21 - EQ4 - peak 3 */ - [0x16] = { 0x0000, 0x007F }, /* R22 - EQ5 - high shelf */ - [0x18] = { 0x0000, 0x01FF }, /* R24 - DAC Limiter 1 */ - [0x19] = { 0x0000, 0x007F }, /* R25 - DAC Limiter 2 */ - [0x1B] = { 0x0000, 0x01FF }, /* R27 - Notch Filter 1 */ - [0x1C] = { 0x0000, 0x017F }, /* R28 - Notch Filter 2 */ - [0x1D] = { 0x0000, 0x017F }, /* R29 - Notch Filter 3 */ - [0x1E] = { 0x0000, 0x017F }, /* R30 - Notch Filter 4 */ - [0x20] = { 0x0000, 0x01BF }, /* R32 - ALC control 1 */ - [0x21] = { 0x0000, 0x00FF }, /* R33 - ALC control 2 */ - [0x22] = { 0x0000, 0x01FF }, /* R34 - ALC control 3 */ - [0x23] = { 0x0000, 0x000F }, /* R35 - Noise Gate */ - [0x24] = { 0x0000, 0x001F }, /* R36 - PLL N */ - [0x25] = { 0x0000, 0x003F }, /* R37 - PLL K 1 */ - [0x26] = { 0x0000, 0x01FF }, /* R38 - PLL K 2 */ - [0x27] = { 0x0000, 0x01FF }, /* R39 - PLL K 3 */ - [0x29] = { 0x0000, 0x000F }, /* R41 - 3D control */ - [0x2A] = { 0x0000, 0x01E7 }, /* R42 - OUT4 to ADC */ - [0x2B] = { 0x0000, 0x01BF }, /* R43 - Beep control */ - [0x2C] = { 0x0000, 0x0177 }, /* R44 - Input ctrl */ - [0x2D] = { 0x0000, 0x01FF }, /* R45 - Left INP PGA gain ctrl */ - [0x2E] = { 0x0000, 0x01FF }, /* R46 - Right INP PGA gain ctrl */ - [0x2F] = { 0x0000, 0x0177 }, /* R47 - Left ADC BOOST ctrl */ - [0x30] = { 0x0000, 0x0177 }, /* R48 - Right ADC BOOST ctrl */ - [0x31] = { 0x0000, 0x007F }, /* R49 - Output ctrl */ - [0x32] = { 0x0000, 0x01FF }, /* R50 - Left mixer ctrl */ - [0x33] = { 0x0000, 0x01FF }, /* R51 - Right mixer ctrl */ - [0x34] = { 0x0000, 0x01FF }, /* R52 - LOUT1 (HP) volume ctrl */ - [0x35] = { 0x0000, 0x01FF }, /* R53 - ROUT1 (HP) volume ctrl */ - [0x36] = { 0x0000, 0x01FF }, /* R54 - LOUT2 (SPK) volume ctrl */ - [0x37] = { 0x0000, 0x01FF }, /* R55 - ROUT2 (SPK) volume ctrl */ - [0x38] = { 0x0000, 0x004F }, /* R56 - OUT3 mixer ctrl */ - [0x39] = { 0x0000, 0x00FF }, /* R57 - OUT4 (MONO) mix ctrl */ - [0x3D] = { 0x0000, 0x0100 } /* R61 - BIAS CTRL */ -}; - /* vol/gain update regs */ static const int vol_update_regs[] = { WM8983_LEFT_DAC_DIGITAL_VOL, @@ -605,12 +545,19 @@ static int eqmode_put(struct snd_kcontrol *kcontrol, return 0; } -static bool wm8983_readable(struct device *dev, unsigned int reg) +static bool wm8983_writeable(struct device *dev, unsigned int reg) { - if (reg > WM8983_MAX_REGISTER) - return 0; - - return wm8983_access_masks[reg].read != 0; + switch (reg) { + case WM8983_SOFTWARE_RESET ... WM8983_RIGHT_ADC_DIGITAL_VOL: + case WM8983_EQ1_LOW_SHELF ... WM8983_DAC_LIMITER_2: + case WM8983_NOTCH_FILTER_1 ... WM8983_NOTCH_FILTER_4: + case WM8983_ALC_CONTROL_1 ... WM8983_PLL_K_3: + case WM8983_3D_CONTROL ... WM8983_OUT4_MONO_MIX_CTRL: + case WM8983_BIAS_CTRL: + return true; + default: + return false; + } } static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute) @@ -1048,8 +995,9 @@ static const struct regmap_config wm8983_regmap = { .reg_defaults = wm8983_defaults, .num_reg_defaults = ARRAY_SIZE(wm8983_defaults), .cache_type = REGCACHE_RBTREE, + .max_register = WM8983_MAX_REGISTER, - .readable_reg = wm8983_readable, + .writeable_reg = wm8983_writeable, }; #if defined(CONFIG_SPI_MASTER) -- cgit v0.10.2 From c8a6b92be8516c92cf46bc127fa0adf53a05d31c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:23 +0200 Subject: ASoC: wm8804: Drop duplicate const SOC_ENUM_SINGLE_DECL() already includes a const, drop the extra const. Fixes the following sparse warning: sound/soc/codecs/wm8804.c:101:14: warning: duplicate const Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index c195c2e..8d91470 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -98,7 +98,7 @@ WM8804_REGULATOR_EVENT(0) WM8804_REGULATOR_EVENT(1) static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; -static const SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text); +static SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text); static const struct snd_kcontrol_new wm8804_tx_source_mux[] = { SOC_DAPM_ENUM_EXT("Input Source", txsrc, -- cgit v0.10.2 From eccad574ef2d74e7519a092d9822932a27c6f165 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:24 +0200 Subject: ASoC: lpass-ipq806x: Staticise local symbols ipq806x_data is not used outside this file, so it can be static. Fixes the following sparse warning: sound/soc/qcom/lpass-ipq806x.c:76:22: warning: symbol 'ipq806x_data' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 7356d3a..7a41679 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -73,7 +73,7 @@ static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) return 0; } -struct lpass_variant ipq806x_data = { +static struct lpass_variant ipq806x_data = { .i2sctrl_reg_base = 0x0010, .i2sctrl_reg_stride = 0x04, .i2s_ports = 5, -- cgit v0.10.2 From e773c2f964640e103cc75a45aa4555c73ba55c29 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:25 +0200 Subject: ASoC: rcar ctu: Staticise local symbols rsnd_of_parse_ctu() is not used outside this file so it can be static. Fixes the following sparse warning: sound/soc/sh/rcar/ctu.c:72:6: warning: symbol 'rsnd_of_parse_ctu' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 05edd20..05498bb 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -69,7 +69,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) return &((struct rsnd_ctu *)(priv->ctu) + id)->mod; } -void rsnd_of_parse_ctu(struct platform_device *pdev, +static void rsnd_of_parse_ctu(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) { -- cgit v0.10.2 From b917abb4064b38b0613e953b09213e788ad94ad0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:26 +0200 Subject: ASoC: uniperf: Add missing __iomem annotation base referes to a iomem region, so it should have the __iomem annotation. Fixes the following warnings from sparse: sound/soc/sti/sti_uniperif.c:169:19: warning: incorrect type in assignment (different address spaces) sound/soc/sti/sti_uniperif.c:169:19: expected void *base sound/soc/sti/sti_uniperif.c:169:19: got void [noderef] * sound/soc/sti/uniperif_player.c:104:18: warning: incorrect type in argument 1 (different address spaces) sound/soc/sti/uniperif_player.c:104:18: expected void const volatile [noderef] *addr sound/soc/sti/uniperif_player.c:104:18: got void * [...] Signed-off-by: Lars-Peter Clausen Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index ee462f7..f0fd5a9 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1168,7 +1168,7 @@ struct uniperif { /* Resources */ struct resource *mem_region; - void *base; + void __iomem *base; unsigned long fifo_phys_address; int irq; -- cgit v0.10.2 From 85cf604edc18722140f73e225394722801e55de0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:27 +0200 Subject: ASoC: uniperf: Staticise local symbols uni_player_dai_ops is not used outside of this file so it should be static. Fixes the following sparse warning: sound/soc/sti/uniperif_player.c:959:30: warning: symbol 'uni_player_dai_ops' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index f609089..d8df906 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -956,7 +956,7 @@ static int uni_player_parse_dt(struct platform_device *pdev, return 0; } -const struct snd_soc_dai_ops uni_player_dai_ops = { +static const struct snd_soc_dai_ops uni_player_dai_ops = { .startup = uni_player_startup, .shutdown = uni_player_shutdown, .prepare = uni_player_prepare, -- cgit v0.10.2 From d32e03f0b6f9b4ad260feca1c5c938a882066de9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 27 Jul 2015 10:56:28 +0200 Subject: ASoC: xtfpga-i2s: Add missing __rcu annotation tx_substeam is accessed using the RCU API and hence should have the __rcu annotation. Fixes the following sparse warnings: sound/soc/xtensa/xtfpga-i2s.c:165:24: error: incompatible types in comparison expression (different address spaces) sound/soc/xtensa/xtfpga-i2s.c:165:24: error: 'struct snd_pcm_substream [noderef] *' versus sound/soc/xtensa/xtfpga-i2s.c:165:24: error: 'struct snd_pcm_substream *' sound/soc/xtensa/xtfpga-i2s.c:255:24: error: incompatible types in comparison expression (different address spaces) sound/soc/xtensa/xtfpga-i2s.c:255:24: error: 'struct snd_pcm_substream [noderef] *' versus sound/soc/xtensa/xtfpga-i2s.c:255:24: error: 'struct snd_pcm_substream *' Signed-off-by: Lars-Peter Clausen Acked-by: Max Filippov Signed-off-by: Mark Brown diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 039f65e..8382ffa 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -75,7 +75,7 @@ struct xtfpga_i2s { * stream in the pcm_close callback it synchronizes with the interrupt * handler by means of synchronize_rcu call. */ - struct snd_pcm_substream *tx_substream; + struct snd_pcm_substream __rcu *tx_substream; unsigned (*tx_fn)(struct xtfpga_i2s *i2s, struct snd_pcm_runtime *runtime, unsigned tx_ptr); -- cgit v0.10.2 From 8ef9724bf9718af81cfc5132253372f79c71b7e2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 26 Jul 2015 21:34:50 -0700 Subject: regmap: regcache-rbtree: Clean new present bits on present bitmap resize When inserting a new register into a block, the present bit map size is increased using krealloc. krealloc does not clear the additionally allocated memory, leaving it filled with random values. Result is that some registers are considered cached even though this is not the case. Fix the problem by clearing the additionally allocated memory. Also, if the bitmap size does not increase, do not reallocate the bitmap at all to reduce overhead. Fixes: 3f4ff561bc88 ("regmap: rbtree: Make cache_present bitmap per node") Signed-off-by: Guenter Roeck Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 81751a4..56486d9 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -296,11 +296,20 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, if (!blk) return -ENOMEM; - present = krealloc(rbnode->cache_present, - BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL); - if (!present) { - kfree(blk); - return -ENOMEM; + if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) { + present = krealloc(rbnode->cache_present, + BITS_TO_LONGS(blklen) * sizeof(*present), + GFP_KERNEL); + if (!present) { + kfree(blk); + return -ENOMEM; + } + + memset(present + BITS_TO_LONGS(rbnode->blklen), 0, + (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen)) + * sizeof(*present)); + } else { + present = rbnode->cache_present; } /* insert the register value in the correct place in the rbnode block */ -- cgit v0.10.2 From 62d6d47cb8bd5ace08a90a1cd78f6908e9f9c2d3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 27 Jul 2015 09:39:43 +0800 Subject: ASoC: max98090: Simplify max98090_readable_register implementation The readable registers are in consecutive ranges: 0x01 ~ 0x03, 0x0D ~ 0xD1, 0xFF So simplify the implementation by specifying a range of consecutive values in a single case label. Signed-off-by: Axel Lin Reviewed-by: Jarkko Nikula Tested-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1697340..17ab597 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -267,75 +267,8 @@ static bool max98090_volatile_register(struct device *dev, unsigned int reg) static bool max98090_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case M98090_REG_DEVICE_STATUS: - case M98090_REG_JACK_STATUS: - case M98090_REG_INTERRUPT_S: - case M98090_REG_RESERVED: - case M98090_REG_LINE_INPUT_CONFIG: - case M98090_REG_LINE_INPUT_LEVEL: - case M98090_REG_INPUT_MODE: - case M98090_REG_MIC1_INPUT_LEVEL: - case M98090_REG_MIC2_INPUT_LEVEL: - case M98090_REG_MIC_BIAS_VOLTAGE: - case M98090_REG_DIGITAL_MIC_ENABLE: - case M98090_REG_DIGITAL_MIC_CONFIG: - case M98090_REG_LEFT_ADC_MIXER: - case M98090_REG_RIGHT_ADC_MIXER: - case M98090_REG_LEFT_ADC_LEVEL: - case M98090_REG_RIGHT_ADC_LEVEL: - case M98090_REG_ADC_BIQUAD_LEVEL: - case M98090_REG_ADC_SIDETONE: - case M98090_REG_SYSTEM_CLOCK: - case M98090_REG_CLOCK_MODE: - case M98090_REG_CLOCK_RATIO_NI_MSB: - case M98090_REG_CLOCK_RATIO_NI_LSB: - case M98090_REG_CLOCK_RATIO_MI_MSB: - case M98090_REG_CLOCK_RATIO_MI_LSB: - case M98090_REG_MASTER_MODE: - case M98090_REG_INTERFACE_FORMAT: - case M98090_REG_TDM_CONTROL: - case M98090_REG_TDM_FORMAT: - case M98090_REG_IO_CONFIGURATION: - case M98090_REG_FILTER_CONFIG: - case M98090_REG_DAI_PLAYBACK_LEVEL: - case M98090_REG_DAI_PLAYBACK_LEVEL_EQ: - case M98090_REG_LEFT_HP_MIXER: - case M98090_REG_RIGHT_HP_MIXER: - case M98090_REG_HP_CONTROL: - case M98090_REG_LEFT_HP_VOLUME: - case M98090_REG_RIGHT_HP_VOLUME: - case M98090_REG_LEFT_SPK_MIXER: - case M98090_REG_RIGHT_SPK_MIXER: - case M98090_REG_SPK_CONTROL: - case M98090_REG_LEFT_SPK_VOLUME: - case M98090_REG_RIGHT_SPK_VOLUME: - case M98090_REG_DRC_TIMING: - case M98090_REG_DRC_COMPRESSOR: - case M98090_REG_DRC_EXPANDER: - case M98090_REG_DRC_GAIN: - case M98090_REG_RCV_LOUTL_MIXER: - case M98090_REG_RCV_LOUTL_CONTROL: - case M98090_REG_RCV_LOUTL_VOLUME: - case M98090_REG_LOUTR_MIXER: - case M98090_REG_LOUTR_CONTROL: - case M98090_REG_LOUTR_VOLUME: - case M98090_REG_JACK_DETECT: - case M98090_REG_INPUT_ENABLE: - case M98090_REG_OUTPUT_ENABLE: - case M98090_REG_LEVEL_CONTROL: - case M98090_REG_DSP_FILTER_ENABLE: - case M98090_REG_BIAS_CONTROL: - case M98090_REG_DAC_CONTROL: - case M98090_REG_ADC_CONTROL: - case M98090_REG_DEVICE_SHUTDOWN: - case M98090_REG_EQUALIZER_BASE ... M98090_REG_EQUALIZER_BASE + 0x68: - case M98090_REG_RECORD_BIQUAD_BASE ... M98090_REG_RECORD_BIQUAD_BASE + 0x0E: - case M98090_REG_DMIC3_VOLUME: - case M98090_REG_DMIC4_VOLUME: - case M98090_REG_DMIC34_BQ_PREATTEN: - case M98090_REG_RECORD_TDM_SLOT: - case M98090_REG_SAMPLE_RATE: - case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: + case M98090_REG_DEVICE_STATUS ... M98090_REG_INTERRUPT_S: + case M98090_REG_LINE_INPUT_CONFIG ... 0xD1: case M98090_REG_REVISION_ID: return true; default: -- cgit v0.10.2 From f0ad462189cc898aa0ef8ced849533ee03392bcc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 23 Jul 2015 13:06:10 +0200 Subject: netfilter: nf_conntrack: silence warning on falling back to vmalloc() Since 88eab472ec21 ("netfilter: conntrack: adjust nf_conntrack_buckets default value"), the hashtable can easily hit this warning. We got reports from users that are getting this message in a quite spamming fashion, so better silence this. Signed-off-by: Pablo Neira Ayuso Acked-by: Florian Westphal diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 651039a..f168099 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1544,10 +1544,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) sz = nr_slots * sizeof(struct hlist_nulls_head); hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, get_order(sz)); - if (!hash) { - printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); + if (!hash) hash = vzalloc(sz); - } if (hash && nulls) for (i = 0; i < nr_slots; i++) -- cgit v0.10.2 From 586b7ccdb7143b6a9b975d2c6ad52b6ca5c162b9 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 28 Jul 2015 15:03:05 +0200 Subject: KVM: s390: Fix hang VCPU hang/loop regression commit 785dbef407d8 ("KVM: s390: optimize round trip time in request handling") introduced a regression. This regression was seen with CPU hotplug in the guest and switching between 1 or 2 CPUs. This will set/reset the IBS control via synced request. Whenever we make a synced request, we first set the vcpu->requests bit and then block the vcpu. The handler, on the other hand, unblocks itself, processes vcpu->requests (by clearing them) and unblocks itself once again. Now, if the requester sleeps between setting of vcpu->requests and blocking, the handler will clear the vcpu->requests bit and try to unblock itself (although no bit is set). When the requester wakes up, it blocks the VCPU and we have a blocked VCPU without requests. Solution is to always unset the block bit. Signed-off-by: Christian Borntraeger Reviewed-by: David Hildenbrand Fixes: 785dbef407d8 ("KVM: s390: optimize round trip time in request handling") diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 2078f92..f32f843 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1742,10 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu) static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) { - if (!vcpu->requests) - return 0; retry: kvm_s390_vcpu_request_handled(vcpu); + if (!vcpu->requests) + return 0; /* * We use MMU_RELOAD just to re-arm the ipte notifier for the * guest prefix page. gmap_ipte_notify will wait on the ptl lock. -- cgit v0.10.2 From 1a727c63612fc582370cf3dc01239d3d239743b5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Jul 2015 01:42:28 +0300 Subject: netfilter: nf_conntrack: checking for IS_ERR() instead of NULL We recently changed this from nf_conntrack_alloc() to nf_ct_tmpl_alloc() so the error handling needs to changed to check for NULL instead of IS_ERR(). Fixes: 0838aa7fcfcd ('netfilter: fix netns dependencies with conntrack templates') Signed-off-by: Dan Carpenter Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index 71f1e9f..d7f1685 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -353,10 +353,8 @@ static int __net_init synproxy_net_init(struct net *net) int err = -ENOMEM; ct = nf_ct_tmpl_alloc(net, 0, GFP_KERNEL); - if (IS_ERR(ct)) { - err = PTR_ERR(ct); + if (!ct) goto err1; - } if (!nfct_seqadj_ext_add(ct)) goto err2; diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index c663003..43ddeee 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -202,9 +202,10 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par, goto err1; ct = nf_ct_tmpl_alloc(par->net, info->zone, GFP_KERNEL); - ret = PTR_ERR(ct); - if (IS_ERR(ct)) + if (!ct) { + ret = -ENOMEM; goto err2; + } ret = 0; if ((info->ct_events || info->exp_events) && -- cgit v0.10.2 From aecdc63d87891c75e60906973c7b7c9cd58403d6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 Jul 2015 23:06:41 +0300 Subject: iwlwifi: pcie: fix stuck queue detection for sleeping clients The stuck queue detection mechanism allows to detect queues that are stuck. For sleeping clients, a queue may rightfully be stuck: if a poor client implementation stays asleep for more than 10s, then we don't want to trigger recovery flows because of that client. In order to cope with this, I added a mechanism that monitors the state of the client: when a client goes to sleep, the timer of his queues is frozen. When he wakes up, the timer is reset to the right value so that if a client was awake for more than 10s and the queues are stuck, only then, the recovery flow will kick in. This is valid only on non-shared queues: A-MPDU queues. There was a bug in case we Tx to a sleeping client that has an empty A-MPDU queue: the timer was armed to now + 10s. This is bad, but pretty harmless. The problem is that when the client wakes up, the timer is modified to be now + remainder. But remainder is 0 since the queue was empty when that client went to sleep... Fix this by checking the state of the client before playing with the timer when we add a packet to an empty queue. Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2b86c21..607acb5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1875,8 +1875,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr) { - if (txq->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); + if (txq->wd_timeout) { + /* + * If the TXQ is active, then set the timer, if not, + * set the timer in remainder so that the timer will + * be armed with the right value when the station will + * wake up. + */ + if (!txq->frozen) + mod_timer(&txq->stuck_timer, + jiffies + txq->wd_timeout); + else + txq->frozen_expiry_remainder = txq->wd_timeout; + } IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); iwl_trans_pcie_ref(trans); } -- cgit v0.10.2 From be052cc87745e01846fb036eb81567c784439078 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 7 Jul 2015 16:06:15 +0300 Subject: extcon: Fix hang and extcon_get/set_cable_state(). Users of find_cable_index_by_name() will cause a kernel hang as the while loop counter is never incremented and end condition is never reached. extcon_get_cable_state() and extcon_set_cable_state() are broken because they use cable index instead of cable id. This causes the first cable state (cable.0) to be always invalid in sysfs or extcon_get_cable_state() users. Introduce a new function find_cable_id_by_name() that fixes both of the above issues. Fixes: commit 73b6ecdb93e8 ("extcon: Redefine the unique id of supported external connectors without 'enum extcon' type") Cc: Greg Kroah-Hartman Signed-off-by: Roger Quadros Tested-by: Ivan T. Ivanov [cw00.choi: Fix minor coding style] Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 76157ab..0e2af17 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -124,25 +124,35 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } -static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) +static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) { - unsigned int id = EXTCON_NONE; + unsigned int id = -EINVAL; int i = 0; - if (edev->max_supported == 0) - return -EINVAL; - - /* Find the the number of extcon cable */ + /* Find the id of extcon cable */ while (extcon_name[i]) { if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) { id = i; break; } + i++; } - if (id == EXTCON_NONE) + return id; +} + +static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) +{ + unsigned int id; + + if (edev->max_supported == 0) return -EINVAL; + /* Find the the number of extcon cable */ + id = find_cable_id_by_name(edev, name); + if (id < 0) + return id; + return find_cable_index_by_id(edev, id); } @@ -228,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev, struct extcon_cable *cable = container_of(attr, struct extcon_cable, attr_state); + int i = cable->cable_index; + return sprintf(buf, "%d\n", extcon_get_cable_state_(cable->edev, - cable->cable_index)); + cable->edev->supported_cable[i])); } /** @@ -361,8 +373,13 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_); */ int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) { - return extcon_get_cable_state_(edev, find_cable_index_by_name - (edev, cable_name)); + unsigned int id; + + id = find_cable_id_by_name(edev, cable_name); + if (id < 0) + return id; + + return extcon_get_cable_state_(edev, id); } EXPORT_SYMBOL_GPL(extcon_get_cable_state); @@ -404,8 +421,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_); int extcon_set_cable_state(struct extcon_dev *edev, const char *cable_name, bool cable_state) { - return extcon_set_cable_state_(edev, find_cable_index_by_name - (edev, cable_name), cable_state); + unsigned int id; + + id = find_cable_id_by_name(edev, cable_name); + if (id < 0) + return id; + + return extcon_set_cable_state_(edev, id, cable_state); } EXPORT_SYMBOL_GPL(extcon_set_cable_state); -- cgit v0.10.2 From 27bbd23fe8e66edfff4c0e92eb9eb39c37856831 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 31 Jul 2015 03:09:49 +0300 Subject: ARM: EXYNOS: Fix potentian kfree() of ro memory The change fixes a bug introduced by 2be2a3ff42a5, memory allocated by kstrdup_const() must be always deallocated with kfree_const(), otherwise there is a risk of kfree'ing ro memory in power domain error exit path. Signed-off-by: Vladimir Zapolskiy Cc: Fixes: 2be2a3ff42a5 ("ARM: EXYNOS: register power domain driver from core_initcall") Signed-off-by: Krzysztof Kozlowski diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 6001f1c..5121baa 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -146,7 +146,7 @@ static __init int exynos4_pm_init_power_domain(void) pd->base = of_iomap(np, 0); if (!pd->base) { pr_warn("%s: failed to map memory\n", __func__); - kfree(pd->pd.name); + kfree_const(pd->pd.name); kfree(pd); of_node_put(np); continue; -- cgit v0.10.2 From 3e9f798784b30293012682021d5a0352f78658b8 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 31 Jul 2015 03:09:50 +0300 Subject: ARM: EXYNOS: fix double of_node_put() on error path The change removes the second of_node_put(), if for_each_compatible_node() body execution is not terminated. This prevents from object refcounter overflow over zero in OF_DYNAMIC build. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Krzysztof Kozlowski diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 5121baa..4a87e86 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -148,7 +148,6 @@ static __init int exynos4_pm_init_power_domain(void) pr_warn("%s: failed to map memory\n", __func__); kfree_const(pd->pd.name); kfree(pd); - of_node_put(np); continue; } -- cgit v0.10.2 From 9450918293b3c35f11883231a53da1aed2c78403 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 29 Jul 2015 22:27:13 -0700 Subject: target: Perform RCU callback barrier before backend/fabric unload This patch addresses a v4.2-rc1 regression where backend driver module unload happening immediately after TBO->free_device() does internal call_rcu(), will currently result in IRQ context rcu_process_callbacks() use-after-free paging OOPsen. It adds the missing rcu_barrier() in target_backend_unregister() to perform an explicit RCU barrier waiting for all RCU callbacks to complete before releasing target_backend_ops memory, and allowing TBO->module exit to proceed. Also, do the same for fabric drivers in target_unregister_template() to ensure se_deve_entry->rcu_head -> kfree_rcu() callbacks have completed, before allowing target_core_fabric_ops->owner module exit to proceed. Acked-by: Paul E. McKenney Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index c2e9fea..860e840 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo) if (!strcmp(t->tf_ops->name, fo->name)) { BUG_ON(atomic_read(&t->tf_access_cnt)); list_del(&t->tf_list); + mutex_unlock(&g_tf_lock); + /* + * Wait for any outstanding fabric se_deve_entry->rcu_head + * callbacks to complete post kfree_rcu(), before allowing + * fabric driver unload of TFO->module to proceed. + */ + rcu_barrier(); kfree(t); - break; + return; } } mutex_unlock(&g_tf_lock); diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 62ea4e8..be9cefc 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops) list_for_each_entry(tb, &backend_list, list) { if (tb->ops == ops) { list_del(&tb->list); + mutex_unlock(&backend_mutex); + /* + * Wait for any outstanding backend driver ->rcu_head + * callbacks to complete post TBO->free_device() -> + * call_rcu(), before allowing backend driver module + * unload of target_backend_ops->owner to proceed. + */ + rcu_barrier(); kfree(tb); - break; + return; } } mutex_unlock(&backend_mutex); -- cgit v0.10.2 From 9547308bda296b6f69876c840a0291fcfbeddbb8 Mon Sep 17 00:00:00 2001 From: Alexei Potashnik Date: Tue, 21 Jul 2015 15:07:56 -0700 Subject: target/iscsi: Fix double free of a TUR followed by a solicited NOPOUT Make sure all non-READ SCSI commands get targ_xfer_tag initialized to 0xffffffff, not just WRITEs. Double-free of a TUR cmd object occurs under the following scenario: 1. TUR received (targ_xfer_tag is uninitialized and left at 0) 2. TUR status sent 3. First unsolicited NOPIN is sent to initiator (gets targ_xfer_tag of 0) 4. NOPOUT for NOPIN (with TTT=0) arrives - its ExpStatSN acks TUR status, TUR is queued for removal - LIO tries to find NOPIN with TTT=0, but finds the same TUR instead, TUR is queued for removal for the 2nd time (Drop unbalanced conditional bracket usage - nab) Signed-off-by: Alexei Potashnik Signed-off-by: Spencer Baugh Cc: # v3.1+ Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index cd77a06..fd09290 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -968,9 +968,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA; conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; - if (hdr->flags & ISCSI_FLAG_CMD_READ) { + if (hdr->flags & ISCSI_FLAG_CMD_READ) cmd->targ_xfer_tag = session_get_next_ttt(conn->sess); - } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE) + else cmd->targ_xfer_tag = 0xFFFFFFFF; cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); -- cgit v0.10.2 From f7a898117aebf3d52370fe637f4d7aff7a237afc Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 6 Jul 2015 17:46:58 +0300 Subject: extcon: Fix extcon_cable_get_state() from getting old state after notification Currently the extcon code notifiers the interested listeners before it updates the extcon state with the new state. This will cause the listeners that use extcon_cable_get_state() to get the stale state and loose the new state. Fix this by first changing the extcon state variable and then notifying listeners. Signed-off-by: Roger Quadros Tested-by: Ivan T. Ivanov Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 0e2af17..43b57b0 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -275,20 +275,25 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) spin_lock_irqsave(&edev->lock, flags); if (edev->state != ((edev->state & ~mask) | (state & mask))) { + u32 old_state; + if (check_mutually_exclusive(edev, (edev->state & ~mask) | (state & mask))) { spin_unlock_irqrestore(&edev->lock, flags); return -EPERM; } - for (index = 0; index < edev->max_supported; index++) { - if (is_extcon_changed(edev->state, state, index, &attached)) - raw_notifier_call_chain(&edev->nh[index], attached, edev); - } - + old_state = edev->state; edev->state &= ~mask; edev->state |= state & mask; + for (index = 0; index < edev->max_supported; index++) { + if (is_extcon_changed(old_state, edev->state, index, + &attached)) + raw_notifier_call_chain(&edev->nh[index], + attached, edev); + } + /* This could be in interrupt handler */ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); if (prop_buf) { -- cgit v0.10.2 From 5d5cd85ff441534a52f23f821d0a7c644d3b6cce Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 28 Jul 2015 07:51:01 +0200 Subject: rsi: Fix failure to load firmware after memory leak fix and fix the leak Fixes commit eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()") which stopped the driver from functioning. Firmware data has been allocated using vmalloc(), resulting in memory that cannot be used for DMA. Hence the firmware was first copied to a buffer allocated with kmalloc() in the original code. This patch reverts the commit and only calls "kfree()" to release the buffer after sending the data. This fixes the memory leak without breaking the driver. Add a comment to the kmemdup() calls to explain why this is done, and abort if memory allocation fails. Tested on a Topic Miami-Florida board which contains the rsi SDIO chip. Also added the same kfree() call to the USB glue driver. This was not tested on actual hardware though, as I only have the SDIO version. Fixes: eae79b4f3e82 ("rsi: fix memory leak in rsi_load_ta_instructions()") Signed-off-by: Mike Looijmans Cc: stable@vger.kernel.org Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index b6cc9ff..1c6788a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 len; u32 num_blocks; + const u8 *fw; const struct firmware *fw_entry = NULL; u32 block_size = dev->tx_blk_size; int status = 0; @@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } + /* Copy firmware into DMA-accessible memory */ + fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!fw) + return -ENOMEM; len = fw_entry->size; if (len % 4) @@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks); + status = rsi_copy_to_card(common, fw, len, num_blocks); + kfree(fw); release_firmware(fw_entry); return status; } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 1106ce7..30c2cf7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } + /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!fw) + return -ENOMEM; len = fw_entry->size; if (len % 4) @@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); status = rsi_copy_to_card(common, fw, len, num_blocks); + kfree(fw); release_firmware(fw_entry); return status; } -- cgit v0.10.2 From 098697dbad9070249eb07a0241c4001aa367bb89 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 29 Jul 2015 23:36:30 +0200 Subject: b43: fix extpa_gain check for 2GHz On the 2GHz and and on the 5GHZ band only the extpa_gain setting from the 5GHz band was checked. this patch makes it check the property from the correct band. Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 25d1cbd..b2f0d24 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) switch (phy->rev) { case 6: case 5: - if (sprom->fem.ghz5.extpa_gain == 3) + if (sprom->fem.ghz2.extpa_gain == 3) return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g; /* fall through */ case 4: -- cgit v0.10.2 From 7c62940165e9ae4004ce4e6b5117330bab94df68 Mon Sep 17 00:00:00 2001 From: Luis Felipe Dominguez Vega Date: Wed, 29 Jul 2015 21:11:20 -0500 Subject: rtlwifi: Fix NULL dereference when PCI driver used as an AP In commit 33511b157bbcebaef853cc1811992b664a2e5862 ("rtlwifi: add support to send beacon frame"), the mechanism for sending beacons was established. That patch works correctly for rtl8192cu, but there is a possibility of getting the following warnings in the PCI drivers: WARNING: CPU: 1 PID: 2439 at net/mac80211/driver-ops.h:12 ieee80211_bss_info_change_notify+0x179/0x1d0 [mac80211]() wlp5s0: Failed check-sdata-in-driver check, flags: 0x0 The warning is followed by a NULL pointer dereference as follows: BUG: unable to handle kernel NULL pointer dereference at 0000000000000006 IP: [] rtl_get_tcb_desc+0x5e/0x760 [rtlwifi] This problem was reported at http://thread.gmane.org/gmane.linux.kernel.wireless.general/138645, but no solution was found at that time. The problem was also reported at https://bugzilla.kernel.org/show_bug.cgi?id=9744 and this solution was developed and tested there. The USB driver works with a NULL final argument in the adapter_tx() callback; however, the PCI drivers need a struct rtl_tcb_desc in that position. Fixes: 33511b157bbc ("rtlwifi: add support to send beacon frame.") Signed-off-by: Luis Felipe Dominguez Vega Signed-off-by: Larry Finger Cc: Stable [3.19+] Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 3b3a88b..585d088 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct rtl_tcb_desc tcb_desc; - if (skb) - rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL); + if (skb) { + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc); + } } static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, -- cgit v0.10.2 From f6762cb2ca48e9052b5233c338fa254fa58d8981 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 7 Jul 2015 16:18:46 +0800 Subject: ceph: fix ceph_encode_locks_to_buffer() posix locks should be in ctx->flc_posix list Signed-off-by: Yan, Zheng Signed-off-by: Ilya Dryomov diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 4347039..6706bde 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -287,7 +287,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode, return 0; spin_lock(&ctx->flc_lock); - list_for_each_entry(lock, &ctx->flc_flock, fl_list) { + list_for_each_entry(lock, &ctx->flc_posix, fl_list) { ++seen_fcntl; if (seen_fcntl > num_fcntl_locks) { err = -ENOSPC; -- cgit v0.10.2 From fc927cd32feca2acefd90a4ac317fa4f0a2e5955 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 20 Jul 2015 09:50:58 +0800 Subject: ceph: always re-send cap flushes when MDS recovers commit e548e9b93d3e565e42b938a99804114565be1f81 makes the kclient only re-send cap flush once during MDS failover. If the kclient sends a cap flush after MDS enters reconnect stage but before MDS recovers. The kclient will skip re-sending the same cap flush when MDS recovers. This causes problem for newly created inode. The MDS handles cap flushes before replaying unsafe requests, so it's possible that MDS find corresponding inode is missing when handling cap flush. The fix is reverting to old behaviour: always re-send when MDS recovers Signed-off-by: Yan, Zheng Signed-off-by: Ilya Dryomov diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index dc10c9d..ddd5e94 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1506,7 +1506,6 @@ static int __mark_caps_flushing(struct inode *inode, swap(cf, ci->i_prealloc_cap_flush); cf->caps = flushing; - cf->kick = false; spin_lock(&mdsc->cap_dirty_lock); list_del_init(&ci->i_dirty_item); @@ -2123,8 +2122,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc, static int __kick_flushing_caps(struct ceph_mds_client *mdsc, struct ceph_mds_session *session, - struct ceph_inode_info *ci, - bool kick_all) + struct ceph_inode_info *ci) { struct inode *inode = &ci->vfs_inode; struct ceph_cap *cap; @@ -2150,9 +2148,7 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc, for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) { cf = rb_entry(n, struct ceph_cap_flush, i_node); - if (cf->tid < first_tid) - continue; - if (kick_all || cf->kick) + if (cf->tid >= first_tid) break; } if (!n) { @@ -2161,7 +2157,6 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc, } cf = rb_entry(n, struct ceph_cap_flush, i_node); - cf->kick = false; first_tid = cf->tid + 1; @@ -2181,8 +2176,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc, { struct ceph_inode_info *ci; struct ceph_cap *cap; - struct ceph_cap_flush *cf; - struct rb_node *n; dout("early_kick_flushing_caps mds%d\n", session->s_mds); list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) { @@ -2205,16 +2198,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc, if ((cap->issued & ci->i_flushing_caps) != ci->i_flushing_caps) { spin_unlock(&ci->i_ceph_lock); - if (!__kick_flushing_caps(mdsc, session, ci, true)) + if (!__kick_flushing_caps(mdsc, session, ci)) continue; spin_lock(&ci->i_ceph_lock); } - for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) { - cf = rb_entry(n, struct ceph_cap_flush, i_node); - cf->kick = true; - } - spin_unlock(&ci->i_ceph_lock); } } @@ -2228,7 +2216,7 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, dout("kick_flushing_caps mds%d\n", session->s_mds); list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) { - int delayed = __kick_flushing_caps(mdsc, session, ci, false); + int delayed = __kick_flushing_caps(mdsc, session, ci); if (delayed) { spin_lock(&ci->i_ceph_lock); __cap_delay_requeue(mdsc, ci); @@ -2261,7 +2249,7 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc, spin_unlock(&ci->i_ceph_lock); - delayed = __kick_flushing_caps(mdsc, session, ci, true); + delayed = __kick_flushing_caps(mdsc, session, ci); if (delayed) { spin_lock(&ci->i_ceph_lock); __cap_delay_requeue(mdsc, ci); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 860cc016..2f2460d 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -189,7 +189,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap) struct ceph_cap_flush { u64 tid; int caps; - bool kick; struct rb_node g_node; // global union { struct rb_node i_node; // inode -- cgit v0.10.2 From 2761713d35e370fd640b5781109f753066b746c4 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 16 Jul 2015 17:36:11 +0300 Subject: rbd: fix copyup completion race For write/discard obj_requests that involved a copyup method call, the opcode of the first op is CEPH_OSD_OP_CALL and the ->callback is rbd_img_obj_copyup_callback(). The latter frees copyup pages, sets ->xferred and delegates to rbd_img_obj_callback(), the "normal" image object callback, for reporting to block layer and putting refs. rbd_osd_req_callback() however treats CEPH_OSD_OP_CALL as a trivial op, which means obj_request is marked done in rbd_osd_trivial_callback(), *before* ->callback is invoked and rbd_img_obj_copyup_callback() has a chance to run. Marking obj_request done essentially means giving rbd_img_obj_callback() a license to end it at any moment, so if another obj_request from the same img_request is being completed concurrently, rbd_img_obj_end_request() may very well be called on such prematurally marked done request: handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() rbd_obj_request_complete() rbd_img_obj_copyup_callback() rbd_img_obj_callback() handle_reply() rbd_osd_req_callback() rbd_osd_trivial_callback() for_each_obj_request(obj_request->img_request) { rbd_img_obj_end_request(obj_request-1/2) rbd_img_obj_end_request(obj_request-2/2) <-- } Calling rbd_img_obj_end_request() on such a request leads to trouble, in particular because its ->xfferred is 0. We report 0 to the block layer with blk_update_request(), get back 1 for "this request has more data in flight" and then trip on rbd_assert(more ^ (which == img_request->obj_request_count)); with rhs (which == ...) being 1 because rbd_img_obj_end_request() has been called for both requests and lhs (more) being 1 because we haven't got a chance to set ->xfferred in rbd_img_obj_copyup_callback() yet. To fix this, leverage that rbd wants to call class methods in only two cases: one is a generic method call wrapper (obj_request is standalone) and the other is a copyup (obj_request is part of an img_request). So make a dedicated handler for CEPH_OSD_OP_CALL and directly invoke rbd_img_obj_copyup_callback() from it if obj_request is part of an img_request, similar to how CEPH_OSD_OP_READ handler invokes rbd_img_obj_request_read_callback(). Since rbd_img_obj_copyup_callback() is now being called from the OSD request callback (only), it is renamed to rbd_osd_copyup_callback(). Cc: Alex Elder Cc: stable@vger.kernel.org # 3.10+, needs backporting for < 3.18 Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d94529d..bc67a93 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -523,6 +523,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...) # define rbd_assert(expr) ((void) 0) #endif /* !RBD_DEBUG */ +static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request); static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request); static void rbd_img_parent_read(struct rbd_obj_request *obj_request); static void rbd_dev_remove_parent(struct rbd_device *rbd_dev); @@ -1818,6 +1819,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request) obj_request_done_set(obj_request); } +static void rbd_osd_call_callback(struct rbd_obj_request *obj_request) +{ + dout("%s: obj %p\n", __func__, obj_request); + + if (obj_request_img_data_test(obj_request)) + rbd_osd_copyup_callback(obj_request); + else + obj_request_done_set(obj_request); +} + static void rbd_osd_req_callback(struct ceph_osd_request *osd_req, struct ceph_msg *msg) { @@ -1866,6 +1877,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req, rbd_osd_discard_callback(obj_request); break; case CEPH_OSD_OP_CALL: + rbd_osd_call_callback(obj_request); + break; case CEPH_OSD_OP_NOTIFY_ACK: case CEPH_OSD_OP_WATCH: rbd_osd_trivial_callback(obj_request); @@ -2530,13 +2543,15 @@ out_unwind: } static void -rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request) +rbd_osd_copyup_callback(struct rbd_obj_request *obj_request) { struct rbd_img_request *img_request; struct rbd_device *rbd_dev; struct page **pages; u32 page_count; + dout("%s: obj %p\n", __func__, obj_request); + rbd_assert(obj_request->type == OBJ_REQUEST_BIO || obj_request->type == OBJ_REQUEST_NODATA); rbd_assert(obj_request_img_data_test(obj_request)); @@ -2563,9 +2578,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request) if (!obj_request->result) obj_request->xferred = obj_request->length; - /* Finish up with the normal image object callback */ - - rbd_img_obj_callback(obj_request); + obj_request_done_set(obj_request); } static void @@ -2650,7 +2663,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request) /* All set, send it off. */ - orig_request->callback = rbd_img_obj_copyup_callback; osdc = &rbd_dev->rbd_client->client->osdc; img_result = rbd_obj_request_submit(osdc, orig_request); if (!img_result) -- cgit v0.10.2 From 1f023297f7f77d434ecc221018d2e181eac0ae36 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:16:31 +0300 Subject: i2c: slave eeprom: clean up sysfs bin attribute read()/write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Note, on file size overflow read() now returns 0, and this is a correct and expected EOF notification according to POSIX. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 8223746..1da4496 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj struct eeprom_data *eeprom; unsigned long flags; - if (off + count > attr->size) - return -EFBIG; - eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); spin_lock_irqsave(&eeprom->buffer_lock, flags); @@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob struct eeprom_data *eeprom; unsigned long flags; - if (off + count > attr->size) - return -EFBIG; - eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); spin_lock_irqsave(&eeprom->buffer_lock, flags); -- cgit v0.10.2 From d12c0aaf3780c5b26b4ea9e795252381f586c063 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:51 +0300 Subject: misc: eeprom: at24: clean up at24_bin_write() The change removes redundant sysfs binary file boundary check, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 2d3db81..6ded3dc 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -438,9 +438,6 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj, { struct at24_data *at24; - if (unlikely(off >= attr->size)) - return -EFBIG; - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); return at24_write(at24, buf, off, count); } -- cgit v0.10.2 From 8b06260836ab47abbb5ea49d889660a0ed8adf90 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Wed, 8 Jul 2015 16:35:06 +0200 Subject: i2c: core: only use set_scl for bus recovery after calling prepare_recovery Using set_scl may be ineffective before calling the driver specific prepare_recovery callback, which might change into a test mode. So instead of setting SCL in i2c_generic_scl_recovery, move it to i2c_generic_recovery (after the optional prepare_recovery). Signed-off-by: Jan Luebbe Acked-by: Alexander Sverdlin Tested-by: Alexander Sverdlin Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e6d4935..8b64cf3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -567,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) if (bri->prepare_recovery) bri->prepare_recovery(adap); + bri->set_scl(adap, val); + ndelay(RECOVERY_NDELAY); + /* * By this time SCL is high, as we need to give 9 falling-rising edges */ @@ -597,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) int i2c_generic_scl_recovery(struct i2c_adapter *adap) { - adap->bus_recovery_info->set_scl(adap, 1); return i2c_generic_recovery(adap); } EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); -- cgit v0.10.2 From 828e66c0edf97bcb79b59b1ddd803a50629b3937 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Wed, 8 Jul 2015 16:35:27 +0200 Subject: i2c: omap: fix bus recovery setup At least on the AM335x, enabling OMAP_I2C_SYSTEST_ST_EN is not enough to allow direct access to the SCL and SDA pins. In addition to ST_EN, we need to set the TMODE to 0b11 (Loop back & SDA/SCL IO mode select). Also, as the reset values of SCL_O and SDA_O are 0 (which means "drive low level"), we need to set them to 1 (which means "high-impedance") to avoid unwanted changes on the pins. As a precaution, reset all these bits to their default values after recovery is complete. Signed-off-by: Jan Luebbe Tested-by: Alexander Sverdlin Reviewed-by: Grygorii Strashko Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d1c22e3..fc9bf7f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1247,7 +1247,14 @@ static void omap_i2c_prepare_recovery(struct i2c_adapter *adap) u32 reg; reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + /* enable test mode */ reg |= OMAP_I2C_SYSTEST_ST_EN; + /* select SDA/SCL IO mode */ + reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT; + /* set SCL to high-impedance state (reset value is 0) */ + reg |= OMAP_I2C_SYSTEST_SCL_O; + /* set SDA to high-impedance state (reset value is 0) */ + reg |= OMAP_I2C_SYSTEST_SDA_O; omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); } @@ -1257,7 +1264,11 @@ static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap) u32 reg; reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + /* restore reset values */ reg &= ~OMAP_I2C_SYSTEST_ST_EN; + reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK; + reg &= ~OMAP_I2C_SYSTEST_SCL_O; + reg &= ~OMAP_I2C_SYSTEST_SDA_O; omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); } -- cgit v0.10.2 From e952849a02524a247967bf7105f36fbb13cd00c2 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 28 Jul 2015 20:11:23 +0900 Subject: i2c: Fix typo in i2c-bfin-twi.c This patch fix some typos found in a printk message and MODULE_DESCRIPTION. Signed-off-by: Masanari Iida Acked-by: Sonic Zhang Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index af162b4..025686d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iface); - dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, " + dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, " "regs_base@%p\n", iface->regs_base); return 0; @@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init); module_exit(i2c_bfin_twi_exit); MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); -MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver"); +MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:i2c-bfin-twi"); -- cgit v0.10.2 From 3473f26592c1c365d376aee29433d7db75f14d1e Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 17 Jul 2015 21:40:28 +0100 Subject: ARM: 8405/1: VDSO: fix regression with toolchains lacking ld.bfd executable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Sourcery CodeBench Lite 2014.05 toolchain (gcc 4.8.3, binutils 2.24.51) has a GCC which implements -fuse-ld, and it doesn't include the gold linker, but it lacks an ld.bfd executable in its installation. This means that passing -fuse-ld=bfd fails with: VDSO arch/arm/vdso/vdso.so.raw collect2: fatal error: cannot find 'ld' Arguably this is a deficiency in the toolchain, but I suspect it's commonly used enough that it's worth accommodating: just use cc-ldoption (to cause a link attempt) instead of cc-option to test whether we can use -fuse-ld. So -fuse-ld=bfd won't be used with this toolchain, but the build will rightly succeed, just as it does for toolchains which don't implement -fuse-ld (and don't use gold as the default linker). Note: this will change the failure mode for a corner case I was trying to handle in d2b30cd4b722, where the toolchain defaults to the gold linker and the BFD linker is not found in PATH, from: VDSO arch/arm/vdso/vdso.so.raw collect2: fatal error: cannot find 'ld' i.e. the BFD linker is not found, to: OBJCOPY arch/arm/vdso/vdso.so BFD: arch/arm/vdso/vdso.so: Not enough room for program headers, try linking with -N that is, we fail to prevent gold from being used as the linker, and it produces an object that objcopy can't digest. Reported-by: Baruch Siach Tested-by: Baruch Siach Tested-by: Raphaël Poggi Fixes: d2b30cd4b722 ("ARM: 8384/1: VDSO: force use of BFD linker") Cc: stable@vger.kernel.org Signed-off-by: Nathan Lynch Signed-off-by: Russell King diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile index 9d259d9..1160434 100644 --- a/arch/arm/vdso/Makefile +++ b/arch/arm/vdso/Makefile @@ -14,7 +14,7 @@ VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 VDSO_LDFLAGS += -nostdlib -shared VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id) -VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd) +VDSO_LDFLAGS += $(call cc-ldoption, -fuse-ld=bfd) obj-$(CONFIG_VDSO) += vdso.o extra-$(CONFIG_VDSO) += vdso.lds -- cgit v0.10.2 From bf08f39e6088c52c6fc7cce2ef7fbbd7bf4692b9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:45 +0200 Subject: ASoC: Export OF module alias information in missing codec drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446..ab39de6 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1533,6 +1533,7 @@ static const struct of_device_id da9055_of_match[] = { { .compatible = "dlg,da9055-codec", }, { } }; +MODULE_DEVICE_TABLE(of, da9055_of_match); /* I2C codec control layer */ static struct i2c_driver da9055_i2c_driver = { diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index dac5beb..0617415 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -598,6 +598,7 @@ static const struct of_device_id wm8510_of_match[] = { { .compatible = "wlf,wm8510" }, { }, }; +MODULE_DEVICE_TABLE(of, wm8510_of_match); static const struct regmap_config wm8510_regmap = { .reg_bits = 7, diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 43ea8ae..483ec72 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -430,6 +430,7 @@ static const struct of_device_id wm8523_of_match[] = { { .compatible = "wlf,wm8523" }, { }, }; +MODULE_DEVICE_TABLE(of, wm8523_of_match); static const struct regmap_config wm8523_regmap = { .reg_bits = 8, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 759a792..a9f3900 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -916,6 +916,7 @@ static const struct of_device_id wm8580_of_match[] = { { .compatible = "wlf,wm8580" }, { }, }; +MODULE_DEVICE_TABLE(of, wm8580_of_match); static const struct regmap_config wm8580_regmap = { .reg_bits = 7, -- cgit v0.10.2 From 8fcd461db7c09337b6d2e22d25eb411123f379e3 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 30 Jul 2015 06:57:46 -0400 Subject: nfsd: do nfs4_check_fh in nfs4_check_file instead of nfs4_check_olstateid Currently, preprocess_stateid_op calls nfs4_check_olstateid which verifies that the open stateid corresponds to the current filehandle in the call by calling nfs4_check_fh. If the stateid is a NFS4_DELEG_STID however, then no such check is done. This could cause incorrect enforcement of permissions, because the nfsd_permission() call in nfs4_check_file uses current the current filehandle, but any subsequent IO operation will use the file descriptor in the stateid. Move the call to nfs4_check_fh into nfs4_check_file instead so that it can be done for all stateid types. Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org [bfields: moved fh check to avoid NULL deref in special stateid case] Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 61dfb33..9520271 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4396,9 +4396,9 @@ laundromat_main(struct work_struct *laundry) queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); } -static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) +static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) { - if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle)) + if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) return nfserr_bad_stateid; return nfs_ok; } @@ -4601,9 +4601,6 @@ nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags) { __be32 status; - status = nfs4_check_fh(fhp, ols); - if (status) - return status; status = nfsd4_check_openowner_confirmed(ols); if (status) return status; @@ -4690,6 +4687,9 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, status = nfserr_bad_stateid; break; } + if (status) + goto out; + status = nfs4_check_fh(fhp, s); done: if (!status && filpp) @@ -4798,7 +4798,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); if (status) return status; - return nfs4_check_fh(current_fh, stp); + return nfs4_check_fh(current_fh, &stp->st_stid); } /* -- cgit v0.10.2 From 40c3ef9d2f14cce91dbd6ae9c9ccf6210d8c5df7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 27 Jul 2015 10:27:21 -0700 Subject: staging: comedi: das1800: add missing break in switch Commit 06ad6bd8 "staging: comedi: das1800: cleanup das1800_probe()" Accidently removed the 'break' statement for case 0x8 of the switch. Add it back. Reported-by: coverity (CID 1309550) Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index bfa4262..94078118 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -1266,6 +1266,7 @@ static const struct das1800_board *das1800_probe(struct comedi_device *dev) if (index == das1801hc || index == das1802hc) return board; index = das1801hc; + break; default: dev_err(dev->class_dev, "Board model: probe returned 0x%x (unknown, please report)\n", -- cgit v0.10.2 From e3311469734093724b10c2a81c1193197db03b78 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 17:30:48 +0300 Subject: i2c: fix leaked device refcount on of_find_i2c_* error path If of_find_i2c_device_by_node() or of_find_i2c_adapter_by_node() find a device by node, but its type does not match, a reference to that device is still held. This change fixes the problem. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8b64cf3..c83e4d1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1340,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data) struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) { struct device *dev; + struct i2c_client *client; - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); + dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); if (!dev) return NULL; - return i2c_verify_client(dev); + client = i2c_verify_client(dev); + if (!client) + put_device(dev); + + return client; } EXPORT_SYMBOL(of_find_i2c_device_by_node); @@ -1354,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node); struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) { struct device *dev; + struct i2c_adapter *adapter; - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); + dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); if (!dev) return NULL; - return i2c_verify_adapter(dev); + adapter = i2c_verify_adapter(dev); + if (!adapter) + put_device(dev); + + return adapter; } EXPORT_SYMBOL(of_find_i2c_adapter_by_node); #else -- cgit v0.10.2 From 7167bf8b7f3f19eeea4602ccc39f26a26a636d8e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Jul 2015 10:01:40 +0200 Subject: phy-sun4i-usb: Add missing EXPORT_SYMBOL_GPL for sun4i_usb_phy_set_squelch_detect sun4i_usb_phy_set_squelch_detect is used by other code, which may be built as a module, so it should be exported. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e17c539..2dad7e8 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -212,6 +212,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled) sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2); } +EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect); static struct phy_ops sun4i_usb_phy_ops = { .init = sun4i_usb_phy_init, -- cgit v0.10.2 From c934b3612747bde6c81cf10c2bbde956c6690aec Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Jul 2015 16:47:22 +0300 Subject: phy: ti-pipe3: i783 workaround for SATA lockup after dpll unlock/relock SATA_PLL_SOFT_RESET bit of CTRL_CORE_SMA_SW_0 must be toggled between a SATA DPLL unlock and re-lock to prevent SATA lockup. Introduce a new DT parameter 'syscon-pllreset' to provide the syscon regmap access to this register which sits in the control module. If the register is not provided we fallback to the old behaviour i.e. SATA DPLL refclk will not be disabled and we prevent SoC low power states. Signed-off-by: Roger Quadros Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 305e3df..9cf9446 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -82,6 +82,9 @@ Optional properties: - id: If there are multiple instance of the same type, in order to differentiate between each instance "id" can be used (e.g., multi-lane PCIe PHY). If "id" is not provided, it is set to default value of '1'. + - syscon-pllreset: Handle to system control region that contains the + CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0 + register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy. This is usually a subnode of ocp2scp to which it is connected. @@ -100,3 +103,16 @@ usb3phy@4a084400 { "sysclk", "refclk"; }; + +sata_phy: phy@4A096000 { + compatible = "ti,phy-pipe3-sata"; + reg = <0x4A096000 0x80>, /* phy_rx */ + <0x4A096400 0x64>, /* phy_tx */ + <0x4A096800 0x40>; /* pll_ctrl */ + reg-names = "phy_rx", "phy_tx", "pll_ctrl"; + ctrl-module = <&omap_control_sata>; + clocks = <&sys_clkin1>, <&sata_ref_clk>; + clock-names = "sysclk", "refclk"; + syscon-pllreset = <&scm_conf 0x3fc>; + #phy-cells = <0>; +}; diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 3510b81..08020dc 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #define PLL_STATUS 0x00000004 #define PLL_GO 0x00000008 @@ -52,6 +54,8 @@ #define PLL_LOCK 0x2 #define PLL_IDLE 0x1 +#define SATA_PLL_SOFT_RESET BIT(18) + /* * This is an Empirical value that works, need to confirm the actual * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status @@ -82,6 +86,9 @@ struct ti_pipe3 { struct clk *refclk; struct clk *div_clk; struct pipe3_dpll_map *dpll_map; + struct regmap *dpll_reset_syscon; /* ctrl. reg. acces */ + unsigned int dpll_reset_reg; /* reg. index within syscon */ + bool sata_refclk_enabled; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -249,8 +256,11 @@ static int ti_pipe3_exit(struct phy *x) u32 val; unsigned long timeout; - /* SATA DPLL can't be powered down due to Errata i783 */ - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) + /* If dpll_reset_syscon is not present we wont power down SATA DPLL + * due to Errata i783 + */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") && + !phy->dpll_reset_syscon) return 0; /* PCIe doesn't have internal DPLL */ @@ -276,6 +286,14 @@ static int ti_pipe3_exit(struct phy *x) } } + /* i783: SATA needs control bit toggle after PLL unlock */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) { + regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, + SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); + regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, + SATA_PLL_SOFT_RESET, 0); + } + ti_pipe3_disable_clocks(phy); return 0; @@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev) } } else { phy->wkupclk = ERR_PTR(-ENODEV); + phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, + "syscon-pllreset"); + if (IS_ERR(phy->dpll_reset_syscon)) { + dev_info(&pdev->dev, + "can't get syscon-pllreset, sata dpll won't idle\n"); + phy->dpll_reset_syscon = NULL; + } else { + if (of_property_read_u32_index(node, + "syscon-pllreset", 1, + &phy->dpll_reset_reg)) { + dev_err(&pdev->dev, + "couldn't get pllreset reg. offset\n"); + return -EINVAL; + } + } } if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { @@ -402,10 +435,16 @@ static int ti_pipe3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); pm_runtime_enable(phy->dev); - /* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */ - if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) - if (!IS_ERR(phy->refclk)) + + /* + * Prevent auto-disable of refclk for SATA PHY due to Errata i783 + */ + if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) { + if (!IS_ERR(phy->refclk)) { clk_prepare_enable(phy->refclk); + phy->sata_refclk_enabled = true; + } + } generic_phy = devm_phy_create(phy->dev, NULL, &ops); if (IS_ERR(generic_phy)) @@ -472,8 +511,18 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) { if (!IS_ERR(phy->wkupclk)) clk_disable_unprepare(phy->wkupclk); - if (!IS_ERR(phy->refclk)) + if (!IS_ERR(phy->refclk)) { clk_disable_unprepare(phy->refclk); + /* + * SATA refclk needs an additional disable as we left it + * on in probe to avoid Errata i783 + */ + if (phy->sata_refclk_enabled) { + clk_disable_unprepare(phy->refclk); + phy->sata_refclk_enabled = false; + } + } + if (!IS_ERR(phy->div_clk)) clk_disable_unprepare(phy->div_clk); } -- cgit v0.10.2 From 1ebd47efa4e17391dfac8caa349c6a8d35f996d1 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 2 Aug 2015 19:29:16 +0200 Subject: rocker: free netdevice during netdevice removal When removing a port's netdevice in 'rocker_remove_ports', we should also free the allocated 'net_device' structure. Do that by calling 'free_netdev' after unregistering it. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Fixes: 4b8ac9660af ("rocker: introduce rocker switch driver") Acked-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2d8578cade..2e7f9a2 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4821,6 +4821,7 @@ static void rocker_remove_ports(const struct rocker *rocker) rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, ROCKER_OP_FLAG_REMOVE); unregister_netdev(rocker_port->dev); + free_netdev(rocker_port->dev); } kfree(rocker->ports); } -- cgit v0.10.2 From 3d0e0af40672a0bf16ca0f0591165535138c1f30 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 31 Jul 2015 17:53:39 -0700 Subject: fq_codel: explicitly reset flows in ->reset() Alex reported the following crash when using fq_codel with htb: crash> bt PID: 630839 TASK: ffff8823c990d280 CPU: 14 COMMAND: "tc" [... snip ...] #8 [ffff8820ceec17a0] page_fault at ffffffff8160a8c2 [exception RIP: htb_qlen_notify+24] RIP: ffffffffa0841718 RSP: ffff8820ceec1858 RFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff88241747b400 RDX: ffff88241747b408 RSI: 0000000000000000 RDI: ffff8811fb27d000 RBP: ffff8820ceec1868 R8: ffff88120cdeff24 R9: ffff88120cdeff30 R10: 0000000000000bd4 R11: ffffffffa0840919 R12: ffffffffa0843340 R13: 0000000000000000 R14: 0000000000000001 R15: ffff8808dae5c2e8 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #9 [...] qdisc_tree_decrease_qlen at ffffffff81565375 #10 [...] fq_codel_dequeue at ffffffffa084e0a0 [sch_fq_codel] #11 [...] fq_codel_reset at ffffffffa084e2f8 [sch_fq_codel] #12 [...] qdisc_destroy at ffffffff81560d2d #13 [...] htb_destroy_class at ffffffffa08408f8 [sch_htb] #14 [...] htb_put at ffffffffa084095c [sch_htb] #15 [...] tc_ctl_tclass at ffffffff815645a3 #16 [...] rtnetlink_rcv_msg at ffffffff81552cb0 [... snip ...] As Jamal pointed out, there is actually no need to call dequeue to purge the queued skb's in reset, data structures can be just reset explicitly. Therefore, we reset everything except config's and stats, so that we would have a fresh start after device flipping. Fixes: 4b549a2ef4be ("fq_codel: Fair Queue Codel AQM") Reported-by: Alex Gartrell Cc: Alex Gartrell Cc: Jamal Hadi Salim Signed-off-by: Eric Dumazet [xiyou.wangcong@gmail.com: added codel_vars_init() and qdisc_qstats_backlog_dec()] Signed-off-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 21ca33c..a9ba030 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -288,10 +288,26 @@ begin: static void fq_codel_reset(struct Qdisc *sch) { - struct sk_buff *skb; + struct fq_codel_sched_data *q = qdisc_priv(sch); + int i; - while ((skb = fq_codel_dequeue(sch)) != NULL) - kfree_skb(skb); + INIT_LIST_HEAD(&q->new_flows); + INIT_LIST_HEAD(&q->old_flows); + for (i = 0; i < q->flows_cnt; i++) { + struct fq_codel_flow *flow = q->flows + i; + + while (flow->head) { + struct sk_buff *skb = dequeue_head(flow); + + qdisc_qstats_backlog_dec(sch, skb); + kfree_skb(skb); + } + + INIT_LIST_HEAD(&flow->flowchain); + codel_vars_init(&flow->cvars); + } + memset(q->backlogs, 0, q->flows_cnt * sizeof(u32)); + sch->q.qlen = 0; } static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { -- cgit v0.10.2 From 423f04d63cf421ea436bcc5be02543d549ce4b28 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 27 Jul 2015 11:48:52 +1000 Subject: md/raid1: extend spinlock to protect raid1_end_read_request against inconsistencies raid1_end_read_request() assumes that the In_sync bits are consistent with the ->degaded count. raid1_spare_active updates the In_sync bit before the ->degraded count and so exposes an inconsistency, as does error() So extend the spinlock in raid1_spare_active() and error() to hide those inconsistencies. This should probably be part of Commit: 34cab6f42003 ("md/raid1: fix test for 'was read error from last working device'.") as it addresses the same issue. It fixes the same bug and should go to -stable for same reasons. Fixes: 76073054c95b ("md/raid1: clean up read_balance.") Cc: stable@vger.kernel.org (v3.0+) Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 94f5b55..967a4ed 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1476,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) { char b[BDEVNAME_SIZE]; struct r1conf *conf = mddev->private; + unsigned long flags; /* * If it is not operational, then we have already marked it as dead @@ -1495,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) return; } set_bit(Blocked, &rdev->flags); + spin_lock_irqsave(&conf->device_lock, flags); if (test_and_clear_bit(In_sync, &rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded++; set_bit(Faulty, &rdev->flags); - spin_unlock_irqrestore(&conf->device_lock, flags); } else set_bit(Faulty, &rdev->flags); + spin_unlock_irqrestore(&conf->device_lock, flags); /* * if recovery is running, make sure it aborts. */ @@ -1568,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev) * Find all failed disks within the RAID1 configuration * and mark them readable. * Called under mddev lock, so rcu protection not needed. + * device_lock used to avoid races with raid1_end_read_request + * which expects 'In_sync' flags and ->degraded to be consistent. */ + spin_lock_irqsave(&conf->device_lock, flags); for (i = 0; i < conf->raid_disks; i++) { struct md_rdev *rdev = conf->mirrors[i].rdev; struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; @@ -1599,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } } - spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded -= count; spin_unlock_irqrestore(&conf->device_lock, flags); -- cgit v0.10.2 From 528464eaa46ae1bd319882e4dd3495802e55b8c4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 23 Jul 2015 14:32:32 +0530 Subject: thermal: remove dangling 'weight_attr' device file This file isn't getting removed while we unbind a device from thermal zone. And this causes following messages when the device is registered again: WARNING: CPU: 0 PID: 2228 at /home/viresh/linux/fs/sysfs/dir.c:31 sysfs_warn_dup+0x60/0x70() sysfs: cannot create duplicate filename '/devices/virtual/thermal/thermal_zone0/cdev0_weight' Modules linked in: cpufreq_dt(+) [last unloaded: cpufreq_dt] CPU: 0 PID: 2228 Comm: insmod Not tainted 4.2.0-rc3-00059-g44fffd9473eb #272 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x84/0xc4) [] (dump_stack) from [] (warn_slowpath_common+0x80/0xb0) [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt) from [] (sysfs_warn_dup+0x60/0x70) [] (sysfs_warn_dup) from [] (sysfs_add_file_mode_ns+0x13c/0x190) [] (sysfs_add_file_mode_ns) from [] (sysfs_create_file_ns+0x3c/0x48) [] (sysfs_create_file_ns) from [] (thermal_zone_bind_cooling_device+0x260/0x358) [] (thermal_zone_bind_cooling_device) from [] (of_thermal_bind+0x88/0xb4) [] (of_thermal_bind) from [] (__thermal_cooling_device_register+0x17c/0x2e0) [] (__thermal_cooling_device_register) from [] (__cpufreq_cooling_register+0x3a0/0x51c) [] (__cpufreq_cooling_register) from [] (cpufreq_ready+0x44/0x88 [cpufreq_dt]) [] (cpufreq_ready [cpufreq_dt]) from [] (cpufreq_add_dev+0x4a0/0x7dc) [] (cpufreq_add_dev) from [] (subsys_interface_register+0x94/0xd8) [] (subsys_interface_register) from [] (cpufreq_register_driver+0x10c/0x1f0) [] (cpufreq_register_driver) from [] (dt_cpufreq_probe+0x60/0x8c [cpufreq_dt]) [] (dt_cpufreq_probe [cpufreq_dt]) from [] (platform_drv_probe+0x44/0xa4) [] (platform_drv_probe) from [] (driver_probe_device+0x174/0x2b4) [] (driver_probe_device) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x19c/0x214) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (do_one_initcall+0x8c/0x1d4) [] (do_one_initcall) from [] (do_init_module+0x5c/0x1b8) [] (do_init_module) from [] (load_module+0xd34/0xed8) [] (load_module) from [] (SyS_init_module+0xd0/0x120) [] (SyS_init_module) from [] (ret_fast_syscall+0x0/0x3c) ---[ end trace 3be0e7b7dc6e3c4f ]--- Fixes: db91651311c8 ("thermal: export weight to sysfs") Acked-by: Javi Merino Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 04659bf..4ca211b 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1333,6 +1333,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz, return -ENODEV; unbind: + device_remove_file(&tz->device, &pos->weight_attr); device_remove_file(&tz->device, &pos->attr); sysfs_remove_link(&tz->device.kobj, pos->name); release_idr(&tz->idr, &tz->lock, pos->id); -- cgit v0.10.2 From d5f831090191fa26a539e12456af64547ab11dde Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Fri, 3 Jul 2015 10:24:33 +0100 Subject: thermal: power_allocator: trace the real requested power The power allocator governor uses ftrace to output a bunch of internal data for debugging and tuning. Currently, the requested power it outputs is the "weighted" requested power, that is, what each cooling device has requested multiplied by the cooling device weight. It is more useful to trace the real request, without any weight being applied. This commit only affects the data traced, there is no functional change. Cc: Zhang Rui Cc: Eduardo Valentin Signed-off-by: Javi Merino Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index 4672250..63a448f 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -229,7 +229,8 @@ static int allocate_power(struct thermal_zone_device *tz, struct thermal_instance *instance; struct power_allocator_params *params = tz->governor_data; u32 *req_power, *max_power, *granted_power, *extra_actor_power; - u32 total_req_power, max_allocatable_power; + u32 *weighted_req_power; + u32 total_req_power, max_allocatable_power, total_weighted_req_power; u32 total_granted_power, power_range; int i, num_actors, total_weight, ret = 0; int trip_max_desired_temperature = params->trip_max_desired_temperature; @@ -247,16 +248,17 @@ static int allocate_power(struct thermal_zone_device *tz, } /* - * We need to allocate three arrays of the same size: - * req_power, max_power and granted_power. They are going to - * be needed until this function returns. Allocate them all - * in one go to simplify the allocation and deallocation - * logic. + * We need to allocate five arrays of the same size: + * req_power, max_power, granted_power, extra_actor_power and + * weighted_req_power. They are going to be needed until this + * function returns. Allocate them all in one go to simplify + * the allocation and deallocation logic. */ BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power)); BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power)); BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power)); - req_power = devm_kcalloc(&tz->device, num_actors * 4, + BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power)); + req_power = devm_kcalloc(&tz->device, num_actors * 5, sizeof(*req_power), GFP_KERNEL); if (!req_power) { ret = -ENOMEM; @@ -266,8 +268,10 @@ static int allocate_power(struct thermal_zone_device *tz, max_power = &req_power[num_actors]; granted_power = &req_power[2 * num_actors]; extra_actor_power = &req_power[3 * num_actors]; + weighted_req_power = &req_power[4 * num_actors]; i = 0; + total_weighted_req_power = 0; total_req_power = 0; max_allocatable_power = 0; @@ -289,13 +293,14 @@ static int allocate_power(struct thermal_zone_device *tz, else weight = instance->weight; - req_power[i] = frac_to_int(weight * req_power[i]); + weighted_req_power[i] = frac_to_int(weight * req_power[i]); if (power_actor_get_max_power(cdev, tz, &max_power[i])) continue; total_req_power += req_power[i]; max_allocatable_power += max_power[i]; + total_weighted_req_power += weighted_req_power[i]; i++; } @@ -303,8 +308,9 @@ static int allocate_power(struct thermal_zone_device *tz, power_range = pid_controller(tz, current_temp, control_temp, max_allocatable_power); - divvy_up_power(req_power, max_power, num_actors, total_req_power, - power_range, granted_power, extra_actor_power); + divvy_up_power(weighted_req_power, max_power, num_actors, + total_weighted_req_power, power_range, granted_power, + extra_actor_power); total_granted_power = 0; i = 0; -- cgit v0.10.2 From 5f09a5cbd14ae16e93866040fa44d930ff885650 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 8 Jun 2015 10:35:49 +0900 Subject: thermal: exynos: Disable the regulator on probe failure During probe the regulator (if present) was enabled but not disabled in case of failure. So an unsuccessful probe lead to enabling the regulator which was actually not needed because the device was not enabled. Additionally each deferred probe lead to increase of regulator enable count so it would not be effectively disabled during removal of the device. Test HW: Exynos4412 - Trats2 board Signed-off-by: Krzysztof Kozlowski Fixes: 498d22f616f6 ("thermal: exynos: Support for TMU regulator defined at device tree") Cc: Reviewed-by: Javier Martinez Canillas Signed-off-by: Lukasz Majewski Tested-by: Lukasz Majewski Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 531f4b17..13c3ace 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1392,6 +1392,8 @@ err_clk_sec: if (!IS_ERR(data->clk_sec)) clk_unprepare(data->clk_sec); err_sensor: + if (!IS_ERR_OR_NULL(data->regulator)) + regulator_disable(data->regulator); thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); return ret; -- cgit v0.10.2 From f87e6bd3f7401ee3c04248d8ea2dc32883a1f8fb Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 2 Jul 2015 15:40:00 +0900 Subject: thermal: exynos: Add the dependency of CONFIG_THERMAL_OF instead of CONFIG_OF The exynos thermal driver use the of_thermal_*() API to parse the basic data for thermal management from devicetree file. So, if CONFIG_EXYNOS_THERMAL is selected without CONFIG_THERMAL_OF, kernel can build it without any problem. But, exynos thermal driver is not working with following error log. This patch add the dependency of CONFIG_THERMAL_OF instead of CONFIG_OF. [ 1.458644] get_th_reg: Cannot get trip points from of-thermal.c! [ 1.459096] get_th_reg: Cannot get trip points from of-thermal.c! [ 1.465211] exynos4412_tmu_initialize: No CRITICAL trip point defined at of-thermal.c! Cc: Zhang Rui Cc: Eduardo Valentin Cc: Lukasz Majewski Signed-off-by: Chanwoo Choi Signed-off-by: Lukasz Majewski Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index c8e35c1..e0da386 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig @@ -1,6 +1,6 @@ config EXYNOS_THERMAL tristate "Exynos thermal management unit driver" - depends on OF + depends on THERMAL_OF help If you say yes here you get support for the TMU (Thermal Management Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises -- cgit v0.10.2 From 3c19d237dd8148926e49259e495ee41dddd1f09c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 2 Jul 2015 15:40:01 +0900 Subject: thermal: exynos: Remove unused code related to platform_data on probe() This patch removes the unused code related to struct exynos_tmu_platform_data because exynos_tmu_probe() don't handle the struct exynos_tmu_platform_data *pdata. Test HW: Exynos4412 - Trats2 board Cc: Zhang Rui Cc: Eduardo Valentin Cc: Lukasz Majewski Signed-off-by: Chanwoo Choi Signed-off-by: Lukasz Majewski Tested-by: Lukasz Majewski Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 13c3ace..c96ff10 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1296,7 +1296,6 @@ static struct thermal_zone_of_device_ops exynos_sensor_ops = { static int exynos_tmu_probe(struct platform_device *pdev) { - struct exynos_tmu_platform_data *pdata; struct exynos_tmu_data *data; int ret; @@ -1318,8 +1317,6 @@ static int exynos_tmu_probe(struct platform_device *pdev) if (ret) goto err_sensor; - pdata = data->pdata; - INIT_WORK(&data->irq_work, exynos_tmu_work); data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); -- cgit v0.10.2 From b6878d9e03043695dbf3fa1caa6dfc09db225b16 Mon Sep 17 00:00:00 2001 From: Benjamin Randazzo Date: Sat, 25 Jul 2015 16:36:50 +0200 Subject: md: use kzalloc() when bitmap is disabled In drivers/md/md.c get_bitmap_file() uses kmalloc() for creating a mdu_bitmap_file_t called "file". 5769 file = kmalloc(sizeof(*file), GFP_NOIO); 5770 if (!file) 5771 return -ENOMEM; This structure is copied to user space at the end of the function. 5786 if (err == 0 && 5787 copy_to_user(arg, file, sizeof(*file))) 5788 err = -EFAULT But if bitmap is disabled only the first byte of "file" is initialized with zero, so it's possible to read some bytes (up to 4095) of kernel space memory from user space. This is an information leak. 5775 /* bitmap disabled, zero the first byte and copy out */ 5776 if (!mddev->bitmap_info.file) 5777 file->pathname[0] = '\0'; Signed-off-by: Benjamin Randazzo Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 0c2a4e8..e25f00f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5759,7 +5759,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg) char *ptr; int err; - file = kmalloc(sizeof(*file), GFP_NOIO); + file = kzalloc(sizeof(*file), GFP_NOIO); if (!file) return -ENOMEM; -- cgit v0.10.2 From 9c395170a559d3b23dad100b01fc4a89d661c698 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 24 Jul 2015 12:11:46 -0700 Subject: target: REPORT LUNS should return LUN 0 even for dynamic ACLs If an initiator doesn't have any real LUNs assigned, we should report LUN 0 and a LUN list length of 1. Some versions of Solaris at least go beserk if we report a LUN list length of 0. Signed-off-by: Roland Dreier Cc: # v3.1+ Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index b5ba1ec..556ea1b 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1221,11 +1221,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) * coming via a target_core_mod PASSTHROUGH op, and not through * a $FABRIC_MOD. In that case, report LUN=0 only. */ - if (!sess) { - int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); - lun_count = 1; + if (!sess) goto done; - } + nacl = sess->se_node_acl; rcu_read_lock(); @@ -1248,6 +1246,14 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) * See SPC3 r07, page 159. */ done: + /* + * If no LUNs are accessible, report virtual LUN 0. + */ + if (lun_count == 0) { + int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); + lun_count = 1; + } + lun_count *= 8; buf[0] = ((lun_count >> 24) & 0xff); buf[1] = ((lun_count >> 16) & 0xff); -- cgit v0.10.2 From 49895bcc7e566ba455eb2996607d6fbd3447ce16 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Aug 2015 17:09:57 +1000 Subject: md/raid5: don't let shrink_slab shrink too far. I have a report of drop_one_stripe() called from raid5_cache_scan() apparently finding ->max_nr_stripes == 0. This should not be allowed. So add a test to keep max_nr_stripes above min_nr_stripes. Also use a 'mask' rather than a 'mod' in drop_one_stripe to ensure 'hash' is valid even if max_nr_stripes does reach zero. Fixes: edbe83ab4c27 ("md/raid5: allow the stripe_cache to grow and shrink.") Cc: stable@vger.kernel.org (4.1 - please release with 2d5b569b665) Reported-by: Tomas Papan Signed-off-by: NeilBrown diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 643d217..f757023 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2256,7 +2256,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) static int drop_one_stripe(struct r5conf *conf) { struct stripe_head *sh; - int hash = (conf->max_nr_stripes - 1) % NR_STRIPE_HASH_LOCKS; + int hash = (conf->max_nr_stripes - 1) & STRIPE_HASH_LOCKS_MASK; spin_lock_irq(conf->hash_locks + hash); sh = get_free_stripe(conf, hash); @@ -6388,7 +6388,8 @@ static unsigned long raid5_cache_scan(struct shrinker *shrink, if (mutex_trylock(&conf->cache_size_mutex)) { ret= 0; - while (ret < sc->nr_to_scan) { + while (ret < sc->nr_to_scan && + conf->max_nr_stripes > conf->min_nr_stripes) { if (drop_one_stripe(conf) == 0) { ret = SHRINK_STOP; break; -- cgit v0.10.2 From 9b2b6f7f357d9a2473017295bb26ff907e149d34 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 19 Jul 2015 23:27:50 +0200 Subject: CPUFREQ: Loongson2: Fix broken build due to incorrect include. 71eeedcf51544831ae356a773814401143ed32d4 (MIPS: Lemote 2F: Fix build caused by recent mass rename.) only fixed one instance of this issue in arch/mips but missed a 2nd one in drivers/cpufreq/loongson2_cpufreq.c. [ralf@linux-mips.org: dropped the one segment for the already fixed instance and changed the other avoiding an include without a / because that's generally is a bad idea.] Signed-off-by: Ralf Baechle Acked-by: Viresh Kumar Patchwork: https://patchwork.linux-mips.org/patch/10659/ diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index e362860..cd593c1 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -20,7 +20,7 @@ #include #include -#include +#include static uint nowait; -- cgit v0.10.2 From d3557d96163d7d8250549a438232c5dd62d96959 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 19 Jul 2015 14:42:49 +0200 Subject: MIPS: Fix build with CONFIG_OF=y for non OF-enabled targets Commit 01306aeadd75 ("MIPS: prepare for user enabling of CONFIG_OF") changed the guards in asm/prom.h from CONFIG_OF to CONFIG_USE_OF, but missed the actual function declarations in kernel/prom.c, which have additional dependencies. Fixes the following build error: CC arch/mips/kernel/prom.o arch/mips/kernel/prom.c: In function '__dt_setup_arch': arch/mips/kernel/prom.c:54:2: error: implicit declaration of function 'early_init_dt_scan' [-Werror=implicit-function-declaration] if (!early_init_dt_scan(bph)) ^ Fixes: 01306aeadd75 ("MIPS: prepare for user enabling of CONFIG_OF") Signed-off-by: Jonas Gorski Acked-by: Rob Herring Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Grant Likely Patchwork: https://patchwork.linux-mips.org/patch/10741/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index b130033..5fcec30 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -38,7 +38,7 @@ char *mips_get_machine_name(void) return mips_machine_name; } -#ifdef CONFIG_OF +#ifdef CONFIG_USE_OF void __init early_init_dt_add_memory_arch(u64 base, u64 size) { return add_memory_region(base, size, BOOT_MEM_RAM); -- cgit v0.10.2 From 1d62d737555e1378eb62a8bba26644f7d97139d2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 19 Jul 2015 00:38:41 +0200 Subject: MIPS: Fix sched_getaffinity with MT FPAFF enabled p->thread.user_cpus_allowed is zero-initialized and is only filled on the first sched_setaffinity call. To avoid adding overhead in the task initialization codepath, simply OR the returned mask in sched_getaffinity with p->cpus_allowed. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10740/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 3e4491a..789d7bf 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr) { unsigned int real_len; - cpumask_t mask; + cpumask_t allowed, mask; int retval; struct task_struct *p; @@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, if (retval) goto out_unlock; - cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask); + cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed); + cpumask_and(&mask, &allowed, cpu_active_mask); out_unlock: read_unlock(&tasklist_lock); -- cgit v0.10.2 From 531a6d599f4304156236ebdd531aaa80be61868d Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Tue, 23 Jun 2015 12:02:00 +0100 Subject: MIPS: unaligned: Fix build error on big endian R6 kernels Commit eeb538950367 ("MIPS: unaligned: Prevent EVA instructions on kernel unaligned accesses") renamed the Load* and Store* defines in unaligned.c to _Load* and _Store* as part of its fix. One define was missed out which causes big endian R6 kernels to fail to build. arch/mips/kernel/unaligned.c:880:35: error: implicit declaration of function '_StoreDW' #define StoreDW(addr, value, res) _StoreDW(addr, value, res) ^ Signed-off-by: James Cowgill Fixes: eeb538950367 ("MIPS: unaligned: Prevent EVA instructions on kernel unaligned accesses") Cc: Markos Chandras Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10575/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index af84bef..eb3efd1 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -438,7 +438,7 @@ do { \ : "memory"); \ } while(0) -#define StoreDW(addr, value, res) \ +#define _StoreDW(addr, value, res) \ do { \ __asm__ __volatile__ ( \ ".set\tpush\n\t" \ -- cgit v0.10.2 From 106eccb4d20f35ebc58ff2286c170d9e79c5ff68 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Jul 2015 15:54:41 +0100 Subject: MIPS: Malta: Don't reinitialise RTC On Malta, since commit a87ea88d8f6c ("MIPS: Malta: initialise the RTC at boot"), the RTC is reinitialised and forced into binary coded decimal (BCD) mode during init, even if the bootloader has already initialised it, and may even have already put it into binary mode (as YAMON does). This corrupts the current time, can result in the RTC seconds being an invalid BCD (e.g. 0x1a..0x1f) for up to 6 seconds, as well as confusing YAMON for a while after reset, enough for it to report timeouts when attempting to load from TFTP (it actually uses the RTC in that code). Therefore only initialise the RTC to the extent that is necessary so that Linux avoids interfering with the bootloader setup, while also allowing it to estimate the CPU frequency without hanging, without a bootloader necessarily having done anything with the RTC (for example when the kernel is loaded via EJTAG). The divider control is configured for a 32KHZ reference clock if necessary, and the SET bit of the RTC_CONTROL register is cleared if necessary without changing any other bits (this bit will be set when coming out of reset if the battery has been disconnected). Fixes: a87ea88d8f6c ("MIPS: Malta: initialise the RTC at boot") Signed-off-by: James Hogan Reviewed-by: Paul Burton Cc: Ralf Baechle Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: # 3.14+ Patchwork: https://patchwork.linux-mips.org/patch/10739/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 5625b19..c1dc730 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -171,14 +171,17 @@ unsigned int get_c0_compare_int(void) static void __init init_rtc(void) { - /* stop the clock whilst setting it up */ - CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL); + unsigned char freq, ctrl; - /* 32KHz time base */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); + /* Set 32KHz time base if not already set */ + freq = CMOS_READ(RTC_FREQ_SELECT); + if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ) + CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); - /* start the clock */ - CMOS_WRITE(RTC_24H, RTC_CONTROL); + /* Ensure SET bit is clear so RTC can run */ + ctrl = CMOS_READ(RTC_CONTROL); + if (ctrl & RTC_SET) + CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL); } void __init plat_time_init(void) -- cgit v0.10.2 From e070dab73523bcbf2409ba8b5c342d53bccc0959 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 23 Jul 2015 11:10:38 +0200 Subject: MIPS: Handle page faults of executable but unreadable pages correctly. Without this we end taking execeptions in an endless loop hanging the thread. Signed-off-by: Ralf Baechle diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 36c0f26..852a41c 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -133,7 +133,8 @@ good_area: #endif goto bad_area; } - if (!(vma->vm_flags & VM_READ)) { + if (!(vma->vm_flags & VM_READ) && + exception_epc(regs) != address) { #if 0 pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n", raw_smp_processor_id(), -- cgit v0.10.2 From 55fdcb2d56b6edc027657fde9da0c4f224d32303 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 23 Jul 2015 11:10:59 +0200 Subject: MIPS: Partially disable RIXI support. Execution of break instruction, trap instructions, emulation of unaligned loads or floating point instructions - anything that tries to read the instruction's opcode from userspace - needs read access to a page. RIXI (Read Inhibit / Execute Inhibit) support however allows the creation of pags that are executable but not readable. On such a mapping the attempted load of the opcode by the kernel is going to cause an endless loop of page faults. The quick workaround for this is to disable the combinations that the kernel currently isn't able to handle which are executable mappings. Signed-off-by: Ralf Baechle diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 77d96db..aab218c 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -160,18 +160,18 @@ static inline void setup_protection_map(void) protection_map[1] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[2] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[3] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); - protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[4] = __pgprot(_page_cachable_default | _PAGE_PRESENT); protection_map[5] = __pgprot(_page_cachable_default | _PAGE_PRESENT); - protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[6] = __pgprot(_page_cachable_default | _PAGE_PRESENT); protection_map[7] = __pgprot(_page_cachable_default | _PAGE_PRESENT); protection_map[8] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ); protection_map[9] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC); protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ); protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE); - protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ); + protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT); protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT); - protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE | _PAGE_NO_READ); + protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE); } else { -- cgit v0.10.2 From 4ace6139bf23ab4f152ba4207fc10b76cc01d2a5 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 24 Jul 2015 16:57:49 +0100 Subject: MIPS: SMP: Don't increment irq_count multiple times for call function IPIs The majority of SMP platforms handle their IPIs through do_IRQ() which calls irq_{enter/exit}(). When a call function IPI is received, smp_call_function_interrupt() is called which also calls irq_{enter,exit}(), meaning irq_count is raised twice. When tick broadcasting is used (which is implemented via a call function IPI), this incorrectly causes all CPU idle time on the core receiving broadcast ticks to be accounted as time spent servicing IRQs, as account_process_tick() will account as such if irq_count is greater than 1. This results in 100% CPU usage being reported on a core which receives its ticks via broadcast. This patch removes the SMP smp_call_function_interrupt() wrapper which calls irq_{enter,exit}(). Platforms which handle their IPIs through do_IRQ() now call generic_smp_call_function_interrupt() directly to avoid incrementing irq_count a second time. Platforms which don't (loongson, sgi-ip27, sibyte) call generic_smp_call_function_interrupt() wrapped in irq_{enter,exit}(). Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10770/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 56f5d08..b7fa9ae 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id) cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); if (action & SMP_CALL_FUNCTION) - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 16f1ea9..03722d4 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -83,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu) extern void play_dead(void); #endif -extern asmlinkage void smp_call_function_interrupt(void); - static inline void arch_send_call_function_single_ipi(int cpu) { extern struct plat_smp_ops *mp_ops; /* private */ diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 336708a..78cf8c2 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id) if (action == 0) scheduler_ipi(); else - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } @@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id) if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); if (action & SMP_CALL_FUNCTION) - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index d0744cc..a31896c 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -192,16 +192,6 @@ asmlinkage void start_secondary(void) cpu_startup_entry(CPUHP_ONLINE); } -/* - * Call into both interrupt handlers, as we share the IPI for them - */ -void __irq_entry smp_call_function_interrupt(void) -{ - irq_enter(); - generic_smp_call_function_interrupt(); - irq_exit(); -} - static void stop_this_cpu(void *dummy) { /* diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 6ab1057..be18648 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 509877c..1a4738a 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); - if (action & SMP_CALL_FUNCTION) - smp_call_function_interrupt(); + if (action & SMP_CALL_FUNCTION) { + irq_enter(); + generic_smp_call_function_interrupt(); + irq_exit(); + } if (action & SMP_ASK_C0COUNT) { BUG_ON(cpu != 0); diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index d1392f8..fa8f591 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index dc3e327..f5fff22 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) { clear_c0_eimr(irq); ack_c0_eirr(irq); - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); set_c0_eimr(irq); } diff --git a/arch/mips/paravirt/paravirt-smp.c b/arch/mips/paravirt/paravirt-smp.c index 42181c7..f8d3e08 100644 --- a/arch/mips/paravirt/paravirt-smp.c +++ b/arch/mips/paravirt/paravirt-smp.c @@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id) static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id) { - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } diff --git a/arch/mips/pmcs-msp71xx/msp_smp.c b/arch/mips/pmcs-msp71xx/msp_smp.c index 1017058..ffa0f71 100644 --- a/arch/mips/pmcs-msp71xx/msp_smp.c +++ b/arch/mips/pmcs-msp71xx/msp_smp.c @@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 3fbaef9..16ec4e1 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void) scheduler_ipi(); } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ); - smp_call_function_interrupt(); + irq_enter(); + generic_smp_call_function_interrupt(); + irq_exit(); } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ); - smp_call_function_interrupt(); + irq_enter(); + generic_smp_call_function_interrupt(); + irq_exit(); } else #endif { diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index af7d44e..4c71aea 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -29,8 +29,6 @@ #include #include -extern void smp_call_function_interrupt(void); - /* * These are routines for dealing with the bcm1480 smp capabilities * independent of board/firmware @@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void) if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); - if (action & SMP_CALL_FUNCTION) - smp_call_function_interrupt(); + if (action & SMP_CALL_FUNCTION) { + irq_enter(); + generic_smp_call_function_interrupt(); + irq_exit(); + } } diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index c0c4b3f..1cf66f5 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void) if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); - if (action & SMP_CALL_FUNCTION) - smp_call_function_interrupt(); + if (action & SMP_CALL_FUNCTION) { + irq_enter(); + generic_smp_call_function_interrupt(); + irq_exit(); + } } diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index b7d54d4..ff4be05 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -538,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) { - smp_call_function_interrupt(); + generic_smp_call_function_interrupt(); return IRQ_HANDLED; } -- cgit v0.10.2 From 55c723e181ccec30fb5c672397fe69ec35967d97 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 27 Jul 2015 13:50:21 +0100 Subject: MIPS: do_mcheck: Fix kernel code dump with EVA If a machine check exception is raised in kernel mode, user context, with EVA enabled, then the do_mcheck handler will attempt to read the code around the EPC using EVA load instructions, i.e. as if the reads were from user mode. This will either read random user data if the process has anything mapped at the same address, or it will cause an exception which is handled by __get_user, resulting in this output: Code: (Bad address in epc) Fix by setting the current user access mode to kernel if the saved register context indicates the exception was taken in kernel mode. This causes __get_user to use normal loads to read the kernel code. Signed-off-by: James Hogan Cc: Markos Chandras Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # 3.15+ Patchwork: https://patchwork.linux-mips.org/patch/10777/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e207a43..02484d1 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1519,6 +1519,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs) const int field = 2 * sizeof(unsigned long); int multi_match = regs->cp0_status & ST0_TS; enum ctx_state prev_state; + mm_segment_t old_fs = get_fs(); prev_state = exception_enter(); show_regs(regs); @@ -1540,8 +1541,13 @@ asmlinkage void do_mcheck(struct pt_regs *regs) dump_tlb_all(); } + if (!user_mode(regs)) + set_fs(KERNEL_DS); + show_code((unsigned int __user *) regs->cp0_epc); + set_fs(old_fs); + /* * Some chips may have other causes of machine check (e.g. SB1 * graduation timer) -- cgit v0.10.2 From 1e77863a51698c4319587df34171bd823691a66a Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 27 Jul 2015 13:50:22 +0100 Subject: MIPS: show_stack: Fix stack trace with EVA The show_stack() function deals exclusively with kernel contexts, but if it gets called in user context with EVA enabled, show_stacktrace() will attempt to access the stack using EVA accesses, which will either read other user mapped data, or more likely cause an exception which will be handled by __get_user(). This is easily reproduced using SysRq t to show all task states, which results in the following stack dump output: Stack : (Bad stack address) Fix by setting the current user access mode to kernel around the call to show_stacktrace(). This causes __get_user() to use normal loads to read the kernel stack. Now we get the correct output, like this: Stack : 00000000 80168960 00000000 004a0000 00000000 00000000 8060016c 1f3abd0c 1f172cd8 8056f09c 7ff1e450 8014fc3c 00000001 806dd0b0 0000001d 00000002 1f17c6a0 1f17c804 1f17c6a0 8066f6e0 00000000 0000000a 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0110e800 1f3abd6c 1f17c6a0 ... Signed-off-by: James Hogan Cc: Markos Chandras Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # 3.15+ Patchwork: https://patchwork.linux-mips.org/patch/10778/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 02484d1..8ea28e6 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task, void show_stack(struct task_struct *task, unsigned long *sp) { struct pt_regs regs; + mm_segment_t old_fs = get_fs(); if (sp) { regs.regs[29] = (unsigned long)sp; regs.regs[31] = 0; @@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp) prepare_frametrace(®s); } } + /* + * show_stack() deals exclusively with kernel mode, so be sure to access + * the stack in the kernel (not user) address space. + */ + set_fs(KERNEL_DS); show_stacktrace(task, ®s); + set_fs(old_fs); } static void show_code(unsigned int __user *pc) -- cgit v0.10.2 From 0cb0985f57783c2f3c6c8ffe7e7665e80c56bd92 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 23 Jul 2015 18:59:52 +0200 Subject: MIPS: Export get_c0_perfcount_int() get_c0_perfcount_int is tested from oprofile code. If oprofile is compiled as module, get_c0_perfcount_int needs to be exported, otherwise it cannot be resolved. Fixes: a669efc4a3b4 ("MIPS: Add hook to get C0 performance counter interrupt") Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Felix Fietkau Cc: linux-mips@linux-mips.org Cc: abrestic@chromium.org Patchwork: https://patchwork.linux-mips.org/patch/10763/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 01a644f..1ba2120 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -190,6 +190,7 @@ int get_c0_perfcount_int(void) { return ATH79_MISC_IRQ(5); } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index be18648..2c218c3 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -466,6 +466,7 @@ int get_c0_perfcount_int(void) { return ltq_perfcount_irq; } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index c1dc730..b7bf721 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -154,6 +154,7 @@ int get_c0_perfcount_int(void) return mips_cpu_perf_irq; } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index e1d6989..a120b7a 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c @@ -77,6 +77,7 @@ int get_c0_perfcount_int(void) return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; return -1; } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { diff --git a/arch/mips/pistachio/time.c b/arch/mips/pistachio/time.c index 7c73fcb..8a37734 100644 --- a/arch/mips/pistachio/time.c +++ b/arch/mips/pistachio/time.c @@ -26,6 +26,7 @@ int get_c0_perfcount_int(void) { return gic_get_c0_perfcount_int(); } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); int get_c0_fdc_int(void) { diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index 53707aa..8c624a8 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -89,6 +89,7 @@ int get_c0_perfcount_int(void) { return rt_perfcount_irq; } +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { -- cgit v0.10.2 From 3592bb08fb2da21157bc2837c4c9a951b84d0c7a Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 28 Apr 2015 10:52:50 -0700 Subject: MIPS: BMIPS: Delete unused Kconfig symbol This was left over from an earlier iteration of the BMIPS irqchip changes. It doesn't actually have an effect, so let's nuke it. Reported-by: Valentin Rothberg Signed-off-by: Kevin Cernekee Acked-by: Florian Fainelli Cc: stable@vger.kernel.org # v4.1+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/9910/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index cee5f93..199a835 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -151,7 +151,6 @@ config BMIPS_GENERIC select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ select IRQ_MIPS_CPU - select RAW_IRQ_ACCESSORS select DMA_NONCOHERENT select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN -- cgit v0.10.2 From 247bfb65d731350093f5d1a0a8b3d65e49c17baa Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 28 Jul 2015 19:24:24 -0700 Subject: Revert "MIPS: BCM63xx: Provide a plat_post_dma_flush hook" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3cf29543413207d3ab1c3f62a88c09bb46f2264e ("MIPS: BCM63xx: Provide a plat_post_dma_flush hook") since this commit was found to prevent BCM6358 (early BMIPS4350 cores) and some BCM6368 (BMIPS4380 cores) from booting reliably. Alvaro was able to track this down to an issue specifically located to devices that use the second thread (TP1) when booting. Since BCM63xx did not have a need for plat_post_dma_flush() hook before, let's just keep things the way they were. Reported-by: Álvaro Fernández Rojas Reported-by: Jonas Gorski Signed-off-by: Florian Fainelli Cc: stable@vger.kernel.org Cc: Kevin Cernekee Cc: Nicolas Schichan Cc: linux-mips@linux-mips.org Cc: blogic@openwrt.org Cc: noltari@gmail.com Cc: jogo@openwrt.org Cc: Florian Fainelli Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10804/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h b/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h deleted file mode 100644 index 11d3b57..0000000 --- a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_MACH_BCM63XX_DMA_COHERENCE_H -#define __ASM_MACH_BCM63XX_DMA_COHERENCE_H - -#include - -#define plat_post_dma_flush bmips_post_dma_flush - -#include - -#endif /* __ASM_MACH_BCM63XX_DMA_COHERENCE_H */ -- cgit v0.10.2 From 741e3b9902d11585e18bfc7f8d47e913616bb070 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 2 Aug 2015 13:24:13 -0500 Subject: rtlwifi: rtl8723be: Add module parameter for MSI interrupts The driver code allows for the disabling of MSI interrupts; however the module_parm line was missed and the option fails to show with modinfo. Signed-off-by: Larry Finger Cc: Stable [3.15+] Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 1017f02..7bf88d9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444); module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444); module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); -- cgit v0.10.2 From 3aff47c062b944a5e1f9af56a37a23f5295628fc Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 31 Jul 2015 16:29:38 +0100 Subject: MIPS: Flush RPS on kernel entry with EVA When EVA is enabled, flush the Return Prediction Stack (RPS) present on some MIPS cores on entry to the kernel from user mode. This is important specifically for interAptiv with EVA enabled, otherwise kernel mode RPS mispredicts may trigger speculative fetches of user return addresses, which may be sensitive in the kernel address space due to EVA's overlapping user/kernel address spaces. Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Markos Chandras Cc: Leonid Yegoshin Cc: linux-mips@linux-mips.org Cc: # 3.15.x- Patchwork: https://patchwork.linux-mips.org/patch/10812/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index 28d6d93..a71da57 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -152,6 +152,31 @@ .set noreorder bltz k0, 8f move k1, sp +#ifdef CONFIG_EVA + /* + * Flush interAptiv's Return Prediction Stack (RPS) by writing + * EntryHi. Toggling Config7.RPS is slower and less portable. + * + * The RPS isn't automatically flushed when exceptions are + * taken, which can result in kernel mode speculative accesses + * to user addresses if the RPS mispredicts. That's harmless + * when user and kernel share the same address space, but with + * EVA the same user segments may be unmapped to kernel mode, + * even containing sensitive MMIO regions or invalid memory. + * + * This can happen when the kernel sets the return address to + * ret_from_* and jr's to the exception handler, which looks + * more like a tail call than a function call. If nested calls + * don't evict the last user address in the RPS, it will + * mispredict the return and fetch from a user controlled + * address into the icache. + * + * More recent EVA-capable cores with MAAR to restrict + * speculative accesses aren't affected. + */ + MFC0 k0, CP0_ENTRYHI + MTC0 k0, CP0_ENTRYHI +#endif .set reorder /* Called from user mode, new stack. */ get_saved_sp -- cgit v0.10.2 From a4504755e7dc8d43ed2a934397032691cd03adf7 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Wed, 17 Jun 2015 17:12:50 +0100 Subject: MIPS: Replace add and sub instructions in relocate_kernel.S with addiu Fixes the assembler errors generated when compiling a MIPS R6 kernel with CONFIG_KEXEC on, by replacing the offending add and sub instructions with addiu instructions. Build errors: arch/mips/kernel/relocate_kernel.S: Assembler messages: arch/mips/kernel/relocate_kernel.S:27: Error: invalid operands `dadd $16,$16,8' arch/mips/kernel/relocate_kernel.S:64: Error: invalid operands `dadd $20,$20,8' arch/mips/kernel/relocate_kernel.S:65: Error: invalid operands `dadd $18,$18,8' arch/mips/kernel/relocate_kernel.S:66: Error: invalid operands `dsub $22,$22,1' scripts/Makefile.build:294: recipe for target 'arch/mips/kernel/relocate_kernel.o' failed Signed-off-by: James Cowgill Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10558/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index 74bab9d..c6bbf21 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -24,7 +24,7 @@ LEAF(relocate_new_kernel) process_entry: PTR_L s2, (s0) - PTR_ADD s0, s0, SZREG + PTR_ADDIU s0, s0, SZREG /* * In case of a kdump/crash kernel, the indirection page is not @@ -61,9 +61,9 @@ copy_word: /* copy page word by word */ REG_L s5, (s2) REG_S s5, (s4) - PTR_ADD s4, s4, SZREG - PTR_ADD s2, s2, SZREG - LONG_SUB s6, s6, 1 + PTR_ADDIU s4, s4, SZREG + PTR_ADDIU s2, s2, SZREG + LONG_ADDIU s6, s6, -1 beq s6, zero, process_entry b copy_word b process_entry -- cgit v0.10.2 From e13c42ecbe580509451e021ba2586871e5b47640 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 3 Aug 2015 15:37:24 +0530 Subject: ARCv2: Fix the peripheral address space detection With HS 2.1 release, the peripheral space register no longer contains the uncached space specifics, causing the kernel to panic early on. So read the newer NON VOLATILE AUX register to get that info. Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 070f588..c8f57b8 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -89,11 +89,10 @@ #define ECR_C_BIT_DTLB_LD_MISS 8 #define ECR_C_BIT_DTLB_ST_MISS 9 - /* Auxiliary registers */ #define AUX_IDENTITY 4 #define AUX_INTR_VEC_BASE 0x25 - +#define AUX_NON_VOL 0x5e /* * Floating Pt Registers @@ -240,9 +239,9 @@ struct bcr_extn_xymem { struct bcr_perip { #ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int start:8, pad2:8, sz:8, pad:8; + unsigned int start:8, pad2:8, sz:8, ver:8; #else - unsigned int pad:8, sz:8, pad2:8, start:8; + unsigned int ver:8, sz:8, pad2:8, start:8; #endif }; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 18cc015..f2f771b 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -47,6 +47,7 @@ static void read_arc_build_cfg_regs(void) struct bcr_perip uncached_space; struct bcr_generic bcr; struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; + unsigned long perip_space; FIX_PTR(cpu); READ_BCR(AUX_IDENTITY, cpu->core); @@ -56,7 +57,12 @@ static void read_arc_build_cfg_regs(void) cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE); READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space); - BUG_ON((uncached_space.start << 24) != ARC_UNCACHED_ADDR_SPACE); + if (uncached_space.ver < 3) + perip_space = uncached_space.start << 24; + else + perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000; + + BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE); READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy); -- cgit v0.10.2 From c93e64e91248becd0edb8f01723dff9da890e2ab Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 16 Jan 2015 11:32:51 -0500 Subject: usb: udc: core: add device_del() call to error pathway This patch fixes a bug in the error pathway of usb_add_gadget_udc_release() in udc-core.c. If the udc registration fails, the gadget registration is not fully undone; there's a put_device(&gadget->dev) call but no device_del(). CC: Acked-by: Peter Chen Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 362ee8a..89ed5e7 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -323,6 +323,7 @@ err4: err3: put_device(&udc->dev); + device_del(&gadget->dev); err2: put_device(&gadget->dev); -- cgit v0.10.2 From 6b5e38dccd2c72b62c57681861ba3594117d993e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:35:00 +0900 Subject: thermal: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Zhang Rui diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index d5dd357..b49f97c 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -405,7 +405,6 @@ static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops, static struct platform_driver hisi_thermal_driver = { .driver = { .name = "hisi_thermal", - .owner = THIS_MODULE, .pm = &hisi_thermal_pm_ops, .of_match_table = of_hisi_thermal_match, }, -- cgit v0.10.2 From 5413fcdbe9e7ca32ce3f00fd5251dfa560b7484b Mon Sep 17 00:00:00 2001 From: Salvatore Mesoraca Date: Mon, 3 Aug 2015 12:40:51 +0200 Subject: Adding YAMA hooks also when YAMA is not stacked. Without this patch YAMA will not work at all if it is chosen as the primary LSM instead of being "stacked". Signed-off-by: Salvatore Mesoraca Acked-by: Kees Cook Signed-off-by: James Morris diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 9ed3250..5ebb896 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -406,6 +406,7 @@ static __init int yama_init(void) */ if (!security_module_enable("yama")) return 0; + yama_add_hooks(); #endif pr_info("Yama: becoming mindful.\n"); -- cgit v0.10.2 From fe16d4f202c59a560533a223bc6375739ee30944 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Aug 2015 11:41:33 -0400 Subject: Revert "libata-eh: Set 'information' field for autosense" This reverts commit a1524f226a02aa6edebd90ae0752e97cfd78b159. As implemented, ACS-4 sense reporting for ATA devices bypasses error diagnosis and handling in libata degrading EH behavior significantly. Revert the related changes for now. Signed-off-by: Tejun Heo Cc: Hannes Reinecke Cc: stable@vger.kernel.org #v4.1+ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index db5d9f7..426bc12 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -694,11 +694,11 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) * RETURNS: * Block address read from @tf. */ -u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev) +u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) { u64 block = 0; - if (!dev || tf->flags & ATA_TFLAG_LBA) { + if (tf->flags & ATA_TFLAG_LBA) { if (tf->flags & ATA_TFLAG_LBA48) { block |= (u64)tf->hob_lbah << 40; block |= (u64)tf->hob_lbam << 32; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7465031..af08d32 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1864,7 +1864,6 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n", sense_key, asc, ascq); ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); - ata_scsi_set_sense_information(qc->scsicmd, &qc->result_tf); qc->flags |= ATA_QCFLAG_SENSE_VALID; } @@ -1907,8 +1906,6 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, tmp = ata_eh_request_sense(qc, qc->scsicmd); if (tmp) qc->err_mask |= tmp; - else - ata_scsi_set_sense_information(qc->scsicmd, tf); } else { ata_dev_warn(qc->dev, "sense data available but port frozen\n"); } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 641a61a..e1ecd2a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -280,18 +280,6 @@ void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); } -void ata_scsi_set_sense_information(struct scsi_cmnd *cmd, - const struct ata_taskfile *tf) -{ - u64 information; - - if (!cmd) - return; - - information = ata_tf_read_block(tf, NULL); - scsi_set_sense_information(cmd->sense_buffer, information); -} - static ssize_t ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a998a17..8cfdd96 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -67,8 +67,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag); extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, u64 block, u32 n_block, unsigned int tf_flags, unsigned int tag); -extern u64 ata_tf_read_block(const struct ata_taskfile *tf, - struct ata_device *dev); +extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen, @@ -139,8 +138,6 @@ extern int ata_scsi_add_hosts(struct ata_host *host, extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); -extern void ata_scsi_set_sense_information(struct scsi_cmnd *cmd, - const struct ata_taskfile *tf); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 106884a..b79bbea 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -2523,33 +2522,3 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) } } EXPORT_SYMBOL(scsi_build_sense_buffer); - -/** - * scsi_set_sense_information - set the information field in a - * formatted sense data buffer - * @buf: Where to build sense data - * @info: 64-bit information value to be set - * - **/ -void scsi_set_sense_information(u8 *buf, u64 info) -{ - if ((buf[0] & 0x7f) == 0x72) { - u8 *ucp, len; - - len = buf[7]; - ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); - if (!ucp) { - buf[7] = len + 0xa; - ucp = buf + 8 + len; - } - ucp[0] = 0; - ucp[1] = 0xa; - ucp[2] = 0x80; /* Valid bit */ - ucp[3] = 0; - put_unaligned_be64(info, &ucp[4]); - } else if ((buf[0] & 0x7f) == 0x70) { - buf[0] |= 0x80; - put_unaligned_be64(info, &buf[3]); - } -} -EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 4942710..8d1d7fa 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -28,7 +28,6 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, u64 * info_out); extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -extern void scsi_set_sense_information(u8 *buf, u64 info); extern int scsi_ioctl_reset(struct scsi_device *, int __user *); -- cgit v0.10.2 From 84ded2f8e7dda336fc2fb3570726ceb3b3b3590f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Aug 2015 11:45:34 -0400 Subject: Revert "libata: Implement support for sense data reporting" This reverts commit fe7173c206de63fc28475ee6ae42ff95c05692de. As implemented, ACS-4 sense reporting for ATA devices bypasses error diagnosis and handling in libata degrading EH behavior significantly. Revert the related changes for now. ATA_ID_COMMAND_SET_3/4 constants are not reverted as they're used by later changes. Signed-off-by: Tejun Heo Cc: Hannes Reinecke Cc: stable@vger.kernel.org #v4.1+ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 426bc12..19bcb80 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2147,24 +2147,6 @@ static int ata_dev_config_ncq(struct ata_device *dev, return 0; } -static void ata_dev_config_sense_reporting(struct ata_device *dev) -{ - unsigned int err_mask; - - if (!ata_id_has_sense_reporting(dev->id)) - return; - - if (ata_id_sense_reporting_enabled(dev->id)) - return; - - err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1); - if (err_mask) { - ata_dev_dbg(dev, - "failed to enable Sense Data Reporting, Emask 0x%x\n", - err_mask); - } -} - /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -2387,7 +2369,7 @@ int ata_dev_configure(struct ata_device *dev) dev->devslp_timing[i] = sata_setting[j]; } } - ata_dev_config_sense_reporting(dev); + dev->cdb_len = 16; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index af08d32..16125be 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1630,70 +1630,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key) } /** - * ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT - * @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to - * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) - * @dfl_sense_key: default sense key to use - * - * Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK - * SENSE. This function is EH helper. - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * encoded sense data on success, 0 on failure or if sense data - * is not available. - */ -static u32 ata_eh_request_sense(struct ata_queued_cmd *qc, - struct scsi_cmnd *cmd) -{ - struct ata_device *dev = qc->dev; - struct ata_taskfile tf; - unsigned int err_mask; - - if (!cmd) - return 0; - - DPRINTK("ATA request sense\n"); - ata_dev_warn(dev, "request sense\n"); - if (!ata_id_sense_reporting_enabled(dev->id)) { - ata_dev_warn(qc->dev, "sense data reporting disabled\n"); - return 0; - } - ata_tf_init(dev, &tf); - - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; - tf.command = ATA_CMD_REQ_SENSE_DATA; - tf.protocol = ATA_PROT_NODATA; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); - /* - * ACS-4 states: - * The device may set the SENSE DATA AVAILABLE bit to one in the - * STATUS field and clear the ERROR bit to zero in the STATUS field - * to indicate that the command returned completion without an error - * and the sense data described in table 306 is available. - * - * IOW the 'ATA_SENSE' bit might not be set even though valid - * sense data is available. - * So check for both. - */ - if ((tf.command & ATA_SENSE) || - tf.lbah != 0 || tf.lbam != 0 || tf.lbal != 0) { - ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal); - qc->flags |= ATA_QCFLAG_SENSE_VALID; - ata_dev_warn(dev, "sense data %02x/%02x/%02x\n", - tf.lbah, tf.lbam, tf.lbal); - } else { - ata_dev_warn(dev, "request sense failed stat %02x emask %x\n", - tf.command, err_mask); - } - return err_mask; -} - -/** * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * @dev: device to perform REQUEST_SENSE to * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) @@ -1896,22 +1832,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return ATA_EH_RESET; } - /* - * Sense data reporting does not work if the - * device fault bit is set. - */ - if ((stat & ATA_SENSE) && !(stat & ATA_DF) && - !(qc->flags & ATA_QCFLAG_SENSE_VALID)) { - if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) { - tmp = ata_eh_request_sense(qc, qc->scsicmd); - if (tmp) - qc->err_mask |= tmp; - } else { - ata_dev_warn(qc->dev, "sense data available but port frozen\n"); - } - } - - /* Set by NCQ autosense or request sense above */ + /* Set by NCQ autosense */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) return 0; @@ -2658,15 +2579,14 @@ static void ata_eh_link_report(struct ata_link *link) #ifdef CONFIG_ATA_VERBOSE_ERROR if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | - ATA_SENSE | ATA_ERR)) { + ATA_ERR)) { if (res->command & ATA_BUSY) ata_dev_err(qc->dev, "status: { Busy }\n"); else - ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n", + ata_dev_err(qc->dev, "status: { %s%s%s%s}\n", res->command & ATA_DRDY ? "DRDY " : "", res->command & ATA_DF ? "DF " : "", res->command & ATA_DRQ ? "DRQ " : "", - res->command & ATA_SENSE ? "SENSE " : "", res->command & ATA_ERR ? "ERR " : ""); } diff --git a/include/linux/ata.h b/include/linux/ata.h index 6c78956..0e6a782 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -385,8 +385,6 @@ enum { SATA_SSP = 0x06, /* Software Settings Preservation */ SATA_DEVSLP = 0x09, /* Device Sleep */ - SETFEATURE_SENSE_DATA = 0xC3, /* Sense Data Reporting feature */ - /* feature values for SET_MAX */ ATA_SET_MAX_ADDR = 0x00, ATA_SET_MAX_PASSWD = 0x01, @@ -720,20 +718,6 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id) return false; } -static inline bool ata_id_has_sense_reporting(const u16 *id) -{ - if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15))) - return false; - return id[ATA_ID_COMMAND_SET_3] & (1 << 6); -} - -static inline bool ata_id_sense_reporting_enabled(const u16 *id) -{ - if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15))) - return false; - return id[ATA_ID_COMMAND_SET_4] & (1 << 6); -} - /** * ata_id_major_version - get ATA level of drive * @id: Identify data -- cgit v0.10.2 From 74a80d67b8316eb3fbeb73dafc060a5a0a708587 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Aug 2015 11:46:39 -0400 Subject: Revert "libata: Implement NCQ autosense" This reverts commit 42b966fbf35da9c87f08d98f9b8978edf9e717cf. As implemented, ACS-4 sense reporting for ATA devices bypasses error diagnosis and handling in libata degrading EH behavior significantly. Revert the related changes for now. Signed-off-by: Tejun Heo Cc: Hannes Reinecke Cc: stable@vger.kernel.org #v4.1+ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 16125be..cb0508a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1592,8 +1592,6 @@ static int ata_eh_read_log_10h(struct ata_device *dev, tf->hob_lbah = buf[10]; tf->nsect = buf[12]; tf->hob_nsect = buf[13]; - if (ata_id_has_ncq_autosense(dev->id)) - tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16]; return 0; } @@ -1791,18 +1789,6 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) memcpy(&qc->result_tf, &tf, sizeof(tf)); qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; - if (qc->result_tf.auxiliary) { - char sense_key, asc, ascq; - - sense_key = (qc->result_tf.auxiliary >> 16) & 0xff; - asc = (qc->result_tf.auxiliary >> 8) & 0xff; - ascq = qc->result_tf.auxiliary & 0xff; - ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n", - sense_key, asc, ascq); - ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq); - qc->flags |= ATA_QCFLAG_SENSE_VALID; - } - ehc->i.err_mask &= ~AC_ERR_DEV; } @@ -1832,10 +1818,6 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return ATA_EH_RESET; } - /* Set by NCQ autosense */ - if (qc->flags & ATA_QCFLAG_SENSE_VALID) - return 0; - if (stat & (ATA_ERR | ATA_DF)) qc->err_mask |= AC_ERR_DEV; else diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e1ecd2a..0d7f0da 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -270,11 +270,8 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR, ata_scsi_park_show, ata_scsi_park_store); EXPORT_SYMBOL_GPL(dev_attr_unload_heads); -void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) { - if (!cmd) - return; - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); @@ -1780,9 +1777,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ((cdb[2] & 0x20) || need_sense)) { ata_gen_passthru_sense(qc); } else { - if (qc->flags & ATA_QCFLAG_SENSE_VALID) { - cmd->result = SAM_STAT_CHECK_CONDITION; - } else if (!need_sense) { + if (!need_sense) { cmd->result = SAM_STAT_GOOD; } else { /* TODO: decide which descriptor format to use diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 8cfdd96..f840ca1 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -137,7 +137,6 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht); extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); -extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); diff --git a/include/linux/ata.h b/include/linux/ata.h index 0e6a782..d2992bf 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -528,8 +528,6 @@ struct ata_bmdma_prd { #define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20) #define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4)) #define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)) -#define ata_id_has_ncq_autosense(id) \ - ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7)) static inline bool ata_id_has_hipm(const u16 *id) { -- cgit v0.10.2 From 3576fd794b38306e196498ac54bb3b21c32e1ae4 Mon Sep 17 00:00:00 2001 From: Glenn Griffin Date: Mon, 3 Aug 2015 09:56:54 -0700 Subject: openvswitch: Fix L4 checksum handling when dealing with IP fragments openvswitch modifies the L4 checksum of a packet when modifying the ip address. When an IP packet is fragmented only the first fragment contains an L4 header and checksum. Prior to this change openvswitch would modify all fragments, modifying application data in non-first fragments, causing checksum failures in the reassembled packet. Signed-off-by: Glenn Griffin Acked-by: Pravin B Shelar Signed-off-by: David S. Miller diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 8a8c0b8..ee34f47 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -273,28 +273,36 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, return 0; } -static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, - __be32 *addr, __be32 new_addr) +static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, + __be32 addr, __be32 new_addr) { int transport_len = skb->len - skb_transport_offset(skb); + if (nh->frag_off & htons(IP_OFFSET)) + return; + if (nh->protocol == IPPROTO_TCP) { if (likely(transport_len >= sizeof(struct tcphdr))) inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, - *addr, new_addr, 1); + addr, new_addr, 1); } else if (nh->protocol == IPPROTO_UDP) { if (likely(transport_len >= sizeof(struct udphdr))) { struct udphdr *uh = udp_hdr(skb); if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { inet_proto_csum_replace4(&uh->check, skb, - *addr, new_addr, 1); + addr, new_addr, 1); if (!uh->check) uh->check = CSUM_MANGLED_0; } } } +} +static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, + __be32 *addr, __be32 new_addr) +{ + update_ip_l4_checksum(skb, nh, *addr, new_addr); csum_replace4(&nh->check, *addr, new_addr); skb_clear_hash(skb); *addr = new_addr; -- cgit v0.10.2 From c20bc5502d151ca731ebc672b95aa77e2bf32c8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 30 Jul 2015 11:01:13 -0700 Subject: Input: turbografx - fix potential out of bound access Patch 17dd3f0f7aa7: "[PATCH] drivers/input/joystick: convert to dynamic input_dev allocation" from Sep 15, 2005, leads to the following static checker warning: drivers/input/joystick/turbografx.c:235 tgfx_probe() error: buffer overflow 'tgfx_buttons' 5 <= 5 drivers/input/joystick/turbografx.c 195 for (i = 0; i < n_devs; i++) { 196 if (n_buttons[i] < 1) 197 continue; 198 199 if (n_buttons[i] > 6) { ^^^^^^^^^^^^^^^^ Possibly off by one. >= 6. Let's change the upper value to ARRAY_SIZE(tgfx_buttons) to ensure we do not reach past the end of the array. Reported-by: Dan Carpenter Reviewed-by: Dan Carpenter Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 27b6a3c..891797a 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) if (n_buttons[i] < 1) continue; - if (n_buttons[i] > 6) { + if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) { printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); err = -EINVAL; goto err_unreg_devs; -- cgit v0.10.2 From b6e26546cc08e870da5413a3fcccc100eb2192c6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Aug 2015 13:29:29 -0700 Subject: Input: axp20x-pek - add module alias Add a proper module alias so the driver can be autoloaded when the parent axp20x mfd driver registers its cells. Signed-off-by: Chen-Yu Tsai Acked-by: Carlo Caione Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 10e140a..1ac898d 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver); MODULE_DESCRIPTION("axp20x Power Button"); MODULE_AUTHOR("Carlo Caione "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:axp20x-pek"); -- cgit v0.10.2 From 073e570d7c2caae9910a993d56f340be4548a4a8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Aug 2015 14:06:24 -0700 Subject: Input: alps - only Dell laptops have separate button bits for v2 dualpoint sticks It turns out that only Dell laptops have the separate button bits for v2 dualpoint sticks and that commit 92bac83dd79e ("Input: alps - non interleaved V2 dualpoint has separate stick button bits") causes regressions on Toshiba laptops. This commit adds a check for Dell laptops to the code for handling these extra button bits, fixing this regression. This patch has been tested on a Dell Latitude D620 to make sure that it does not reintroduce the original problem. Reported-and-tested-by: Douglas Christman Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index e301887d..765d99c 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2 byte 5: 0 z6 z5 z4 z3 z2 z1 z0 Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for -the DualPoint Stick. For non interleaved dualpoint devices the pointingstick -buttons get reported separately in the PSM, PSR and PSL bits. +the DualPoint Stick. The M, R and L bits signal the combined status of both +the pointingstick and touchpad buttons, except for Dell dualpoint devices +where the pointingstick buttons get reported separately in the PSM, PSR +and PSL bits. Dualpoint device -- interleaved packet format --------------------------------------------- diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 113d6f1..4d24686 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "psmouse.h" #include "alps.h" @@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 6-byte ALPS packet */ +#define ALPS_DELL 0x100 /* device is a Dell laptop */ #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ static const struct alps_model_info alps_model_data[] = { @@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) return; } - /* Non interleaved V2 dualpoint has separate stick button bits */ + /* Dell non interleaved V2 dualpoint has separate stick button bits */ if (priv->proto_version == ALPS_PROTO_V2 && - priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) { + priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) { left |= packet[0] & 1; right |= packet[0] & 2; middle |= packet[0] & 4; @@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->byte0 = protocol->byte0; priv->mask0 = protocol->mask0; priv->flags = protocol->flags; + if (dmi_name_in_vendors("Dell")) + priv->flags |= ALPS_DELL; priv->x_max = 2000; priv->y_max = 1400; -- cgit v0.10.2 From 636dba8e12d797357b2063981476390f11262c08 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 30 Jul 2015 17:12:20 -0700 Subject: act_mirred: avoid calling tcf_hash_release() when binding When we share an action within a filter, the bind refcnt should increase, therefore we should not call tcf_hash_release(). Cc: Jamal Hadi Salim Cc: Daniel Borkmann Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index a42a3b2..2685450 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -98,6 +98,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, return ret; ret = ACT_P_CREATED; } else { + if (bind) + return 0; if (!ovr) { tcf_hash_release(a, bind); return -EEXIST; -- cgit v0.10.2 From 7895086afde2a05fa24a0e410d8e6b75ca7c8fdd Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 3 Aug 2015 16:07:48 +0300 Subject: xhci: fix off by one error in TRB DMA address boundary check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to check that a TRB is part of the current segment before calculating its DMA address. Previously a ring segment didn't use a full memory page, and every new ring segment got a new memory page, so the off by one error in checking the upper bound was never seen. Now that we use a full memory page, 256 TRBs (4096 bytes), the off by one didn't catch the case when a TRB was the first element of the next segment. This is triggered if the virtual memory pages for a ring segment are next to each in increasing order where the ring buffer wraps around and causes errors like: [ 106.398223] xhci_hcd 0000:00:14.0: ERROR Transfer event TRB DMA ptr not part of current TD ep_index 0 comp_code 1 [ 106.398230] xhci_hcd 0000:00:14.0: Looking for event-dma fffd3000 trb-start fffd4fd0 trb-end fffd5000 seg-start fffd4000 seg-end fffd4ff0 The trb-end address is one outside the end-seg address. Cc: Tested-by: Arkadiusz Miśkiewicz Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6a8fc52..32f4d56 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -82,7 +82,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, return 0; /* offset in TRBs */ segment_offset = trb - seg->trbs; - if (segment_offset > TRBS_PER_SEGMENT) + if (segment_offset >= TRBS_PER_SEGMENT) return 0; return seg->dma + (segment_offset * sizeof(*trb)); } -- cgit v0.10.2 From ffe5adcb7661d94e952d6b5ed7f493cb4ef0c7bc Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 3 Aug 2015 16:07:49 +0300 Subject: drivers/usb: Delete XHCI command timer if necessary When xhci_mem_cleanup() is called, it's possible that the command timer isn't initialized and scheduled. For those cases, to delete the command timer causes soft-lockup as below stack dump shows. The patch avoids deleting the command timer if it's not scheduled with the help of timer_pending(). NMI watchdog: BUG: soft lockup - CPU#40 stuck for 23s! [kworker/40:1:8140] : NIP [c000000000150b30] lock_timer_base.isra.34+0x90/0xa0 LR [c000000000150c24] try_to_del_timer_sync+0x34/0xa0 Call Trace: [c000000f67c975e0] [c0000000015b84f8] mon_ops+0x0/0x8 (unreliable) [c000000f67c97620] [c000000000150c24] try_to_del_timer_sync+0x34/0xa0 [c000000f67c97660] [c000000000150cf0] del_timer_sync+0x60/0x80 [c000000f67c97690] [c00000000070ac0c] xhci_mem_cleanup+0x5c/0x5e0 [c000000f67c97740] [c00000000070c2e8] xhci_mem_init+0x1158/0x13b0 [c000000f67c97860] [c000000000700978] xhci_init+0x88/0x110 [c000000f67c978e0] [c000000000701644] xhci_gen_setup+0x2b4/0x590 [c000000f67c97970] [c0000000006d4410] xhci_pci_setup+0x40/0x190 [c000000f67c979f0] [c0000000006b1af8] usb_add_hcd+0x418/0xba0 [c000000f67c97ab0] [c0000000006cb15c] usb_hcd_pci_probe+0x1dc/0x5c0 [c000000f67c97b50] [c0000000006d3ba4] xhci_pci_probe+0x64/0x1f0 [c000000f67c97ba0] [c0000000004fe9ac] local_pci_probe+0x6c/0x130 [c000000f67c97c30] [c0000000000e5ce8] work_for_cpu_fn+0x38/0x60 [c000000f67c97c60] [c0000000000eacb8] process_one_work+0x198/0x470 [c000000f67c97cf0] [c0000000000eb6ac] worker_thread+0x37c/0x5a0 [c000000f67c97d80] [c0000000000f2730] kthread+0x110/0x130 [c000000f67c97e30] [c000000000009660] ret_from_kernel_thread+0x5c/0x7c Cc: Reported-by: Priya M. A Signed-off-by: Gavin Shan Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3e442f7..9a8c936 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1792,7 +1792,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) int size; int i, j, num_ports; - del_timer_sync(&xhci->cmd_timer); + if (timer_pending(&xhci->cmd_timer)) + del_timer_sync(&xhci->cmd_timer); /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); -- cgit v0.10.2 From 468b732b6f76b138c0926eadf38ac88467dcd271 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 1 Aug 2015 15:33:26 +0300 Subject: rds: fix an integer overflow test in rds_info_getsockopt() "len" is a signed integer. We check that len is not negative, so it goes from zero to INT_MAX. PAGE_SIZE is unsigned long so the comparison is type promoted to unsigned long. ULONG_MAX - 4095 is a higher than INT_MAX so the condition can never be true. I don't know if this is harmful but it seems safe to limit "len" to INT_MAX - 4095. Fixes: a8c879a7ee98 ('RDS: Info and stats') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/net/rds/info.c b/net/rds/info.c index 9a6b4f6..140a44a 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, /* check for all kinds of wrapping and the like */ start = (unsigned long)optval; - if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) { + if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) { ret = -EINVAL; goto out; } -- cgit v0.10.2 From 2fc09962e24ace45154d0c16024f1eb15700f3e8 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Mon, 3 Aug 2015 11:18:12 +0800 Subject: 3c59x: Fix resource leaks in vortex_open When vortex_up is failed, the skb buffers allocated by __netdev_alloc_skb in vortex_open are not released, which may cause resource leaks. This bug has been submitted before. This patch modifies the error handling code to fix it. Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 2d1ce3c..753887d 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1763,16 +1763,9 @@ vortex_open(struct net_device *dev) vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } if (i != RX_RING_SIZE) { - int j; pr_emerg("%s: no memory for rx ring\n", dev->name); - for (j = 0; j < i; j++) { - if (vp->rx_skbuff[j]) { - dev_kfree_skb(vp->rx_skbuff[j]); - vp->rx_skbuff[j] = NULL; - } - } retval = -ENOMEM; - goto err_free_irq; + goto err_free_skb; } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); @@ -1782,7 +1775,13 @@ vortex_open(struct net_device *dev) if (!retval) goto out; -err_free_irq: +err_free_skb: + for (i = 0; i < RX_RING_SIZE; i++) { + if (vp->rx_skbuff[i]) { + dev_kfree_skb(vp->rx_skbuff[i]); + vp->rx_skbuff[i] = NULL; + } + } free_irq(dev->irq, dev); err: if (vortex_debug > 1) -- cgit v0.10.2 From 1f17124006b65482d9084c01e252b59dbca8db8f Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 2 Aug 2015 12:34:46 +0100 Subject: staging: vt6655: vnt_bss_info_changed check conf->beacon_rate is not NULL conf->beacon_rate can be NULL on association. So check conf->beacon_rate BSS_CHANGED_BEACON_INFO needs to flagged in changed as the beacon_rate will appear later. Signed-off-by: Malcolm Priestley Cc: # v3.19+ Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index b0c8e23..69bdc8f 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1483,8 +1483,9 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) { - if (conf->assoc) { + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && + priv->op_mode != NL80211_IFTYPE_AP) { + if (conf->assoc && conf->beacon_rate) { CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, conf->sync_tsf); -- cgit v0.10.2 From bd4aaf8f9b85d6b2df3231fd62b219ebb75d3568 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 3 Aug 2015 09:54:58 -0400 Subject: dm: fix dm_merge_bvec regression on 32 bit systems A DM regression on 32 bit systems was reported against v4.2-rc3 here: https://lkml.org/lkml/2015/7/29/401 Fix this by reverting both commit 1c220c69 ("dm: fix casting bug in dm_merge_bvec()") and 148e51ba ("dm: improve documentation and code clarity in dm_merge_bvec"). This combined revert is done to eliminate the possibility of a partial revert in stable@ kernels. In hindsight the correct fix, at the time 1c220c69 was applied to fix the regression that 148e51ba introduced, should've been to simply revert 148e51ba. Reported-by: Josh Boyer Tested-by: Adam Williamson Acked-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 3.19+ diff --git a/drivers/md/dm.c b/drivers/md/dm.c index ab37ae1..0d7ab20 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1729,7 +1729,8 @@ static int dm_merge_bvec(struct request_queue *q, struct mapped_device *md = q->queuedata; struct dm_table *map = dm_get_live_table_fast(md); struct dm_target *ti; - sector_t max_sectors, max_size = 0; + sector_t max_sectors; + int max_size = 0; if (unlikely(!map)) goto out; @@ -1742,18 +1743,10 @@ static int dm_merge_bvec(struct request_queue *q, * Find maximum amount of I/O that won't need splitting */ max_sectors = min(max_io_len(bvm->bi_sector, ti), - (sector_t) queue_max_sectors(q)); + (sector_t) BIO_MAX_SECTORS); max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size; - - /* - * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t - * to the targets' merge function since it holds sectors not bytes). - * Just doing this as an interim fix for stable@ because the more - * comprehensive cleanup of switching to sector_t will impact every - * DM target that implements a ->merge hook. - */ - if (max_size > INT_MAX) - max_size = INT_MAX; + if (max_size < 0) + max_size = 0; /* * merge_bvec_fn() returns number of bytes @@ -1761,13 +1754,13 @@ static int dm_merge_bvec(struct request_queue *q, * max is precomputed maximal io size */ if (max_size && ti->type->merge) - max_size = ti->type->merge(ti, bvm, biovec, (int) max_size); + max_size = ti->type->merge(ti, bvm, biovec, max_size); /* * If the target doesn't support merge method and some of the devices - * provided their merge_bvec method (we know this by looking for the - * max_hw_sectors that dm_set_device_limits may set), then we can't - * allow bios with multiple vector entries. So always set max_size - * to 0, and the code below allows just one page. + * provided their merge_bvec method (we know this by looking at + * queue_max_hw_sectors), then we can't allow bios with multiple vector + * entries. So always set max_size to 0, and the code below allows + * just one page. */ else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9) max_size = 0; -- cgit v0.10.2 From 6de7abfbad1c6a45893a47a17c2ac91b551aa90d Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 3 Aug 2015 18:27:56 +0530 Subject: ARCv2: [axs103_smp] Reduce clk for Quad FPGA configs Signed-off-by: Vineet Gupta diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index 99f7da5..e7769c3 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -389,6 +389,21 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od) static void __init axs103_early_init(void) { + /* + * AXS103 configurations for SMP/QUAD configurations share device tree + * which defaults to 90 MHz. However recent failures of Quad config + * revealed P&R timing violations so clamp it down to safe 50 MHz + * Instead of duplicating defconfig/DT for SMP/QUAD, add a small hack + * + * This hack is really hacky as of now. Fix it properly by getting the + * number of cores as return value of platform's early SMP callback + */ +#ifdef CONFIG_ARC_MCIP + unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F; + if (num_cores > 2) + arc_set_core_freq(50 * 1000000); +#endif + switch (arc_get_core_freq()/1000000) { case 33: axs103_set_freq(1, 1, 1); -- cgit v0.10.2 From f5959cb0c34c5c7f9f387e5d8fe1ec831ccb42ac Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 29 Jul 2015 19:20:58 +0530 Subject: Revert "ARCv2: STAR 9000837815 workaround hardware exclusive transactions livelock" Extended testing of quad core configuration revealed that this fix was insufficient. Specifically LTP open posix shm_op/23-1 would cause the hardware livelock in llock/scond loop in update_cpu_load_active() So remove this and make way for a proper workaround This reverts commit a5c8b52abe677977883655166796f167ef1e0084. Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 03484cb..20b7dc1 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -23,21 +23,13 @@ #define atomic_set(v, i) (((v)->counter) = (i)) -#ifdef CONFIG_ISA_ARCV2 -#define PREFETCHW " prefetchw [%1] \n" -#else -#define PREFETCHW -#endif - #define ATOMIC_OP(op, c_op, asm_op) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ unsigned int temp; \ \ __asm__ __volatile__( \ - "1: \n" \ - PREFETCHW \ - " llock %0, [%1] \n" \ + "1: llock %0, [%1] \n" \ " " #asm_op " %0, %0, %2 \n" \ " scond %0, [%1] \n" \ " bnz 1b \n" \ @@ -58,9 +50,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ smp_mb(); \ \ __asm__ __volatile__( \ - "1: \n" \ - PREFETCHW \ - " llock %0, [%1] \n" \ + "1: llock %0, [%1] \n" \ " " #asm_op " %0, %0, %2 \n" \ " scond %0, [%1] \n" \ " bnz 1b \n" \ -- cgit v0.10.2 From 8ac0665fb6ff125efc4df08772317f7311a95ce5 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 21 Jul 2015 12:05:42 +0300 Subject: ARC: refactor atomic inline asm operands with symbolic names This reduces the diff in forth-coming patches and also helps understand better the incremental changes to inline asm. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 20b7dc1..3dd36c1 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -26,22 +26,23 @@ #define ATOMIC_OP(op, c_op, asm_op) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ - unsigned int temp; \ + unsigned int val; \ \ __asm__ __volatile__( \ - "1: llock %0, [%1] \n" \ - " " #asm_op " %0, %0, %2 \n" \ - " scond %0, [%1] \n" \ - " bnz 1b \n" \ - : "=&r"(temp) /* Early clobber, to prevent reg reuse */ \ - : "r"(&v->counter), "ir"(i) \ + "1: llock %[val], [%[ctr]] \n" \ + " " #asm_op " %[val], %[val], %[i] \n" \ + " scond %[val], [%[ctr]] \n" \ + " bnz 1b \n" \ + : [val] "=&r" (val) /* Early clobber to prevent reg reuse */ \ + : [ctr] "r" (&v->counter), /* Not "m": llock only supports reg direct addr mode */ \ + [i] "ir" (i) \ : "cc"); \ } \ #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ - unsigned int temp; \ + unsigned int val; \ \ /* \ * Explicit full memory barrier needed before/after as \ @@ -50,17 +51,18 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ smp_mb(); \ \ __asm__ __volatile__( \ - "1: llock %0, [%1] \n" \ - " " #asm_op " %0, %0, %2 \n" \ - " scond %0, [%1] \n" \ - " bnz 1b \n" \ - : "=&r"(temp) \ - : "r"(&v->counter), "ir"(i) \ + "1: llock %[val], [%[ctr]] \n" \ + " " #asm_op " %[val], %[val], %[i] \n" \ + " scond %[val], [%[ctr]] \n" \ + " bnz 1b \n" \ + : [val] "=&r" (val) \ + : [ctr] "r" (&v->counter), \ + [i] "ir" (i) \ : "cc"); \ \ smp_mb(); \ \ - return temp; \ + return val; \ } #else /* !CONFIG_ARC_HAS_LLSC */ -- cgit v0.10.2 From ae7eae9e031206bde8645d038c76ad89e7d3fbcb Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 14 Jul 2015 17:55:05 +0530 Subject: ARC: LLOCK/SCOND based spin_lock Current spin_lock uses EXchange instruction to implement the atomic test and set of lock location (reads orig value and ST 1). This however forces the cacheline into exclusive state (because of the ST) and concurrent loops in multiple cores will bounce the line around between cores. Instead, use LLOCK/SCOND to implement the atomic test and set which is better as line is in shared state while lock is spinning on LLOCK The real motivation of this change however is to make way for future changes in atomics to implement delayed retry (with backoff). Initial experiment with delayed retry in atomics combined with orig EX based spinlock was a total disaster (broke even LMBench) as struct sock has a cache line sharing an atomic_t and spinlock. The tight spinning on lock, caused the atomic retry to keep backing off such that it would never finish. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index e1651df..4f6c90a 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -18,9 +18,68 @@ #define arch_spin_unlock_wait(x) \ do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) +#ifdef CONFIG_ARC_HAS_LLSC + +static inline void arch_spin_lock(arch_spinlock_t *lock) +{ + unsigned int val; + + smp_mb(); + + __asm__ __volatile__( + "1: llock %[val], [%[slock]] \n" + " breq %[val], %[LOCKED], 1b \n" /* spin while LOCKED */ + " scond %[LOCKED], [%[slock]] \n" /* acquire */ + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [slock] "r" (&(lock->slock)), + [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_spin_trylock(arch_spinlock_t *lock) +{ + unsigned int val, got_it = 0; + + smp_mb(); + + __asm__ __volatile__( + "1: llock %[val], [%[slock]] \n" + " breq %[val], %[LOCKED], 4f \n" /* already LOCKED, just bail */ + " scond %[LOCKED], [%[slock]] \n" /* acquire */ + " bnz 1b \n" + " mov %[got_it], 1 \n" + "4: \n" + " \n" + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + : [slock] "r" (&(lock->slock)), + [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_spin_unlock(arch_spinlock_t *lock) +{ + smp_mb(); + + lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__; + + smp_mb(); +} + +#else /* !CONFIG_ARC_HAS_LLSC */ + static inline void arch_spin_lock(arch_spinlock_t *lock) { - unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__; + unsigned int val = __ARCH_SPIN_LOCK_LOCKED__; /* * This smp_mb() is technically superfluous, we only need the one @@ -33,7 +92,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) __asm__ __volatile__( "1: ex %0, [%1] \n" " breq %0, %2, 1b \n" - : "+&r" (tmp) + : "+&r" (val) : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__) : "memory"); @@ -48,26 +107,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) smp_mb(); } +/* 1 - lock taken successfully */ static inline int arch_spin_trylock(arch_spinlock_t *lock) { - unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__; + unsigned int val = __ARCH_SPIN_LOCK_LOCKED__; smp_mb(); __asm__ __volatile__( "1: ex %0, [%1] \n" - : "+r" (tmp) + : "+r" (val) : "r"(&(lock->slock)) : "memory"); smp_mb(); - return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__); + return (val == __ARCH_SPIN_LOCK_UNLOCKED__); } static inline void arch_spin_unlock(arch_spinlock_t *lock) { - unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__; + unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__; /* * RELEASE barrier: given the instructions avail on ARCv2, full barrier @@ -77,7 +137,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) __asm__ __volatile__( " ex %0, [%1] \n" - : "+r" (tmp) + : "+r" (val) : "r"(&(lock->slock)) : "memory"); @@ -88,6 +148,8 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) smp_mb(); } +#endif + /* * Read-write spinlocks, allowing multiple readers but only one writer. * -- cgit v0.10.2 From 69cbe630f54ec02efe47fdb9e257e617161da370 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 16 Jul 2015 10:31:45 +0530 Subject: ARC: LLOCK/SCOND based rwlock With LLOCK/SCOND, the rwlock counter can be atomically updated w/o need for a guarding spin lock. This in turn elides the EXchange instruction based spinning which causes the cacheline transition to exclusive state and concurrent spinning across cores would cause the line to keep bouncing around. LLOCK/SCOND based implementation is superior as spinning on LLOCK keeps the cacheline in shared state. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index 4f6c90a..9fd5a02 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -75,6 +75,164 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) smp_mb(); } +/* + * Read-write spinlocks, allowing multiple readers but only one writer. + * Unfair locking as Writers could be starved indefinitely by Reader(s) + */ + +static inline void arch_read_lock(arch_rwlock_t *rw) +{ + unsigned int val; + + smp_mb(); + + /* + * zero means writer holds the lock exclusively, deny Reader. + * Otherwise grant lock to first/subseq reader + * + * if (rw->counter > 0) { + * rw->counter--; + * ret = 1; + * } + */ + + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " brls %[val], %[WR_LOCKED], 1b\n" /* <= 0: spin while write locked */ + " sub %[val], %[val], 1 \n" /* reader lock */ + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [rwlock] "r" (&(rw->counter)), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_read_trylock(arch_rwlock_t *rw) +{ + unsigned int val, got_it = 0; + + smp_mb(); + + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " brls %[val], %[WR_LOCKED], 4f\n" /* <= 0: already write locked, bail */ + " sub %[val], %[val], 1 \n" /* counter-- */ + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" /* retry if collided with someone */ + " mov %[got_it], 1 \n" + " \n" + "4: ; --- done --- \n" + + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + : [rwlock] "r" (&(rw->counter)), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_write_lock(arch_rwlock_t *rw) +{ + unsigned int val; + + smp_mb(); + + /* + * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__), + * deny writer. Otherwise if unlocked grant to writer + * Hence the claim that Linux rwlocks are unfair to writers. + * (can be starved for an indefinite time by readers). + * + * if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) { + * rw->counter = 0; + * ret = 1; + * } + */ + + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " brne %[val], %[UNLOCKED], 1b \n" /* while !UNLOCKED spin */ + " mov %[val], %[WR_LOCKED] \n" + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [rwlock] "r" (&(rw->counter)), + [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_write_trylock(arch_rwlock_t *rw) +{ + unsigned int val, got_it = 0; + + smp_mb(); + + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " brne %[val], %[UNLOCKED], 4f \n" /* !UNLOCKED, bail */ + " mov %[val], %[WR_LOCKED] \n" + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" /* retry if collided with someone */ + " mov %[got_it], 1 \n" + " \n" + "4: ; --- done --- \n" + + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + : [rwlock] "r" (&(rw->counter)), + [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_read_unlock(arch_rwlock_t *rw) +{ + unsigned int val; + + smp_mb(); + + /* + * rw->counter++; + */ + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " add %[val], %[val], 1 \n" + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [rwlock] "r" (&(rw->counter)) + : "memory", "cc"); + + smp_mb(); +} + +static inline void arch_write_unlock(arch_rwlock_t *rw) +{ + smp_mb(); + + rw->counter = __ARCH_RW_LOCK_UNLOCKED__; + + smp_mb(); +} + #else /* !CONFIG_ARC_HAS_LLSC */ static inline void arch_spin_lock(arch_spinlock_t *lock) @@ -148,23 +306,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) smp_mb(); } -#endif - /* * Read-write spinlocks, allowing multiple readers but only one writer. + * Unfair locking as Writers could be starved indefinitely by Reader(s) * * The spinlock itself is contained in @counter and access to it is * serialized with @lock_mutex. - * - * Unfair locking as Writers could be starved indefinitely by Reader(s) */ -/* Would read_trylock() succeed? */ -#define arch_read_can_lock(x) ((x)->counter > 0) - -/* Would write_trylock() succeed? */ -#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__) - /* 1 - lock taken successfully */ static inline int arch_read_trylock(arch_rwlock_t *rw) { @@ -235,6 +384,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) arch_spin_unlock(&(rw->lock_mutex)); } +#endif + +#define arch_read_can_lock(x) ((x)->counter > 0) +#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__) + #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) diff --git a/arch/arc/include/asm/spinlock_types.h b/arch/arc/include/asm/spinlock_types.h index 662627c..4e1ef5f 100644 --- a/arch/arc/include/asm/spinlock_types.h +++ b/arch/arc/include/asm/spinlock_types.h @@ -26,7 +26,9 @@ typedef struct { */ typedef struct { volatile unsigned int counter; +#ifndef CONFIG_ARC_HAS_LLSC arch_spinlock_t lock_mutex; +#endif } arch_rwlock_t; #define __ARCH_RW_LOCK_UNLOCKED__ 0x01000000 -- cgit v0.10.2 From e78fdfef84be13a5c2b8276e12203cdf24778596 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 14 Jul 2015 19:50:18 +0530 Subject: ARCv2: spinlock/rwlock/atomics: Delayed retry of failed SCOND with exponential backoff This is to workaround the llock/scond livelock HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping coherency transactions in the SCU. The exclusive line state keeps rotating among contenting cores leading to a never ending cycle. So break the cycle by deferring the retry of failed exclusive access (SCOND). The actual delay needed is function of number of contending cores as well as the unrelated coherency traffic from other cores. To keep the code simple, start off with small delay of 1 which would suffice most cases and in case of contention double the delay. Eventually the delay is sufficient such that the coherency pipeline is drained, thus a subsequent exclusive access would succeed. Link: http://lkml.kernel.org/r/1438612568-28265-1-git-send-email-vgupta@synopsys.com Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index a5fccdf..bd4670d 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -365,6 +365,11 @@ config ARC_HAS_LLSC default y depends on !ARC_CANT_LLSC +config ARC_STAR_9000923308 + bool "Workaround for llock/scond livelock" + default y + depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC + config ARC_HAS_SWAPE bool "Insn: SWAPE (endian-swap)" default y diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 3dd36c1..629dfd0 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -23,17 +23,51 @@ #define atomic_set(v, i) (((v)->counter) = (i)) +#ifdef CONFIG_ARC_STAR_9000923308 + +#define SCOND_FAIL_RETRY_VAR_DEF \ + unsigned int delay = 1, tmp; \ + +#define SCOND_FAIL_RETRY_ASM \ + " bz 4f \n" \ + " ; --- scond fail delay --- \n" \ + " mov %[tmp], %[delay] \n" /* tmp = delay */ \ + "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \ + " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \ + " asl.f %[delay], %[delay], 1 \n" /* delay *= 2 */ \ + " mov.z %[delay], 1 \n" /* handle overflow */ \ + " b 1b \n" /* start over */ \ + "4: ; --- success --- \n" \ + +#define SCOND_FAIL_RETRY_VARS \ + ,[delay] "+&r" (delay),[tmp] "=&r" (tmp) \ + +#else /* !CONFIG_ARC_STAR_9000923308 */ + +#define SCOND_FAIL_RETRY_VAR_DEF + +#define SCOND_FAIL_RETRY_ASM \ + " bnz 1b \n" \ + +#define SCOND_FAIL_RETRY_VARS + +#endif + #define ATOMIC_OP(op, c_op, asm_op) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ - unsigned int val; \ + unsigned int val; \ + SCOND_FAIL_RETRY_VAR_DEF \ \ __asm__ __volatile__( \ "1: llock %[val], [%[ctr]] \n" \ " " #asm_op " %[val], %[val], %[i] \n" \ " scond %[val], [%[ctr]] \n" \ - " bnz 1b \n" \ + " \n" \ + SCOND_FAIL_RETRY_ASM \ + \ : [val] "=&r" (val) /* Early clobber to prevent reg reuse */ \ + SCOND_FAIL_RETRY_VARS \ : [ctr] "r" (&v->counter), /* Not "m": llock only supports reg direct addr mode */ \ [i] "ir" (i) \ : "cc"); \ @@ -42,7 +76,8 @@ static inline void atomic_##op(int i, atomic_t *v) \ #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ - unsigned int val; \ + unsigned int val; \ + SCOND_FAIL_RETRY_VAR_DEF \ \ /* \ * Explicit full memory barrier needed before/after as \ @@ -54,8 +89,11 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ "1: llock %[val], [%[ctr]] \n" \ " " #asm_op " %[val], %[val], %[i] \n" \ " scond %[val], [%[ctr]] \n" \ - " bnz 1b \n" \ + " \n" \ + SCOND_FAIL_RETRY_ASM \ + \ : [val] "=&r" (val) \ + SCOND_FAIL_RETRY_VARS \ : [ctr] "r" (&v->counter), \ [i] "ir" (i) \ : "cc"); \ @@ -142,6 +180,9 @@ ATOMIC_OP(and, &=, and) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP +#undef SCOND_FAIL_RETRY_VAR_DEF +#undef SCOND_FAIL_RETRY_ASM +#undef SCOND_FAIL_RETRY_VARS /** * __atomic_add_unless - add unless the number is a given value diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index 9fd5a02..2a84525 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -20,6 +20,11 @@ #ifdef CONFIG_ARC_HAS_LLSC +/* + * A normal LLOCK/SCOND based system, w/o need for livelock workaround + */ +#ifndef CONFIG_ARC_STAR_9000923308 + static inline void arch_spin_lock(arch_spinlock_t *lock) { unsigned int val; @@ -233,6 +238,294 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) smp_mb(); } +#else /* CONFIG_ARC_STAR_9000923308 */ + +/* + * HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping + * coherency transactions in the SCU. The exclusive line state keeps rotating + * among contenting cores leading to a never ending cycle. So break the cycle + * by deferring the retry of failed exclusive access (SCOND). The actual delay + * needed is function of number of contending cores as well as the unrelated + * coherency traffic from other cores. To keep the code simple, start off with + * small delay of 1 which would suffice most cases and in case of contention + * double the delay. Eventually the delay is sufficient such that the coherency + * pipeline is drained, thus a subsequent exclusive access would succeed. + */ + +#define SCOND_FAIL_RETRY_VAR_DEF \ + unsigned int delay, tmp; \ + +#define SCOND_FAIL_RETRY_ASM \ + " ; --- scond fail delay --- \n" \ + " mov %[tmp], %[delay] \n" /* tmp = delay */ \ + "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \ + " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \ + " asl.f %[delay], %[delay], 1 \n" /* delay *= 2 */ \ + " mov.z %[delay], 1 \n" /* handle overflow */ \ + " b 1b \n" /* start over */ \ + " \n" \ + "4: ; --- done --- \n" \ + +#define SCOND_FAIL_RETRY_VARS \ + ,[delay] "=&r" (delay), [tmp] "=&r" (tmp) \ + +static inline void arch_spin_lock(arch_spinlock_t *lock) +{ + unsigned int val; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[slock]] \n" + " breq %[val], %[LOCKED], 1b \n" /* spin while LOCKED */ + " scond %[LOCKED], [%[slock]] \n" /* acquire */ + " bz 4f \n" /* done */ + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val) + SCOND_FAIL_RETRY_VARS + : [slock] "r" (&(lock->slock)), + [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_spin_trylock(arch_spinlock_t *lock) +{ + unsigned int val, got_it = 0; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[slock]] \n" + " breq %[val], %[LOCKED], 4f \n" /* already LOCKED, just bail */ + " scond %[LOCKED], [%[slock]] \n" /* acquire */ + " bz.d 4f \n" + " mov.z %[got_it], 1 \n" /* got it */ + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + SCOND_FAIL_RETRY_VARS + : [slock] "r" (&(lock->slock)), + [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_spin_unlock(arch_spinlock_t *lock) +{ + smp_mb(); + + lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__; + + smp_mb(); +} + +/* + * Read-write spinlocks, allowing multiple readers but only one writer. + * Unfair locking as Writers could be starved indefinitely by Reader(s) + */ + +static inline void arch_read_lock(arch_rwlock_t *rw) +{ + unsigned int val; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + /* + * zero means writer holds the lock exclusively, deny Reader. + * Otherwise grant lock to first/subseq reader + * + * if (rw->counter > 0) { + * rw->counter--; + * ret = 1; + * } + */ + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[rwlock]] \n" + " brls %[val], %[WR_LOCKED], 1b\n" /* <= 0: spin while write locked */ + " sub %[val], %[val], 1 \n" /* reader lock */ + " scond %[val], [%[rwlock]] \n" + " bz 4f \n" /* done */ + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val) + SCOND_FAIL_RETRY_VARS + : [rwlock] "r" (&(rw->counter)), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_read_trylock(arch_rwlock_t *rw) +{ + unsigned int val, got_it = 0; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[rwlock]] \n" + " brls %[val], %[WR_LOCKED], 4f\n" /* <= 0: already write locked, bail */ + " sub %[val], %[val], 1 \n" /* counter-- */ + " scond %[val], [%[rwlock]] \n" + " bz.d 4f \n" + " mov.z %[got_it], 1 \n" /* got it */ + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + SCOND_FAIL_RETRY_VARS + : [rwlock] "r" (&(rw->counter)), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_write_lock(arch_rwlock_t *rw) +{ + unsigned int val; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + /* + * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__), + * deny writer. Otherwise if unlocked grant to writer + * Hence the claim that Linux rwlocks are unfair to writers. + * (can be starved for an indefinite time by readers). + * + * if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) { + * rw->counter = 0; + * ret = 1; + * } + */ + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[rwlock]] \n" + " brne %[val], %[UNLOCKED], 1b \n" /* while !UNLOCKED spin */ + " mov %[val], %[WR_LOCKED] \n" + " scond %[val], [%[rwlock]] \n" + " bz 4f \n" + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val) + SCOND_FAIL_RETRY_VARS + : [rwlock] "r" (&(rw->counter)), + [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); +} + +/* 1 - lock taken successfully */ +static inline int arch_write_trylock(arch_rwlock_t *rw) +{ + unsigned int val, got_it = 0; + SCOND_FAIL_RETRY_VAR_DEF; + + smp_mb(); + + __asm__ __volatile__( + "0: mov %[delay], 1 \n" + "1: llock %[val], [%[rwlock]] \n" + " brne %[val], %[UNLOCKED], 4f \n" /* !UNLOCKED, bail */ + " mov %[val], %[WR_LOCKED] \n" + " scond %[val], [%[rwlock]] \n" + " bz.d 4f \n" + " mov.z %[got_it], 1 \n" /* got it */ + " \n" + SCOND_FAIL_RETRY_ASM + + : [val] "=&r" (val), + [got_it] "+&r" (got_it) + SCOND_FAIL_RETRY_VARS + : [rwlock] "r" (&(rw->counter)), + [UNLOCKED] "ir" (__ARCH_RW_LOCK_UNLOCKED__), + [WR_LOCKED] "ir" (0) + : "memory", "cc"); + + smp_mb(); + + return got_it; +} + +static inline void arch_read_unlock(arch_rwlock_t *rw) +{ + unsigned int val; + + smp_mb(); + + /* + * rw->counter++; + */ + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " add %[val], %[val], 1 \n" + " scond %[val], [%[rwlock]] \n" + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [rwlock] "r" (&(rw->counter)) + : "memory", "cc"); + + smp_mb(); +} + +static inline void arch_write_unlock(arch_rwlock_t *rw) +{ + unsigned int val; + + smp_mb(); + + /* + * rw->counter = __ARCH_RW_LOCK_UNLOCKED__; + */ + __asm__ __volatile__( + "1: llock %[val], [%[rwlock]] \n" + " scond %[UNLOCKED], [%[rwlock]]\n" + " bnz 1b \n" + " \n" + : [val] "=&r" (val) + : [rwlock] "r" (&(rw->counter)), + [UNLOCKED] "r" (__ARCH_RW_LOCK_UNLOCKED__) + : "memory", "cc"); + + smp_mb(); +} + +#undef SCOND_FAIL_RETRY_VAR_DEF +#undef SCOND_FAIL_RETRY_ASM +#undef SCOND_FAIL_RETRY_VARS + +#endif /* CONFIG_ARC_STAR_9000923308 */ + #else /* !CONFIG_ARC_HAS_LLSC */ static inline void arch_spin_lock(arch_spinlock_t *lock) diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index f2f771b..cabde9d 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -336,6 +336,10 @@ static void arc_chk_core_config(void) pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n"); else if (!cpu->extn.fpu_dp && fpu_enabled) panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n"); + + if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic && + !IS_ENABLED(CONFIG_ARC_STAR_9000923308)) + panic("llock/scond livelock workaround missing\n"); } /* -- cgit v0.10.2 From b89aa12c177477e34caa722818536fb5d0bffd76 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 21 Jul 2015 18:46:53 +0300 Subject: ARCv2: spinlock/rwlock: Reset retry delay when starting a new spin-wait cycle The previous commit for delayed retry of SCOND needs some fine tuning for spin locks. The backoff from delayed retry in conjunction with spin looping of lock itself can potentially cause the delay counter to reach high values. So to provide fairness to any lock operation, after a lock "seems" available (i.e. just before first SCOND try0, reset the delay counter back to starting value of 1 Essentially reset delay to 1 for a new spin-wait-loop-acquire cycle. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index 2a84525..7071fc0 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -279,7 +279,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) __asm__ __volatile__( "0: mov %[delay], 1 \n" "1: llock %[val], [%[slock]] \n" - " breq %[val], %[LOCKED], 1b \n" /* spin while LOCKED */ + " breq %[val], %[LOCKED], 0b \n" /* spin while LOCKED */ " scond %[LOCKED], [%[slock]] \n" /* acquire */ " bz 4f \n" /* done */ " \n" @@ -358,7 +358,7 @@ static inline void arch_read_lock(arch_rwlock_t *rw) __asm__ __volatile__( "0: mov %[delay], 1 \n" "1: llock %[val], [%[rwlock]] \n" - " brls %[val], %[WR_LOCKED], 1b\n" /* <= 0: spin while write locked */ + " brls %[val], %[WR_LOCKED], 0b\n" /* <= 0: spin while write locked */ " sub %[val], %[val], 1 \n" /* reader lock */ " scond %[val], [%[rwlock]] \n" " bz 4f \n" /* done */ @@ -427,7 +427,7 @@ static inline void arch_write_lock(arch_rwlock_t *rw) __asm__ __volatile__( "0: mov %[delay], 1 \n" "1: llock %[val], [%[rwlock]] \n" - " brne %[val], %[UNLOCKED], 1b \n" /* while !UNLOCKED spin */ + " brne %[val], %[UNLOCKED], 0b \n" /* while !UNLOCKED spin */ " mov %[val], %[WR_LOCKED] \n" " scond %[val], [%[rwlock]] \n" " bz 4f \n" -- cgit v0.10.2 From 10e2eb878f3ca07ac2f05fa5ca5e6c4c9174a27a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 1 Aug 2015 12:14:33 +0200 Subject: udp: fix dst races with multicast early demux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multicast dst are not cached. They carry DST_NOCACHE. As mentioned in commit f8864972126899 ("ipv4: fix dst race in sk_dst_get()"), these dst need special care before caching them into a socket. Caching them is allowed only if their refcnt was not 0, ie we must use atomic_inc_not_zero() Also, we must use READ_ONCE() to fetch sk->sk_rx_dst, as mentioned in commit d0c294c53a771 ("tcp: prevent fetching dst twice in early demux code") Fixes: 421b3885bf6d ("udp: ipv4: Add udp early demux") Tested-by: Gregory Hoggarth Signed-off-by: Eric Dumazet Reported-by: Gregory Hoggarth Reported-by: Alex Gartrell Cc: Michal Kubeček Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 83aa604..1b8c5ba 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1995,12 +1995,19 @@ void udp_v4_early_demux(struct sk_buff *skb) skb->sk = sk; skb->destructor = sock_efree; - dst = sk->sk_rx_dst; + dst = READ_ONCE(sk->sk_rx_dst); if (dst) dst = dst_check(dst, 0); - if (dst) - skb_dst_set_noref(skb, dst); + if (dst) { + /* DST_NOCACHE can not be used without taking a reference */ + if (dst->flags & DST_NOCACHE) { + if (likely(atomic_inc_not_zero(&dst->__refcnt))) + skb_dst_set(skb, dst); + } else { + skb_dst_set_noref(skb, dst); + } + } } int udp_rcv(struct sk_buff *skb) -- cgit v0.10.2 From 2475b22526d70234ecfe4a1ff88aed69badefba9 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Mon, 3 Aug 2015 15:38:03 +0100 Subject: xen-netback: Allocate fraglist early to avoid complex rollback Determine if a fraglist is needed in the tx path, and allocate it if necessary before setting up the copy and map operations. Otherwise, undoing the copy and map operations is tricky. This fixes a use-after-free: if allocating the fraglist failed, the copy and map operations that had been set up were still executed, writing over the data area of a freed skb. Signed-off-by: Ross Lagerwall Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 7d50711..1b406e7 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -810,23 +810,17 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue, struct sk_buff *skb, struct xen_netif_tx_request *txp, - struct gnttab_map_grant_ref *gop) + struct gnttab_map_grant_ref *gop, + unsigned int frag_overflow, + struct sk_buff *nskb) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; int start; pending_ring_idx_t index; - unsigned int nr_slots, frag_overflow = 0; + unsigned int nr_slots; - /* At this point shinfo->nr_frags is in fact the number of - * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. - */ - if (shinfo->nr_frags > MAX_SKB_FRAGS) { - frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS; - BUG_ON(frag_overflow > MAX_SKB_FRAGS); - shinfo->nr_frags = MAX_SKB_FRAGS; - } nr_slots = shinfo->nr_frags; /* Skip first skb fragment if it is on same page as header fragment. */ @@ -841,13 +835,6 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que } if (frag_overflow) { - struct sk_buff *nskb = xenvif_alloc_skb(0); - if (unlikely(nskb == NULL)) { - if (net_ratelimit()) - netdev_err(queue->vif->dev, - "Can't allocate the frag_list skb.\n"); - return NULL; - } shinfo = skb_shinfo(nskb); frags = shinfo->frags; @@ -1175,9 +1162,10 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, unsigned *copy_ops, unsigned *map_ops) { - struct gnttab_map_grant_ref *gop = queue->tx_map_ops, *request_gop; - struct sk_buff *skb; + struct gnttab_map_grant_ref *gop = queue->tx_map_ops; + struct sk_buff *skb, *nskb; int ret; + unsigned int frag_overflow; while (skb_queue_len(&queue->tx_queue) < budget) { struct xen_netif_tx_request txreq; @@ -1265,6 +1253,29 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, break; } + skb_shinfo(skb)->nr_frags = ret; + if (data_len < txreq.size) + skb_shinfo(skb)->nr_frags++; + /* At this point shinfo->nr_frags is in fact the number of + * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. + */ + frag_overflow = 0; + nskb = NULL; + if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) { + frag_overflow = skb_shinfo(skb)->nr_frags - MAX_SKB_FRAGS; + BUG_ON(frag_overflow > MAX_SKB_FRAGS); + skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS; + nskb = xenvif_alloc_skb(0); + if (unlikely(nskb == NULL)) { + kfree_skb(skb); + xenvif_tx_err(queue, &txreq, idx); + if (net_ratelimit()) + netdev_err(queue->vif->dev, + "Can't allocate the frag_list skb.\n"); + break; + } + } + if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { struct xen_netif_extra_info *gso; gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; @@ -1272,6 +1283,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, if (xenvif_set_skb_gso(queue->vif, skb, gso)) { /* Failure in xenvif_set_skb_gso is fatal. */ kfree_skb(skb); + kfree_skb(nskb); break; } } @@ -1294,9 +1306,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, (*copy_ops)++; - skb_shinfo(skb)->nr_frags = ret; if (data_len < txreq.size) { - skb_shinfo(skb)->nr_frags++; frag_set_pending_idx(&skb_shinfo(skb)->frags[0], pending_idx); xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop); @@ -1310,13 +1320,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, queue->pending_cons++; - request_gop = xenvif_get_requests(queue, skb, txfrags, gop); - if (request_gop == NULL) { - kfree_skb(skb); - xenvif_tx_err(queue, &txreq, idx); - break; - } - gop = request_gop; + gop = xenvif_get_requests(queue, skb, txfrags, gop, + frag_overflow, nskb); __skb_queue_tail(&queue->tx_queue, skb); -- cgit v0.10.2 From fed66e2cdd4f127a43fd11b8d92a99bdd429528c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 11 Jun 2015 10:32:01 +0200 Subject: perf: Fix fasync handling on inherited events Vince reported that the fasync signal stuff doesn't work proper for inherited events. So fix that. Installing fasync allocates memory and sets filp->f_flags |= FASYNC, which upon the demise of the file descriptor ensures the allocation is freed and state is updated. Now for perf, we can have the events stick around for a while after the original FD is dead because of references from child events. So we cannot copy the fasync pointer around. We can however consistently use the parent's fasync, as that will be updated. Reported-and-Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Arnaldo Carvalho deMelo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: eranian@google.com Link: http://lkml.kernel.org/r/1434011521.1495.71.camel@twins Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 10d076b..072b8a6 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4740,12 +4740,20 @@ static const struct file_operations perf_fops = { * to user-space before waking everybody up. */ +static inline struct fasync_struct **perf_event_fasync(struct perf_event *event) +{ + /* only the parent has fasync state */ + if (event->parent) + event = event->parent; + return &event->fasync; +} + void perf_event_wakeup(struct perf_event *event) { ring_buffer_wakeup(event); if (event->pending_kill) { - kill_fasync(&event->fasync, SIGIO, event->pending_kill); + kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill); event->pending_kill = 0; } } @@ -6124,7 +6132,7 @@ static int __perf_event_overflow(struct perf_event *event, else perf_event_output(event, data, regs); - if (event->fasync && event->pending_kill) { + if (*perf_event_fasync(event) && event->pending_kill) { event->pending_wakeup = 1; irq_work_queue(&event->pending); } -- cgit v0.10.2 From 3b8a684bd6cbc13dfd21ca41814c304e9f27ec7f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Aug 2015 17:24:08 +0200 Subject: drm/atomic-helper: Add an atomice best_encoder callback With legacy helpers all the routing was already set up when calling best_encoder and so could be inspected. But with atomic it's staged, hence we need a new atomic compliant callback for drivers which need to inspect the requested state and can't just decided the best encoder statically. This is needed to fix up i915 dp mst where we need to pick the right encoder depending upon the requested CRTC for the connector. v2: Don't forget to amend the kerneldoc Cc: Chris Wilson Cc: Linus Torvalds Cc: Theodore Ts'o Acked-by: Thierry Reding Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aac2122..8694ca9 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -196,7 +196,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) } funcs = connector->helper_private; - new_encoder = funcs->best_encoder(connector); + + if (funcs->atomic_best_encoder) + new_encoder = funcs->atomic_best_encoder(connector, + connector_state); + else + new_encoder = funcs->best_encoder(connector); if (!new_encoder) { DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n", diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index c8fc187..918aa68 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -168,6 +168,7 @@ struct drm_encoder_helper_funcs { * @get_modes: get mode list for this connector * @mode_valid: is this mode valid on the given connector? (optional) * @best_encoder: return the preferred encoder for this connector + * @atomic_best_encoder: atomic version of @best_encoder * * The helper operations are called by the mid-layer CRTC helper. */ @@ -176,6 +177,8 @@ struct drm_connector_helper_funcs { enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); struct drm_encoder *(*best_encoder)(struct drm_connector *connector); + struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector, + struct drm_connector_state *connector_state); }; extern void drm_helper_disable_unused_functions(struct drm_device *dev); -- cgit v0.10.2 From 459485ad3513bce12a3773f801e4647445062d9e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Aug 2015 17:24:09 +0200 Subject: drm/i915: Fixup dp mst encoder selection In commit 8c7b5ccb729870e606321b3703e2c2e698c49a95 Author: Ander Conselvan de Oliveira Date: Tue Apr 21 17:13:19 2015 +0300 drm/i915: Use atomic helpers for computing changed flags we've switched over to the atomic version to compute the crtc->encoder->connector routing from the i915 variant. That one relies upon the ->best_encoder callback, but the i915-private version relied upon intel_find_encoder. Which didn't matter except for dp mst, where the encoder depends upon the selected crtc. Fix this functional bug by implemented a correct atomic-state based encoder selector for dp mst. Note that we can't get rid of the legacy best_encoder callback since the fbdev emulation uses that still. That means it's incorrect there still, but that's been the case ever since i915 dp mst support was merged so not a regression. Best to fix that by converting fbdev over to atomic too. Cc: Chris Wilson Cc: Linus Torvalds Cc: Theodore Ts'o Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 6e4cc53..600afdb 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -357,6 +357,16 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, return MODE_OK; } +static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_dp *intel_dp = intel_connector->mst_port; + struct intel_crtc *crtc = to_intel_crtc(state->crtc); + + return &intel_dp->mst_encoders[crtc->pipe]->base.base; +} + static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); @@ -367,6 +377,7 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { .get_modes = intel_dp_mst_get_modes, .mode_valid = intel_dp_mst_mode_valid, + .atomic_best_encoder = intel_mst_atomic_best_encoder, .best_encoder = intel_mst_best_encoder, }; -- cgit v0.10.2 From 42639ba554655c280ae6cb72df0522b1201f2961 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Aug 2015 17:24:10 +0200 Subject: drm/dp-mst: Remove debug WARN_ON Apparently been in there since forever and fairly easy to hit when hotplugging really fast. I can do that since my mst hub has a manual button to flick the hpd line for reprobing. The resulting WARNING spam isn't pretty. Cc: Dave Airlie Cc: stable@vger.kernel.org Reviewed-by: Thierry Reding Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 778bbb6..b0487c9 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1294,7 +1294,6 @@ retry: goto retry; } DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret); - WARN(1, "fail\n"); return -EIO; } -- cgit v0.10.2 From 6ea76f3cade4734e73e3da842005820558b8b828 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Aug 2015 17:24:11 +0200 Subject: drm/atomic-helpers: Make encoder picking more robust We've had a few issues with atomic where subtle bugs in the encoder picking logic lead to accidental self-stealing of the encoder, resulting in a NULL connector_state->crtc in update_connector_routing and subsequent. Linus applied some duct-tape for an mst regression in commit 27667f4744fc5a0f3e50910e78740bac5670d18b Author: Linus Torvalds Date: Wed Jul 29 22:18:16 2015 -0700 i915: temporary fix for DP MST docking station NULL pointer dereference But that was incomplete (the code will still oops when debuggin is enabled) and mangled the state even further. So instead WARN and bail out as the more future-proof option. Cc: Theodore Ts'o Cc: Linus Torvalds Reviewed-by: Thierry Reding Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8694ca9..9dcc728 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -234,13 +234,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) } } + if (WARN_ON(!connector_state->crtc)) + return -EINVAL; + connector_state->best_encoder = new_encoder; - if (connector_state->crtc) { - idx = drm_crtc_index(connector_state->crtc); + idx = drm_crtc_index(connector_state->crtc); - crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; - } + crtc_state = state->crtc_states[idx]; + crtc_state->mode_changed = true; DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", connector->base.id, -- cgit v0.10.2 From 56113f6e6f8d57d3c184544c6421422558a9988e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 3 Aug 2015 10:49:29 -0700 Subject: ASoC: atmel_ssc_dai: Correct misuse of 0x% Correct misuse of 0x%d in logging message. Signed-off-by: Joe Perches Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 841d059..ba8def5 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -290,7 +290,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, int dir, dir_mask; int ret; - pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", + pr_debug("atmel_ssc_startup: SSC_SR=0x%x\n", ssc_readl(ssc_p->ssc->regs, SR)); /* Enable PMC peripheral clock for this SSC */ -- cgit v0.10.2 From 0621809e37936e7c2b3eac9165cf2aad7f9189eb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Aug 2015 14:57:30 +0900 Subject: HID: hid-input: Fix accessing freed memory during device disconnect During unbinding the driver was dereferencing a pointer to memory already freed by power_supply_unregister(). Driver was freeing its internal description of battery through pointers stored in power_supply structure. However, because the core owns the power supply instance, after calling power_supply_unregister() this memory is freed and the driver cannot access these members. Fix this by storing the pointer to internal description of battery in a local variable before calling power_supply_unregister(), so the pointer remains valid. Signed-off-by: Krzysztof Kozlowski Reported-by: H.J. Lu Fixes: 297d716f6260 ("power_supply: Change ownership from driver to core") Cc: Reviewed-by: Dmitry Torokhov Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3511bbab..e3c6364 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -462,12 +462,15 @@ out: static void hidinput_cleanup_battery(struct hid_device *dev) { + const struct power_supply_desc *psy_desc; + if (!dev->battery) return; + psy_desc = dev->battery->desc; power_supply_unregister(dev->battery); - kfree(dev->battery->desc->name); - kfree(dev->battery->desc); + kfree(psy_desc->name); + kfree(psy_desc); dev->battery = NULL; } #else /* !CONFIG_HID_BATTERY_STRENGTH */ -- cgit v0.10.2 From fcdf31a7c162de0c93a2bee51df4688ab0a348f8 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Fri, 31 Jul 2015 14:30:42 +0100 Subject: xen/events/fifo: Handle linked events when closing a port An event channel bound to a CPU that was offlined may still be linked on that CPU's queue. If this event channel is closed and reused, subsequent events will be lost because the event channel is never unlinked and thus cannot be linked onto the correct queue. When a channel is closed and the event is still linked into a queue, ensure that it is unlinked before completing. If the CPU to which the event channel bound is online, spin until the event is handled by that CPU. If that CPU is offline, it can't handle the event, so clear the event queue during the close, dropping the events. This fixes the missing interrupts (and subsequent disk stalls etc.) when offlining a CPU. Signed-off-by: Ross Lagerwall Cc: Signed-off-by: David Vrabel diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 96093ae..1495ecc 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -452,10 +452,12 @@ static void xen_free_irq(unsigned irq) irq_free_desc(irq); } -static void xen_evtchn_close(unsigned int port) +static void xen_evtchn_close(unsigned int port, unsigned int cpu) { struct evtchn_close close; + xen_evtchn_op_close(port, cpu); + close.port = port; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) BUG(); @@ -544,7 +546,7 @@ out: err: pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc); - xen_evtchn_close(evtchn); + xen_evtchn_close(evtchn, NR_CPUS); return 0; } @@ -565,7 +567,7 @@ static void shutdown_pirq(struct irq_data *data) return; mask_evtchn(evtchn); - xen_evtchn_close(evtchn); + xen_evtchn_close(evtchn, cpu_from_evtchn(evtchn)); xen_irq_info_cleanup(info); } @@ -609,7 +611,7 @@ static void __unbind_from_irq(unsigned int irq) if (VALID_EVTCHN(evtchn)) { unsigned int cpu = cpu_from_irq(irq); - xen_evtchn_close(evtchn); + xen_evtchn_close(evtchn, cpu); switch (type_from_irq(irq)) { case IRQT_VIRQ: diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index ed673e1..6df8aac 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -255,6 +255,12 @@ static void evtchn_fifo_unmask(unsigned port) } } +static bool evtchn_fifo_is_linked(unsigned port) +{ + event_word_t *word = event_word_from_port(port); + return sync_test_bit(EVTCHN_FIFO_BIT(LINKED, word), BM(word)); +} + static uint32_t clear_linked(volatile event_word_t *word) { event_word_t new, old, w; @@ -281,7 +287,8 @@ static void handle_irq_for_port(unsigned port) static void consume_one_event(unsigned cpu, struct evtchn_fifo_control_block *control_block, - unsigned priority, unsigned long *ready) + unsigned priority, unsigned long *ready, + bool drop) { struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); uint32_t head; @@ -313,13 +320,15 @@ static void consume_one_event(unsigned cpu, if (head == 0) clear_bit(priority, ready); - if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) - handle_irq_for_port(port); + if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) { + if (likely(!drop)) + handle_irq_for_port(port); + } q->head[priority] = head; } -static void evtchn_fifo_handle_events(unsigned cpu) +static void __evtchn_fifo_handle_events(unsigned cpu, bool drop) { struct evtchn_fifo_control_block *control_block; unsigned long ready; @@ -331,11 +340,16 @@ static void evtchn_fifo_handle_events(unsigned cpu) while (ready) { q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES); - consume_one_event(cpu, control_block, q, &ready); + consume_one_event(cpu, control_block, q, &ready, drop); ready |= xchg(&control_block->ready, 0); } } +static void evtchn_fifo_handle_events(unsigned cpu) +{ + __evtchn_fifo_handle_events(cpu, false); +} + static void evtchn_fifo_resume(void) { unsigned cpu; @@ -371,6 +385,26 @@ static void evtchn_fifo_resume(void) event_array_pages = 0; } +static void evtchn_fifo_close(unsigned port, unsigned int cpu) +{ + if (cpu == NR_CPUS) + return; + + get_online_cpus(); + if (cpu_online(cpu)) { + if (WARN_ON(irqs_disabled())) + goto out; + + while (evtchn_fifo_is_linked(port)) + cpu_relax(); + } else { + __evtchn_fifo_handle_events(cpu, true); + } + +out: + put_online_cpus(); +} + static const struct evtchn_ops evtchn_ops_fifo = { .max_channels = evtchn_fifo_max_channels, .nr_channels = evtchn_fifo_nr_channels, @@ -384,6 +418,7 @@ static const struct evtchn_ops evtchn_ops_fifo = { .unmask = evtchn_fifo_unmask, .handle_events = evtchn_fifo_handle_events, .resume = evtchn_fifo_resume, + .close = evtchn_fifo_close, }; static int evtchn_fifo_alloc_control_block(unsigned cpu) diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h index 50c2050a..d18e123 100644 --- a/drivers/xen/events/events_internal.h +++ b/drivers/xen/events/events_internal.h @@ -68,6 +68,7 @@ struct evtchn_ops { bool (*test_and_set_mask)(unsigned port); void (*mask)(unsigned port); void (*unmask)(unsigned port); + void (*close)(unsigned port, unsigned cpu); void (*handle_events)(unsigned cpu); void (*resume)(void); @@ -145,6 +146,12 @@ static inline void xen_evtchn_resume(void) evtchn_ops->resume(); } +static inline void xen_evtchn_op_close(unsigned port, unsigned cpu) +{ + if (evtchn_ops->close) + return evtchn_ops->close(port, cpu); +} + void xen_evtchn_2l_init(void); int xen_evtchn_fifo_init(void); -- cgit v0.10.2 From 257d5d9a9f19ee6c6801589c74791d5422c374e9 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 17 Jul 2015 16:47:23 +0300 Subject: ARM: dts: dra7: Add syscon-pllreset syscon to SATA PHY This register is required to be passed to the SATA PHY driver to workaround errata i783 (SATA Lockup After SATA DPLL Unlock/Relock). Signed-off-by: Roger Quadros Acked-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 8f1e25b..4a0718c 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1140,6 +1140,7 @@ ctrl-module = <&omap_control_sata>; clocks = <&sys_clkin1>, <&sata_ref_clk>; clock-names = "sysclk", "refclk"; + syscon-pllreset = <&scm_conf 0x3fc>; #phy-cells = <0>; }; -- cgit v0.10.2 From f202a666e933f3c7557126d63833a6a3b577ac15 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 16 Jun 2015 21:06:24 +0200 Subject: batman-adv: avoid DAT to mess up LAN state When a node running DAT receives an ARP request from the LAN for the first time, it is likely that this node will request the ARP entry through the distributed ARP table (DAT) in the mesh. Once a DAT reply is received the asking node must check if the MAC address for which the IP address has been asked is local. If it is, the node must drop the ARP reply bceause the client should have replied on its own locally. Forwarding this reply means fooling any L2 bridge (e.g. Ethernet switches) lying between the batman-adv node and the LAN. This happens because the L2 bridge will think that the client sending the ARP reply lies somewhere in the mesh, while this node is sitting in the same LAN. Reported-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index fb54e6a..6d0b471 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, * @bat_priv: the bat priv with all the soft interface information * @skb: packet to check * @hdr_size: size of the encapsulation header + * + * Returns true if the packet was snooped and consumed by DAT. False if the + * packet has to be delivered to the interface */ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) @@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, uint16_t type; __be32 ip_src, ip_dst; uint8_t *hw_src, *hw_dst; - bool ret = false; + bool dropped = false; unsigned short vid; if (!atomic_read(&bat_priv->distributed_arp_table)) @@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, /* if this REPLY is directed to a client of mine, let's deliver the * packet to the interface */ - ret = !batadv_is_my_client(bat_priv, hw_dst, vid); + dropped = !batadv_is_my_client(bat_priv, hw_dst, vid); + + /* if this REPLY is sent on behalf of a client of mine, let's drop the + * packet because the client will reply by itself + */ + dropped |= batadv_is_my_client(bat_priv, hw_src, vid); out: - if (ret) + if (dropped) kfree_skb(skb); - /* if ret == false -> packet has to be delivered to the interface */ - return ret; + /* if dropped == false -> deliver to the interface */ + return dropped; } /** -- cgit v0.10.2 From 354136bcc3c4f40a2813bba8f57ca5267d812d15 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 9 Jun 2015 21:24:36 +0800 Subject: batman-adv: fix kernel crash due to missing NULL checks batadv_softif_vlan_get() may return NULL which has to be verified by the caller. Fixes: 35df3b298fc8 ("batman-adv: fix TT VLAN inconsistency on VLAN re-add") Reported-by: Ryan Thompson Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index c002961..a2fc843 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -479,6 +479,9 @@ out: */ void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan) { + if (!vlan) + return; + if (atomic_dec_and_test(&vlan->refcount)) { spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); hlist_del_rcu(&vlan->list); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index b482495..38b83c5 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -594,6 +594,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, /* increase the refcounter of the related vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); + if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", + addr, BATADV_PRINT_VID(vid))) + goto out; batadv_dbg(BATADV_DBG_TT, bat_priv, "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", @@ -1066,6 +1069,9 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, /* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); + if (!vlan) + goto out; + batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan); @@ -1166,8 +1172,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) /* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, tt_common_entry->vid); - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + if (vlan) { + batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_free_ref(vlan); + } batadv_tt_local_entry_free_ref(tt_local); } @@ -3207,8 +3215,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) /* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + if (vlan) { + batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_free_ref(vlan); + } batadv_tt_local_entry_free_ref(tt_local); } -- cgit v0.10.2 From ef72706a0543d0c3a5ab29bd6378fdfb368118d9 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 17 Jun 2015 20:01:36 +0800 Subject: batman-adv: protect tt_local_entry from concurrent delete events The tt_local_entry deletion performed in batadv_tt_local_remove() was neither protecting against simultaneous deletes nor checking whether the element was still part of the list before calling hlist_del_rcu(). Replacing the hlist_del_rcu() call with batadv_hash_remove() provides adequate protection via hash spinlocks as well as an is-element-still-in-hash check to avoid 'blind' hash removal. Fixes: 068ee6e204e1 ("batman-adv: roaming handling mechanism redesign") Reported-by: alfonsname@web.de Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 38b83c5..5e953297 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1037,6 +1037,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry; uint16_t flags, curr_flags = BATADV_NO_FLAGS; struct batadv_softif_vlan *vlan; + void *tt_entry_exists; tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) @@ -1064,7 +1065,15 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, * immediately purge it */ batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); - hlist_del_rcu(&tt_local_entry->common.hash_entry); + + tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, + batadv_compare_tt, + batadv_choose_tt, + &tt_local_entry->common); + if (!tt_entry_exists) + goto out; + + /* extra call to free the local tt entry */ batadv_tt_local_entry_free_ref(tt_local_entry); /* decrease the reference held for this vlan */ -- cgit v0.10.2 From 27a4d5efd417b6ef3190e9af357715532d4617a3 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 24 Jun 2015 14:50:19 +0200 Subject: batman-adv: initialize up/down values when adding a gateway Without this initialization, gateways which actually announce up/down bandwidth of 0/0 could be added. If these nodes get purged via _batadv_purge_orig() later, the gw_node structure does not get removed since batadv_gw_node_delete() updates the gw_node with up/down bandwidth of 0/0, and the updating function then discards the change and does not free gw_node. This results in leaking the gw_node structures, which references other structures: gw_node -> orig_node -> orig_node_ifinfo -> hardif. When removing the interface later, the open reference on the hardif may cause hangs with the infamous "unregister_netdevice: waiting for mesh1 to become free. Usage count = 1" message. Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index bb015862..cffa92d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, INIT_HLIST_NODE(&gw_node->list); gw_node->orig_node = orig_node; + gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); + gw_node->bandwidth_up = ntohl(gateway->bandwidth_up); atomic_set(&gw_node->refcount, 1); spin_lock_bh(&bat_priv->gw.list_lock); -- cgit v0.10.2 From aa65fa35ba6b589a12a6025739c2d935dd743b5a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 4 Aug 2015 23:23:50 -0400 Subject: may_follow_link() should use nd->inode Now that we can get there in RCU mode, we shouldn't play with nd->path.dentry->d_inode - it's not guaranteed to be stable. Use nd->inode instead. Reported-by: Hugh Dickins Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index fbbcf09..1c2105e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -879,7 +879,7 @@ static inline int may_follow_link(struct nameidata *nd) return 0; /* Allowed if parent directory not sticky and world-writable. */ - parent = nd->path.dentry->d_inode; + parent = nd->inode; if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH)) return 0; -- cgit v0.10.2 From fb1de5a4c825a389f054cc3803e06116d2fbdc7e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 1 Aug 2015 07:01:24 -0700 Subject: staging: lustre: Include unaligned.h instead of access_ok.h Including access_ok.h causes the ia64:allmodconfig build (and maybe others) to fail with include/linux/unaligned/le_struct.h:6:19: error: redefinition of 'get_unaligned_le16' include/linux/unaligned/access_ok.h:7:19: note: previous definition of 'get_unaligned_le16' was here include/linux/unaligned/le_struct.h:26:20: error: redefinition of 'put_unaligned_le32' include/linux/unaligned/access_ok.h:42:20: note: previous definition of 'put_unaligned_le32' was here include/linux/unaligned/le_struct.h:31:20: error: redefinition of 'put_unaligned_le64' include/linux/unaligned/access_ok.h:47:20: note: previous definition of 'put_unaligned_le64' was here Include unaligned.h instead and leave it up to the architecture to decide how to implement unaligned accesses. Fixes: 8c4f136497315 ("Staging: lustre: Use put_unaligned_le64") Cc: Vaishali Thakkar Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c index 9c934e6..c61add4 100644 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ b/drivers/staging/lustre/lustre/obdclass/debug.c @@ -40,7 +40,7 @@ #define DEBUG_SUBSYSTEM D_OTHER -#include +#include #include "../include/obd_support.h" #include "../include/lustre_debug.h" -- cgit v0.10.2 From 87ce62802f7a3553234ebf1ae7cd52c8bf272fb9 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 5 Aug 2015 11:12:00 +0530 Subject: ARC: Make pt_regs regs unsigned KGDB fails to build after f51e2f191112 ("ARC: make sure instruction_pointer() returns unsigned value") The hack to force one specific reg to unsigned backfired. There's no reason to keep the regs signed after all. | CC arch/arc/kernel/kgdb.o |../arch/arc/kernel/kgdb.c: In function 'kgdb_trap': | ../arch/arc/kernel/kgdb.c:180:29: error: lvalue required as left operand of assignment | instruction_pointer(regs) -= BREAK_INSTR_SIZE; Reported-by: Yuriy Kolerov Fixes: f51e2f191112 ("ARC: make sure instruction_pointer() returns unsigned value") Cc: Alexey Brodkin Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 91694ec..69095da 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -20,20 +20,20 @@ struct pt_regs { /* Real registers */ - long bta; /* bta_l1, bta_l2, erbta */ + unsigned long bta; /* bta_l1, bta_l2, erbta */ - long lp_start, lp_end, lp_count; + unsigned long lp_start, lp_end, lp_count; - long status32; /* status32_l1, status32_l2, erstatus */ - long ret; /* ilink1, ilink2 or eret */ - long blink; - long fp; - long r26; /* gp */ + unsigned long status32; /* status32_l1, status32_l2, erstatus */ + unsigned long ret; /* ilink1, ilink2 or eret */ + unsigned long blink; + unsigned long fp; + unsigned long r26; /* gp */ - long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; + unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; - long sp; /* user/kernel sp depending on where we came from */ - long orig_r0; + unsigned long sp; /* User/Kernel depending on where we came from */ + unsigned long orig_r0; /* * To distinguish bet excp, syscall, irq @@ -55,13 +55,13 @@ struct pt_regs { unsigned long event; }; - long user_r25; + unsigned long user_r25; }; #else struct pt_regs { - long orig_r0; + unsigned long orig_r0; union { struct { @@ -76,26 +76,26 @@ struct pt_regs { unsigned long event; }; - long bta; /* bta_l1, bta_l2, erbta */ + unsigned long bta; /* bta_l1, bta_l2, erbta */ - long user_r25; + unsigned long user_r25; - long r26; /* gp */ - long fp; - long sp; /* user/kernel sp depending on where we came from */ + unsigned long r26; /* gp */ + unsigned long fp; + unsigned long sp; /* user/kernel sp depending on where we came from */ - long r12; + unsigned long r12; /*------- Below list auto saved by h/w -----------*/ - long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; + unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; - long blink; - long lp_end, lp_start, lp_count; + unsigned long blink; + unsigned long lp_end, lp_start, lp_count; - long ei, ldi, jli; + unsigned long ei, ldi, jli; - long ret; - long status32; + unsigned long ret; + unsigned long status32; }; #endif @@ -103,10 +103,10 @@ struct pt_regs { /* Callee saved registers - need to be saved only when you are scheduled out */ struct callee_regs { - long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13; + unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13; }; -#define instruction_pointer(regs) (unsigned long)((regs)->ret) +#define instruction_pointer(regs) ((regs)->ret) #define profile_pc(regs) instruction_pointer(regs) /* return 1 if user mode or 0 if kernel mode */ @@ -142,7 +142,7 @@ struct callee_regs { static inline long regs_return_value(struct pt_regs *regs) { - return regs->r0; + return (long)regs->r0; } #endif /* !__ASSEMBLY__ */ diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h index 76a7739..0b3ef63 100644 --- a/arch/arc/include/uapi/asm/ptrace.h +++ b/arch/arc/include/uapi/asm/ptrace.h @@ -32,20 +32,20 @@ */ struct user_regs_struct { - long pad; + unsigned long pad; struct { - long bta, lp_start, lp_end, lp_count; - long status32, ret, blink, fp, gp; - long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; - long sp; + unsigned long bta, lp_start, lp_end, lp_count; + unsigned long status32, ret, blink, fp, gp; + unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0; + unsigned long sp; } scratch; - long pad2; + unsigned long pad2; struct { - long r25, r24, r23, r22, r21, r20; - long r19, r18, r17, r16, r15, r14, r13; + unsigned long r25, r24, r23, r22, r21, r20; + unsigned long r19, r18, r17, r16, r15, r14, r13; } callee; - long efa; /* break pt addr, for break points in delay slots */ - long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */ + unsigned long efa; /* break pt addr, for break points in delay slots */ + unsigned long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */ }; #endif /* !__ASSEMBLY__ */ -- cgit v0.10.2 From ecf5fc6e9654cd7a268c782a523f072b2f1959f9 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 4 Aug 2015 14:36:58 -0700 Subject: mm, vmscan: Do not wait for page writeback for GFP_NOFS allocations Nikolay has reported a hang when a memcg reclaim got stuck with the following backtrace: PID: 18308 TASK: ffff883d7c9b0a30 CPU: 1 COMMAND: "rsync" #0 __schedule at ffffffff815ab152 #1 schedule at ffffffff815ab76e #2 schedule_timeout at ffffffff815ae5e5 #3 io_schedule_timeout at ffffffff815aad6a #4 bit_wait_io at ffffffff815abfc6 #5 __wait_on_bit at ffffffff815abda5 #6 wait_on_page_bit at ffffffff8111fd4f #7 shrink_page_list at ffffffff81135445 #8 shrink_inactive_list at ffffffff81135845 #9 shrink_lruvec at ffffffff81135ead #10 shrink_zone at ffffffff811360c3 #11 shrink_zones at ffffffff81136eff #12 do_try_to_free_pages at ffffffff8113712f #13 try_to_free_mem_cgroup_pages at ffffffff811372be #14 try_charge at ffffffff81189423 #15 mem_cgroup_try_charge at ffffffff8118c6f5 #16 __add_to_page_cache_locked at ffffffff8112137d #17 add_to_page_cache_lru at ffffffff81121618 #18 pagecache_get_page at ffffffff8112170b #19 grow_dev_page at ffffffff811c8297 #20 __getblk_slow at ffffffff811c91d6 #21 __getblk_gfp at ffffffff811c92c1 #22 ext4_ext_grow_indepth at ffffffff8124565c #23 ext4_ext_create_new_leaf at ffffffff81246ca8 #24 ext4_ext_insert_extent at ffffffff81246f09 #25 ext4_ext_map_blocks at ffffffff8124a848 #26 ext4_map_blocks at ffffffff8121a5b7 #27 mpage_map_one_extent at ffffffff8121b1fa #28 mpage_map_and_submit_extent at ffffffff8121f07b #29 ext4_writepages at ffffffff8121f6d5 #30 do_writepages at ffffffff8112c490 #31 __filemap_fdatawrite_range at ffffffff81120199 #32 filemap_flush at ffffffff8112041c #33 ext4_alloc_da_blocks at ffffffff81219da1 #34 ext4_rename at ffffffff81229b91 #35 ext4_rename2 at ffffffff81229e32 #36 vfs_rename at ffffffff811a08a5 #37 SYSC_renameat2 at ffffffff811a3ffc #38 sys_renameat2 at ffffffff811a408e #39 sys_rename at ffffffff8119e51e #40 system_call_fastpath at ffffffff815afa89 Dave Chinner has properly pointed out that this is a deadlock in the reclaim code because ext4 doesn't submit pages which are marked by PG_writeback right away. The heuristic was introduced by commit e62e384e9da8 ("memcg: prevent OOM with too many dirty pages") and it was applied only when may_enter_fs was specified. The code has been changed by c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") which has removed the __GFP_FS restriction with a reasoning that we do not get into the fs code. But this is not sufficient apparently because the fs doesn't necessarily submit pages marked PG_writeback for IO right away. ext4_bio_write_page calls io_submit_add_bh but that doesn't necessarily submit the bio. Instead it tries to map more pages into the bio and mpage_map_one_extent might trigger memcg charge which might end up waiting on a page which is marked PG_writeback but hasn't been submitted yet so we would end up waiting for something that never finishes. Fix this issue by replacing __GFP_IO by may_enter_fs check (for case 2) before we go to wait on the writeback. The page fault path, which is the only path that triggers memcg oom killer since 3.12, shouldn't require GFP_NOFS and so we shouldn't reintroduce the premature OOM killer issue which was originally addressed by the heuristic. As per David Chinner the xfs is doing similar thing since 2.6.15 already so ext4 is not the only affected filesystem. Moreover he notes: : For example: IO completion might require unwritten extent conversion : which executes filesystem transactions and GFP_NOFS allocations. The : writeback flag on the pages can not be cleared until unwritten : extent conversion completes. Hence memory reclaim cannot wait on : page writeback to complete in GFP_NOFS context because it is not : safe to do so, memcg reclaim or otherwise. Cc: stable@vger.kernel.org # 3.9+ [tytso@mit.edu: corrected the control flow] Fixes: c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") Reported-by: Nikolay Borisov Signed-off-by: Michal Hocko Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds diff --git a/mm/vmscan.c b/mm/vmscan.c index e61445d..8286938 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -973,22 +973,18 @@ static unsigned long shrink_page_list(struct list_head *page_list, * caller can stall after page list has been processed. * * 2) Global or new memcg reclaim encounters a page that is - * not marked for immediate reclaim or the caller does not - * have __GFP_IO. In this case mark the page for immediate + * not marked for immediate reclaim, or the caller does not + * have __GFP_FS (or __GFP_IO if it's simply going to swap, + * not to fs). In this case mark the page for immediate * reclaim and continue scanning. * - * __GFP_IO is checked because a loop driver thread might + * Require may_enter_fs because we would wait on fs, which + * may not have submitted IO yet. And the loop driver might * enter reclaim, and deadlock if it waits on a page for * which it is needed to do the write (loop masks off * __GFP_IO|__GFP_FS for this reason); but more thought * would probably show more reasons. * - * Don't require __GFP_FS, since we're not going into the - * FS, just waiting on its writeback completion. Worryingly, - * ext4 gfs2 and xfs allocate pages with - * grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing - * may_enter_fs here is liable to OOM on them. - * * 3) Legacy memcg encounters a page that is not already marked * PageReclaim. memcg does not have any dirty pages * throttling so we could easily OOM just because too many @@ -1005,7 +1001,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, /* Case 2 above */ } else if (sane_reclaim(sc) || - !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) { + !PageReclaim(page) || !may_enter_fs) { /* * This is slightly racy - end_page_writeback() * might have just cleared PageReclaim, then -- cgit v0.10.2 From f58e5aa7b873b8a4376b816993d4b0e903befcba Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 4 Aug 2015 18:34:00 -0700 Subject: netfilter: conntrack: Use flags in nf_ct_tmpl_alloc() The flags were ignored for this function when it was introduced. Also fix the style problem in kzalloc. Fixes: 0838aa7fc (netfilter: fix netns dependencies with conntrack templates) Signed-off-by: Joe Stringer Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f168099..3c20d02 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -292,7 +292,7 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags) { struct nf_conn *tmpl; - tmpl = kzalloc(sizeof(struct nf_conn), GFP_KERNEL); + tmpl = kzalloc(sizeof(*tmpl), flags); if (tmpl == NULL) return NULL; @@ -303,7 +303,7 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags) if (zone) { struct nf_conntrack_zone *nf_ct_zone; - nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, GFP_ATOMIC); + nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, flags); if (!nf_ct_zone) goto out_free; nf_ct_zone->id = zone; -- cgit v0.10.2 From 46011e6ea39235e4aca656673c500eac81a07a17 Mon Sep 17 00:00:00 2001 From: David Daney Date: Mon, 3 Aug 2015 17:48:43 -0700 Subject: MIPS: Make set_pte() SMP safe. On MIPS the GLOBAL bit of the PTE must have the same value in any aligned pair of PTEs. These pairs of PTEs are referred to as "buddies". In a SMP system is is possible for two CPUs to be calling set_pte() on adjacent PTEs at the same time. There is a race between setting the PTE and a different CPU setting the GLOBAL bit in its buddy PTE. This race can be observed when multiple CPUs are executing vmap()/vfree() at the same time. Make setting the buddy PTE's GLOBAL bit an atomic operation to close the race condition. The case of CONFIG_64BIT_PHYS_ADDR && CONFIG_CPU_MIPS32 is *not* handled. Signed-off-by: David Daney Cc: Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10835/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 9d81067..ae85694 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) * Make sure the buddy is global too (if it's !none, * it better already be global) */ +#ifdef CONFIG_SMP + /* + * For SMP, multiple CPUs can race, so we need to do + * this atomically. + */ +#ifdef CONFIG_64BIT +#define LL_INSN "lld" +#define SC_INSN "scd" +#else /* CONFIG_32BIT */ +#define LL_INSN "ll" +#define SC_INSN "sc" +#endif + unsigned long page_global = _PAGE_GLOBAL; + unsigned long tmp; + + __asm__ __volatile__ ( + " .set push\n" + " .set noreorder\n" + "1: " LL_INSN " %[tmp], %[buddy]\n" + " bnez %[tmp], 2f\n" + " or %[tmp], %[tmp], %[global]\n" + " " SC_INSN " %[tmp], %[buddy]\n" + " beqz %[tmp], 1b\n" + " nop\n" + "2:\n" + " .set pop" + : [buddy] "+m" (buddy->pte), + [tmp] "=&r" (tmp) + : [global] "r" (page_global)); +#else /* !CONFIG_SMP */ if (pte_none(*buddy)) pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; +#endif /* CONFIG_SMP */ } #endif } -- cgit v0.10.2 From 00a6d6e50ff34aa2351746422e4a1c85c7765b15 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 5 Aug 2015 10:03:18 +0800 Subject: ASoC: Add function "rl6231_get_pre_div" to correct the dmic clock calculation Signed-off-by: Bard Liao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 96f3e90..57e51c1 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -11,10 +11,57 @@ */ #include +#include #include "rl6231.h" /** + * rl6231_get_pre_div - Return the value of pre divider. + * + * @map: map for setting. + * @reg: register. + * @sft: shift. + * + * Return the value of pre divider from given register value. + * Return negative error code for unexpected register value. + */ +int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft) +{ + int pd, val; + + regmap_read(map, reg, &val); + + val = (val >> sft) & 0x7; + + switch (val) { + case 0: + case 1: + case 2: + case 3: + pd = val + 1; + break; + case 4: + pd = 6; + break; + case 5: + pd = 8; + break; + case 6: + pd = 12; + break; + case 7: + pd = 16; + break; + default: + pd = -EINVAL; + break; + } + + return pd; +} +EXPORT_SYMBOL_GPL(rl6231_get_pre_div); + +/** * rl6231_calc_dmic_clk - Calculate the parameter of dmic. * * @rate: base clock rate. diff --git a/sound/soc/codecs/rl6231.h b/sound/soc/codecs/rl6231.h index 0f7b057..4c77b44 100644 --- a/sound/soc/codecs/rl6231.h +++ b/sound/soc/codecs/rl6231.h @@ -30,5 +30,6 @@ int rl6231_calc_dmic_clk(int rate); int rl6231_pll_calc(const unsigned int freq_in, const unsigned int freq_out, struct rl6231_pll_code *pll_code); int rl6231_get_clk_info(int sclk, int rate); +int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft); #endif /* __RL6231_H__ */ diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..7168957 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -459,10 +459,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); - int idx = -EINVAL; - - idx = rl6231_calc_dmic_clk(rt5640->sysclk); + int idx, rate; + rate = rt5640->sysclk / rl6231_get_pre_div(rt5640->regmap, + RT5640_ADDA_CLK1, RT5640_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); else diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..7d9d85d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -510,10 +510,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); - int idx = -EINVAL; - - idx = rl6231_calc_dmic_clk(rt5645->sysclk); + int idx, rate; + rate = rt5645->sysclk / rl6231_get_pre_div(rt5645->regmap, + RT5645_ADDA_CLK1, RT5645_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); else diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..8df690a 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -378,10 +378,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); - int idx = -EINVAL; - - idx = rl6231_calc_dmic_clk(rt5651->sysclk); + int idx, rate; + rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap, + RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); else diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..5d78fa1 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -683,10 +683,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); - int idx = -EINVAL; - - idx = rl6231_calc_dmic_clk(rt5670->sysclk); + int idx, rate; + rate = rt5670->sysclk / rl6231_get_pre_div(rt5670->regmap, + RT5670_ADDA_CLK1, RT5670_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); else diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..f662bfd 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -917,8 +917,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8); + int idx, rate; + rate = rt5677->sysclk / rl6231_get_pre_div(rt5677->regmap, + RT5677_CLK_TREE_CTRL1, RT5677_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); if (idx < 0) dev_err(codec->dev, "Failed to set DMIC clock\n"); else -- cgit v0.10.2 From 4a6ca1a2c2530af4611024476ba7005bf0336dfe Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 17 Jul 2015 13:07:35 +0200 Subject: drm/i2c: tda998x: fix bad checksum of the HDMI AVI infoframe The commit 8c7a075da9f7980cc95ffcd7e6621d4a87f20f40 "drm/i2c: tda998x: use drm_hdmi_avi_infoframe_from_display_mode()" also uses hdmi_avi_infoframe_pack() to create the AVI infoframe. This function sets the checksum of the frame and this breaks the second calculation of the checksum done in tda998x_write_if(). Fixes: 8c7a075da9f7980c ("drm/i2c: tda998x: use drm_hdmi_avi_infoframe_from_display_mode()") Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 290a69d..e7f2000 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -582,8 +582,6 @@ static void tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, uint8_t *buf, size_t size) { - buf[PB(0)] = tda998x_cksum(buf, size); - reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, size); reg_set(priv, REG_DIP_IF_FLAGS, bit); @@ -603,6 +601,8 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) buf[PB(4)] = p->audio_frame[4]; buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */ + buf[PB(0)] = tda998x_cksum(buf, sizeof(buf)); + tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, sizeof(buf)); } -- cgit v0.10.2 From fc1a8126bf8095b10f5a79893f2d2b19227f88f2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 4 Aug 2015 10:58:26 -0600 Subject: KVM: MTRR: Use default type for non-MTRR-covered gfn before WARN_ON The patch was munged on commit to re-order these tests resulting in excessive warnings when trying to do device assignment. Return to original ordering: https://lkml.org/lkml/2015/7/15/769 Fixes: 3e5d2fdceda1 ("KVM: MTRR: simplify kvm_mtrr_get_guest_memory_type") Signed-off-by: Alex Williamson Reviewed-by: Xiao Guangrong Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index dc0a84a..9e8bf13 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -672,16 +672,16 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) if (iter.mtrr_disabled) return mtrr_disabled_type(); + /* not contained in any MTRRs. */ + if (type == -1) + return mtrr_default_type(mtrr_state); + /* * We just check one page, partially covered by MTRRs is * impossible. */ WARN_ON(iter.partial_map); - /* not contained in any MTRRs. */ - if (type == -1) - return mtrr_default_type(mtrr_state); - return type; } EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type); -- cgit v0.10.2 From 4317c8c9121e4685561422ac267b292df8e80806 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 17:46:38 +0530 Subject: ARM: dts: omap243x: Fix broken pbias device creation commit <72b10ac00eb1> ("ARM: dts: omap24xx: add minimal l4 bus layout with control module support") moved pbias_regulator dt node from being a child node of ocp to be the child node of scm_conf. After this device for pbias_regulator is not created. Fix it by adding "simple-bus" compatible property to scm_conf dt node. Fixes: 72b10ac00eb1 ("ARM: dts: omap24xx: add minimal l4 bus layout with control module support") Cc: # v4.1 Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index 11a7963..2390f38 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -51,7 +51,8 @@ }; scm_conf: scm_conf@270 { - compatible = "syscon"; + compatible = "syscon", + "simple-bus"; reg = <0x270 0x240>; #address-cells = <1>; #size-cells = <1>; -- cgit v0.10.2 From 89a898df87e114952191ab0e061aa18e3c617880 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 17:46:39 +0530 Subject: ARM: dts: OMAP4: Fix broken pbias device creation commit <7415b0b4c645> ("ARM: dts: omap4: add minimal l4 bus layout with control module support") moved pbias_regulator dt node from being a child node of ocp to be the child node of omap4_padconf_global. After this device for pbias_regulator is not created. Fix it by adding "simple-bus" compatible property to omap4_padconf_global dt node. Fixes: 7415b0b4c645 ("ARM: dts: omap4: add minimal l4 bus layout with control module support") Cc: # v4.1 Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 7d31c6f..abc4473 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -191,7 +191,8 @@ }; omap4_padconf_global: omap4_padconf_global@5a0 { - compatible = "syscon"; + compatible = "syscon", + "simple-bus"; reg = <0x5a0 0x170>; #address-cells = <1>; #size-cells = <1>; -- cgit v0.10.2 From 70caac3f25291cf715cf8f2d8c7db46f6cbefe7c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 17:46:40 +0530 Subject: ARM: dts: OMAP5: Fix broken pbias device creation commit ("ARM: dts: omap5: add minimal l4 bus layout with control module support") moved pbias_regulator dt node from being a child node of ocp to be the child node of omap5_padconf_global. After this device for pbias_regulator is not created. Fix it by adding "simple-bus" compatible property to omap5_padconf_global dt node. Fixes: ed8509edddeb ("ARM: dts: omap5: add minimal l4 bus layout with control module support") Cc: # v4.1 Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index c8fd648..b1a1263 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -180,7 +180,8 @@ }; omap5_padconf_global: omap5_padconf_global@5a0 { - compatible = "syscon"; + compatible = "syscon", + "simple-bus"; reg = <0x5a0 0xec>; #address-cells = <1>; #size-cells = <1>; -- cgit v0.10.2 From cd4556733b30cc363adc7b1cea3bffa7e2dd0c7c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 17:46:41 +0530 Subject: ARM: dts: dra7: Fix broken pbias device creation commit ("ARM: dts: dra7: add minimal l4 bus layout with control module support") moved pbias_regulator dt node from being a child node of ocp to be the child node of scm_conf. After this device for pbias_regulator is not created. Fix it by adding "simple-bus" compatible property to scm_conf dt node. Fixes: d919501feffa ("ARM: dts: dra7: add minimal l4 bus layout with control module support") Cc: # v4.1 Suggested-by: Tero Kristo Signed-off-by: Kishon Vijay Abraham I Tested-by: Grygorii Strashko Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 8f1e25b..3062b1f 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -116,7 +116,7 @@ ranges = <0 0x2000 0x2000>; scm_conf: scm_conf@0 { - compatible = "syscon"; + compatible = "syscon", "simple-bus"; reg = <0x0 0x1400>; #address-cells = <1>; #size-cells = <1>; -- cgit v0.10.2 From f17cbcfef3cf6d91a374817f84c66951c84f11e2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:29 +0200 Subject: ASoC: 88pm860x: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 38b3dad..51dd50e 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -156,33 +156,29 @@ static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1); static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0); /* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */ -static const unsigned int mic_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(mic_tlv, 0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0), 3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0), - 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0), -}; + 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0) +); /* {0, 0, 0, -6, 0, 6, 12, 18}dB */ -static const unsigned int aux_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(aux_tlv, 0, 2, TLV_DB_SCALE_ITEM(0, 0, 0), - 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0), -}; + 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0) +); /* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */ -static const unsigned int out_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(out_tlv, 0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1), 4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0), 5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0), - 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0), -}; + 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0) +); -static const unsigned int st_tlv[] = { - TLV_DB_RANGE_HEAD(8), +static const DECLARE_TLV_DB_RANGE(st_tlv, 0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0), 2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0), 4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0), @@ -190,8 +186,8 @@ static const unsigned int st_tlv[] = { 8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0), 10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0), 14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0), - 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0), -}; + 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0) +); /* Sidetone Gain = M * 2^(-5-N) */ struct st_gain { -- cgit v0.10.2 From 69dae09f2da83c96de6c8573061bd38e9989e873 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:30 +0200 Subject: ASoC: ab8500: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index c7d243d..affb192 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -1335,11 +1335,10 @@ static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1); static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1); /* -1dB = Mute */ -static const unsigned int hs_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(hs_gain_tlv, 0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0), - 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0), -}; + 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0) +); static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0); -- cgit v0.10.2 From 31581f3c09e796d5faac183eadfe06dca2223a5e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:31 +0200 Subject: ASoC: adau1373: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index a431602..1fc1bd4 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -320,13 +320,12 @@ static const struct reg_default adau1373_reg_defaults[] = { { ADAU1373_DIGEN, 0x00 }, }; -static const unsigned int adau1373_out_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(adau1373_out_tlv, 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1), 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0), 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0), - 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0), -}; + 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0) +); static const DECLARE_TLV_DB_MINMAX(adau1373_digital_tlv, -9563, 0); static const DECLARE_TLV_DB_SCALE(adau1373_in_pga_tlv, -1300, 100, 1); @@ -381,12 +380,11 @@ static const char *adau1373_bass_hpf_cutoff_text[] = { "158Hz", "232Hz", "347Hz", "520Hz", }; -static const unsigned int adau1373_bass_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(adau1373_bass_tlv, 0, 2, TLV_DB_SCALE_ITEM(-600, 600, 1), 3, 4, TLV_DB_SCALE_ITEM(950, 250, 0), - 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), -}; + 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0) +); static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); @@ -414,11 +412,10 @@ static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); -static const unsigned int adau1373_3d_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(adau1373_3d_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), - 1, 7, TLV_DB_LINEAR_ITEM(-1800, -120), -}; + 1, 7, TLV_DB_LINEAR_ITEM(-1800, -120) +); static const char *adau1373_lr_mux_text[] = { "Mute", -- cgit v0.10.2 From c8aeb0f60f648fbb77c1d5b3edda86e08bf53b30 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:32 +0200 Subject: ASoC: alc5623: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 0fc24e0..ebdaf0d 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -82,12 +82,11 @@ static int amp_mixer_event(struct snd_soc_dapm_widget *w, static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0); -static const unsigned int boost_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(boost_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0) +); static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0); static const struct snd_kcontrol_new alc5621_vol_snd_controls[] = { -- cgit v0.10.2 From ec7e4dc85cd7a2498d6ab71e9f77f49b41729fb4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:33 +0200 Subject: ASoC: alc5632: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 607a63b..1cabb40 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -146,11 +146,10 @@ static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0); /* -16.5db min scale, 1.5db steps, no mute */ static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0); -static const unsigned int boost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(boost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), -}; + 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0) +); /* 0db min scale, 6 db steps, no mute */ static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0); /* 0db min scalem 0.75db steps, no mute */ -- cgit v0.10.2 From 0a017768e8964ab4a6a68ad47a042d28b35695fb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:34 +0200 Subject: ASoC: cs42l52: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9..b4b4dc6 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -196,11 +196,10 @@ static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0); static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0); -static const unsigned int limiter_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(limiter_tlv, 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), - 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), -}; + 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0) +); static const char * const cs42l52_adca_text[] = { "Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"}; -- cgit v0.10.2 From 37879bafc2e0932279ad440d5a81c323e0c5c58c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:35 +0200 Subject: ASoC: cs42l56: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba4..e88a559 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -185,21 +185,18 @@ static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0); static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); -static const unsigned int ngnb_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(ngnb_tlv, 0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0), - 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0), -}; -static const unsigned int ngb_tlv[] = { - TLV_DB_RANGE_HEAD(2), + 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0) +); +static const DECLARE_TLV_DB_RANGE(ngb_tlv, 0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0), - 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0), -}; -static const unsigned int alc_tlv[] = { - TLV_DB_RANGE_HEAD(2), + 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0) +); +static const DECLARE_TLV_DB_RANGE(alc_tlv, 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), - 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), -}; + 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0) +); static const char * const beep_config_text[] = { "Off", "Single", "Multiple", "Continuous" -- cgit v0.10.2 From 0c8129152cb849183a204fe0ce95673e4c88d2f6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:36 +0200 Subject: ASoC: cs42l73: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index b7853b9..15ba377 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -253,11 +253,10 @@ static bool cs42l73_readable_register(struct device *dev, unsigned int reg) } } -static const unsigned int hpaloa_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(hpaloa_tlv, 0, 13, TLV_DB_SCALE_ITEM(-7600, 200, 0), - 14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0), -}; + 14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0) +); static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2500, 0); @@ -267,11 +266,10 @@ static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0); static DECLARE_TLV_DB_SCALE(micpga_tlv, -600, 50, 0); -static const unsigned int limiter_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(limiter_tlv, 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), - 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), -}; + 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0) +); static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1); -- cgit v0.10.2 From 6c1e1bfe22d6dc45384acebe0722d35e89011cc2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:37 +0200 Subject: ASoC: da7210: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Adam Thomson Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5..18ecdf3 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -267,33 +267,29 @@ enum clk_src { * * Reserved area are considered as "mute". */ -static const unsigned int hp_out_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(hp_out_tlv, 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* -54 dB to +15 dB */ - 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0), -}; + 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0) +); -static const unsigned int lineout_vol_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(lineout_vol_tlv, 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* -54dB to 15dB */ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0) -}; +); -static const unsigned int mono_vol_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(mono_vol_tlv, 0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1), /* -18dB to 6dB */ 0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0) -}; +); -static const unsigned int aux1_vol_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(aux1_vol_tlv, 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* -48dB to 21dB */ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-4800, 150, 0) -}; +); static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0); static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1); -- cgit v0.10.2 From 32e933be3f221723ace230fe1293eb3b3b3466ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:38 +0200 Subject: ASoC: da7213: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Adam Thomson Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 238e48a..c2358a9 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -28,27 +28,24 @@ /* Gain and Volume */ -static const unsigned int aux_vol_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(aux_vol_tlv, /* -54dB */ 0x0, 0x11, TLV_DB_SCALE_ITEM(-5400, 0, 0), /* -52.5dB to 15dB */ 0x12, 0x3f, TLV_DB_SCALE_ITEM(-5250, 150, 0) -}; +); -static const unsigned int digital_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(digital_gain_tlv, 0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* -78dB to 12dB */ 0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0) -}; +); -static const unsigned int alc_analog_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv, 0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* 0dB to 36dB */ 0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0) -}; +); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0); -- cgit v0.10.2 From e27c8404a4745b3efeec1457e6b72f448ab4a785 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:39 +0200 Subject: ASoC: da9055: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446..8e6fc57 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -289,26 +289,23 @@ enum clk_src { /* Gain and Volume */ -static const unsigned int aux_vol_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(aux_vol_tlv, 0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0), /* -54dB to 15dB */ 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0) -}; +); -static const unsigned int digital_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(digital_gain_tlv, 0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* -78dB to 12dB */ 0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0) -}; +); -static const unsigned int alc_analog_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv, 0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), /* 0dB to 36dB */ 0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0) -}; +); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0); -- cgit v0.10.2 From 4689ac530efa8dadfb3ef8a284f9b2b14b75ad5f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:40 +0200 Subject: ASoC: jz4740: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 9363fdb..1f5ab99 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -78,11 +78,10 @@ struct jz4740_codec { struct regmap *regmap; }; -static const unsigned int jz4740_mic_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(jz4740_mic_tlv, 0, 2, TLV_DB_SCALE_ITEM(0, 600, 0), - 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0) +); static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0); static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0); -- cgit v0.10.2 From 44744eeccff7de65f98f2d5db804adc51bfd3333 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:41 +0200 Subject: ASoC: max9768: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index e1c196a..ceae776 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -63,8 +63,7 @@ static int max9768_set_gpio(struct snd_kcontrol *kcontrol, return 0; } -static const unsigned int volume_tlv[] = { - TLV_DB_RANGE_HEAD(43), +static const DECLARE_TLV_DB_RANGE(volume_tlv, 0, 0, TLV_DB_SCALE_ITEM(-16150, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(-9280, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(-9030, 0, 0), @@ -107,8 +106,8 @@ static const unsigned int volume_tlv[] = { 51, 57, TLV_DB_SCALE_ITEM(290, 50, 0), 58, 58, TLV_DB_SCALE_ITEM(650, 0, 0), 59, 62, TLV_DB_SCALE_ITEM(700, 60, 0), - 63, 63, TLV_DB_SCALE_ITEM(950, 0, 0), -}; + 63, 63, TLV_DB_SCALE_ITEM(950, 0, 0) +); static const struct snd_kcontrol_new max9768_volume[] = { SOC_SINGLE_TLV("Playback Volume", MAX9768_VOL, 0, 63, 0, volume_tlv), -- cgit v0.10.2 From 80170468deec8fe851957d1e1cc3cf680ae46804 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:42 +0200 Subject: ASoC: max98088: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index d0f4534..d326d66 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -680,29 +680,26 @@ static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol, return 0; } -static const unsigned int max98088_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), - 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; +static const DECLARE_TLV_DB_RANGE(max98088_micboost_tlv, + 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0) +); -static const unsigned int max98088_hp_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98088_hp_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0) +); -static const unsigned int max98088_spk_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98088_spk_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0) +); static const struct snd_kcontrol_new max98088_snd_controls[] = { -- cgit v0.10.2 From 8896bc3e089b39d077c7afbf785166aac28e5151 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:43 +0200 Subject: ASoC: max98090: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f05..cf8789f 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -360,22 +360,20 @@ static int max98090_reset(struct max98090_priv *max98090) return ret; } -static const unsigned int max98090_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(max98090_micboost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0) +); static const DECLARE_TLV_DB_SCALE(max98090_mic_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_line_single_ended_tlv, -600, 600, 0); -static const unsigned int max98090_line_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(max98090_line_tlv, 0, 3, TLV_DB_SCALE_ITEM(-600, 300, 0), - 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0), -}; + 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0) +); static const DECLARE_TLV_DB_SCALE(max98090_avg_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); @@ -391,38 +389,34 @@ static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0); -static const unsigned int max98090_mixout_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(max98090_mixout_tlv, 0, 1, TLV_DB_SCALE_ITEM(-1200, 250, 0), - 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0), -}; + 2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0) +); -static const unsigned int max98090_hp_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98090_hp_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0) +); -static const unsigned int max98090_spk_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98090_spk_tlv, 0, 4, TLV_DB_SCALE_ITEM(-4800, 400, 0), 5, 10, TLV_DB_SCALE_ITEM(-2900, 300, 0), 11, 14, TLV_DB_SCALE_ITEM(-1200, 200, 0), 15, 29, TLV_DB_SCALE_ITEM(-500, 100, 0), - 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0), -}; + 30, 39, TLV_DB_SCALE_ITEM(950, 50, 0) +); -static const unsigned int max98090_rcv_lout_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0) +); static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v0.10.2 From 54c2011f5a7c31ec4e2ddb8694b559e29673941e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:44 +0200 Subject: ASoC: max98095: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9a46d3d..78e4b5a 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -661,48 +661,43 @@ static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol, return 0; } -static const unsigned int max98095_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(max98095_micboost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0) +); static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0); -static const unsigned int max98095_hp_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98095_hp_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(150, 50, 0) +); -static const unsigned int max98095_spk_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(max98095_spk_tlv, 0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0), 11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0), 19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0), - 28, 39, TLV_DB_SCALE_ITEM(650, 50, 0), -}; + 28, 39, TLV_DB_SCALE_ITEM(650, 50, 0) +); -static const unsigned int max98095_rcv_lout_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(max98095_rcv_lout_tlv, 0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0), 7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0), 15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0), 22, 27, TLV_DB_SCALE_ITEM(100, 100, 0), - 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0), -}; + 28, 31, TLV_DB_SCALE_ITEM(650, 50, 0) +); -static const unsigned int max98095_lin_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(max98095_lin_tlv, 0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0), 3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0), - 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0), -}; + 4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0) +); static const struct snd_kcontrol_new max98095_snd_controls[] = { -- cgit v0.10.2 From e0340985999fbee1a51bd4653d90ca19a8a7acdc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:45 +0200 Subject: ASoC: max9850: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 481d58f1..3774e42 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -67,13 +67,12 @@ static const struct regmap_config max9850_regmap = { .cache_type = REGCACHE_RBTREE, }; -static const unsigned int max9850_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(max9850_tlv, 0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0), 0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0), 0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0), - 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0), -}; + 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0) +); static const struct snd_kcontrol_new max9850_controls[] = { SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv), -- cgit v0.10.2 From d6e3bb7aca7fbd092f1a19991526c095e59f8531 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:46 +0200 Subject: ASoC: max9877: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 29549cd..9aac52d 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -30,19 +30,17 @@ static struct reg_default max9877_regs[] = { { 4, 0x49 }, }; -static const unsigned int max9877_pgain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(max9877_pgain_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0), - 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0), -}; + 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0) +); -static const unsigned int max9877_output_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(max9877_output_tlv, 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1), 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0), 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0), - 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0), -}; + 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0) +); static const char *max9877_out_mode[] = { "INA -> SPK", -- cgit v0.10.2 From 7f708abeac7d12f00b200848aa0cafe589ea8454 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:47 +0200 Subject: ASoC: rt5631: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 058167c..63fba98 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -174,16 +174,15 @@ static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */ -static unsigned int mic_bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(mic_bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v0.10.2 From 8295822dac5d78e62beb6a13bbb2d82e36ba763c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:48 +0200 Subject: ASoC: rt5640: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..71bd4a3 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -347,16 +347,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); /* Interface data select */ static const char * const rt5640_data_select[] = { -- cgit v0.10.2 From 6d698a83fa768be38780d54fc6c244c99cf7684d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:49 +0200 Subject: ASoC: rt5645: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..df27ec1 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -424,16 +424,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* Speaker Output Volume */ -- cgit v0.10.2 From 8e3648e10fd832e4e07bc3c0cf0e37f95de60082 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:50 +0200 Subject: ASoC: rt5651: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e1..a7f456c 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -292,16 +292,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); /* Interface data select */ static const char * const rt5651_data_select[] = { -- cgit v0.10.2 From dea6d32e9efea0a75b5fb367fd53fa0562154852 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:51 +0200 Subject: ASoC: rt5670: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4..7ce8d06 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -592,16 +592,15 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); /* Interface data select */ static const char * const rt5670_data_select[] = { -- cgit v0.10.2 From 53f28609b0091c1e450105aaef924320aa748082 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:52 +0200 Subject: ASoC: rt5677: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969a..985e437 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -789,16 +789,15 @@ static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const DECLARE_TLV_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v0.10.2 From 53eb1ca3caab417f1f686627bbf6bfa7d54cb5a8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:53 +0200 Subject: ASoC: sgtl5000: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e673f6c..c59a687 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -406,11 +406,10 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0); /* tlv for mic gain, 0db 20db 30db 40db */ -static const unsigned int mic_gain_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(mic_gain_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), - 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), -}; + 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0) +); /* tlv for hp volume, -51.5db to 12.0db, step .5db */ static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); -- cgit v0.10.2 From f9d54802b6339cc3d4bdf30ca3648790064462d2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:54 +0200 Subject: ASoC: ssm2602: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 69a773a..4452fea 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -75,11 +75,10 @@ static const struct soc_enum ssm2602_enum[] = { ssm2602_deemph), }; -static const unsigned int ssm260x_outmix_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv, 0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), - 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0), -}; + 48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0) +); static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0); -- cgit v0.10.2 From 4e0e5f8084cf9766ea70234f90271e03fd8aa56d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:55 +0200 Subject: ASoC: tpa6130a2: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fac9e0..1e1d4ab 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -259,8 +259,7 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going * down in gain. */ -static const unsigned int tpa6130_tlv[] = { - TLV_DB_RANGE_HEAD(10), +static const DECLARE_TLV_DB_RANGE(tpa6130_tlv, 0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0), 2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0), 4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0), @@ -270,8 +269,8 @@ static const unsigned int tpa6130_tlv[] = { 12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0), 14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0), 21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0), - 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0), -}; + 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0) +); static const struct snd_kcontrol_new tpa6130a2_controls[] = { SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume", @@ -280,12 +279,11 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = { tpa6130_tlv), }; -static const unsigned int tpa6140_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(tpa6140_tlv, 0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0), 9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0), - 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0), -}; + 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0) +); static const struct snd_kcontrol_new tpa6140a2_controls[] = { SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume", -- cgit v0.10.2 From 2524911e300771954698f384bd7f44543b2af2de Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:56 +0200 Subject: ASoC: twl4030: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 90f5f04..2713e18 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -524,12 +524,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); /* Digital bypass gain, mute instead of -30dB */ -static const unsigned int twl4030_dapm_dbypass_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(twl4030_dapm_dbypass_tlv, 0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1), 2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0), - 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), -}; + 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0) +); /* Digital bypass left (TX1L -> RX2L) */ static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control = -- cgit v0.10.2 From 5ee0b8f8296f237604f0ff72f03e7836f5e164b4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:57 +0200 Subject: ASoC: uda1380: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 6e159f5..4b9b438 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -269,12 +269,11 @@ static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); * from -66 dB in 0.5 dB steps (2 dB steps, really) and * from -52 dB in 0.25 dB steps */ -static const unsigned int mvol_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(mvol_tlv, 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), - 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), -}; + 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0) +); /* * from -72 dB in 1.5 dB steps (6 dB steps really), @@ -282,13 +281,12 @@ static const unsigned int mvol_tlv[] = { * from -60 dB in 0.5 dB steps (2 dB steps really) and * from -46 dB in 0.25 dB steps */ -static const unsigned int vc_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(vc_tlv, 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), - 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), -}; + 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0) +); /* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); -- cgit v0.10.2 From d3d383ba8b49fbb2024851442e09a104b1f030fe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:58 +0200 Subject: ASoC: wm8350: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 41c62c1..ffbf3df 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -394,11 +394,10 @@ static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1); static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1); static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1); -static const unsigned int capture_sd_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(capture_sd_tlv, 0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1), - 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0), -}; + 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0) +); static const struct snd_kcontrol_new wm8350_snd_controls[] = { SOC_ENUM("Playback Deemphasis", wm8350_enum[0]), -- cgit v0.10.2 From 0b65e6c7e22c93139b2b4efdd7ba6bd7bfa27fa7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:19:59 +0200 Subject: ASoC: wm8400: Don't use range container for TLV with one entry For TLVs with only a single entry it is not necessary to use a range container. Use DECLARE_TLV_DB_SCALE() directly instead of a combination of TLV_DB_RANGE_HEAD() and TLV_DB_SCALE_ITEM(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index d755508..b1d346a 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -370,10 +370,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w, } /* INMIX dB values */ -static const unsigned int in_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0,7, TLV_DB_SCALE_ITEM(-1200, 600, 0), -}; +static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0); /* Left In PGA Connections */ static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = { -- cgit v0.10.2 From 7d711f63e36737968dcda5ce28fed3fb3e12fbdc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:00 +0200 Subject: ASoC: wm8737: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 6ad606f..54e6158 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -79,13 +79,12 @@ static int wm8737_reset(struct snd_soc_codec *codec) return snd_soc_write(codec, WM8737_RESET, 0); } -static const unsigned int micboost_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(micboost_tlv, 0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0), - 3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0) +); static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1); static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0); -- cgit v0.10.2 From 11c3727c4e625c248ff3b546290aade1399affec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:01 +0200 Subject: ASoC: wm8753: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index feb2997a..f588341 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -276,12 +276,11 @@ static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); -static const unsigned int out_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(out_tlv, /* 0000000 - 0101111 = "Analogue mute" */ 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), - 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), -}; + 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0) +); static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); -- cgit v0.10.2 From 5d272d89339a4f8c1905d5bdf5851346582b78f2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:02 +0200 Subject: ASoC: wm8961: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a057662..44ee143 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -331,13 +331,12 @@ static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); -static unsigned int boost_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(boost_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(13, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(20, 0, 0), - 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0) +); static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0); static const struct snd_kcontrol_new wm8961_snd_controls[] = { -- cgit v0.10.2 From fcbb71e9ccac59940b619bdd5a51c96495dd4731 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:03 +0200 Subject: ASoC: wm8962: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd..b618da9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1456,14 +1456,13 @@ static int wm8962_reset(struct wm8962_priv *wm8962) static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0); static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0); -static const unsigned int mixinpga_tlv[] = { - TLV_DB_RANGE_HEAD(5), +static const DECLARE_TLV_DB_RANGE(mixinpga_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 600, 0), 2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0), 3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0), 5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0), - 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0), -}; + 6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0) +); static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1); static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); @@ -1471,11 +1470,10 @@ static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0); -static const unsigned int classd_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(classd_tlv, 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), - 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), -}; + 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0) +); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static int wm8962_dsp2_write_config(struct snd_soc_codec *codec) -- cgit v0.10.2 From dfd0edda1fb3cd7a7cdde56467d718b1e49e32d5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:04 +0200 Subject: ASoC: wm8990: Don't use range container for TLV with one entry For TLVs with only a single entry it is not necessary to use a range container. Use DECLARE_TLV_DB_SCALE() directly instead of a combination of TLV_DB_RANGE_HEAD() and TLV_DB_SCALE_ITEM(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 1993fd2..2befdde 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -418,10 +418,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } /* INMIX dB values */ -static const unsigned int in_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0), -}; +static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0); /* Left In PGA Connections */ static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { -- cgit v0.10.2 From 00769dbe3982c76dd68dac1d3f54328fa935bd21 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:05 +0200 Subject: ASoC: wm8991: Don't use range container for TLVs with one entry For TLVs with only a single entry it is not necessary to use a range container. Use DECLARE_TLV_DB_LINEAR() directly instead of a combination of TLV_DB_RANGE_HEAD() and TLV_DB_LINEAR_ITEM(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 44a6777..de9110e 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -111,45 +111,14 @@ static bool wm8991_volatile(struct device *dev, unsigned int reg) } } -static const unsigned int rec_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(-1500, 600), -}; - -static const unsigned int in_pga_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 0x1F, TLV_DB_LINEAR_ITEM(-1650, 3000), -}; - -static const unsigned int out_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(0, -2100), -}; - -static const unsigned int out_pga_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 127, TLV_DB_LINEAR_ITEM(-7300, 600), -}; - -static const unsigned int out_omix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(-600, 0), -}; - -static const unsigned int out_dac_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 255, TLV_DB_LINEAR_ITEM(-7163, 0), -}; - -static const unsigned int in_adc_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 255, TLV_DB_LINEAR_ITEM(-7163, 1763), -}; - -static const unsigned int out_sidetone_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 31, TLV_DB_LINEAR_ITEM(-3600, 0), -}; +static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); +static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); +static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); +static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); +static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); +static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); +static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); +static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -429,10 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } /* INMIX dB values */ -static const unsigned int in_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), -}; +static const DECLARE_TLV_DB_LINEAR(in_mix_tlv, -1200, 600); /* Left In PGA Connections */ static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = { -- cgit v0.10.2 From f1022087d372b02c8ffe5e1e084a3de763bea16b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:06 +0200 Subject: ASoC: wm8993: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db86..bc9e042 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -628,11 +628,10 @@ static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0); -static const unsigned int drc_max_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(drc_max_tlv, 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0), - 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0) +); static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0); static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); -- cgit v0.10.2 From 5d9a5e609bd026294c0d5c02372303cb969c9d98 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:07 +0200 Subject: ASoC: wm9081: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 8a8b1c0..5740cab 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -243,13 +243,12 @@ static int wm9081_reset(struct regmap *map) static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0); -static unsigned int drc_max_tlv[] = { - TLV_DB_RANGE_HEAD(4), +static const DECLARE_TLV_DB_RANGE(drc_max_tlv, 0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), - 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0) +); static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0); static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0); -- cgit v0.10.2 From 0894e2b3cddaf00a52302d0eb83edb717c6fb913 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:08 +0200 Subject: ASoC: wm9090: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 13d23fc..334c4c1 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -162,23 +162,20 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec) dev_err(codec->dev, "Timed out waiting for DC Servo\n"); } -static const unsigned int in_tlv[] = { - TLV_DB_RANGE_HEAD(3), +static const DECLARE_TLV_DB_RANGE(in_tlv, 0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0), 1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0), - 4, 6, TLV_DB_SCALE_ITEM(600, 600, 0), -}; -static const unsigned int mix_tlv[] = { - TLV_DB_RANGE_HEAD(2), + 4, 6, TLV_DB_SCALE_ITEM(600, 600, 0) +); +static const DECLARE_TLV_DB_RANGE(mix_tlv, 0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0), - 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0) +); static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); -static const unsigned int spkboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(spkboost_tlv, 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), - 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), -}; + 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0) +); static const struct snd_kcontrol_new wm9090_controls[] = { SOC_SINGLE_TLV("IN1A Volume", WM9090_IN1_LINE_INPUT_A_VOLUME, 0, 6, 0, -- cgit v0.10.2 From 5092e76b8ab406af56b6a24629a7daf30ea94f78 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:09 +0200 Subject: ASoC: wm9713: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 89cd2d6..e842b08 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -116,11 +116,10 @@ SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */ static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0); -static unsigned int mic_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(mic_tlv, 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0), - 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; + 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0) +); static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = { SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv), -- cgit v0.10.2 From 2e45a25f9cb6546d8b3c20d9461e21f8c0a75a8a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 2 Aug 2015 17:20:10 +0200 Subject: ASoC: wm_hubs: Replace TLV_DB_RANGE_HEAD with DECLARE_TLV_DB_RANGE DECLARE_TLV_DB_RANGE() has the advantage over using TLV_DB_RANGE_HEAD() that it automatically calculates the number of items in the TLV and is hence less prone to manual error. Generate using the following coccinelle script // @@ declarer name DECLARE_TLV_DB_RANGE; identifier tlv; constant x; @@ -unsigned int tlv[] = { - TLV_DB_RANGE_HEAD(x), +DECLARE_TLV_DB_RANGE(tlv, ... -}; +); // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index fd86bd1..624b3b9 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -38,11 +38,10 @@ static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0); static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0); static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1); static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0); -static const unsigned int spkboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const DECLARE_TLV_DB_RANGE(spkboost_tlv, 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), - 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), -}; + 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0) +); static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0); static const char *speaker_ref_text[] = { -- cgit v0.10.2 From 6f55a041378f8688ab4afd2702416cd5318fa73d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 30 Jul 2015 10:24:03 +0800 Subject: ASoC: wm8741: Simplify wm8741_set_dai_sysclk implementation Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index b346237..506792b 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -278,51 +278,38 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, switch (freq) { case 0: wm8741->sysclk_constraints = NULL; - wm8741->sysclk = freq; - return 0; - + break; case 11289600: wm8741->sysclk_constraints = &constraints_11289; - wm8741->sysclk = freq; - return 0; - + break; case 12288000: wm8741->sysclk_constraints = &constraints_12288; - wm8741->sysclk = freq; - return 0; - + break; case 16384000: wm8741->sysclk_constraints = &constraints_16384; - wm8741->sysclk = freq; - return 0; - + break; case 16934400: wm8741->sysclk_constraints = &constraints_16934; - wm8741->sysclk = freq; - return 0; - + break; case 18432000: wm8741->sysclk_constraints = &constraints_18432; - wm8741->sysclk = freq; - return 0; - + break; case 22579200: case 33868800: wm8741->sysclk_constraints = &constraints_22579; - wm8741->sysclk = freq; - return 0; - + break; case 24576000: wm8741->sysclk_constraints = &constraints_24576; - wm8741->sysclk = freq; - return 0; - + break; case 36864000: wm8741->sysclk_constraints = &constraints_36864; - wm8741->sysclk = freq; - return 0; + break; + default: + return -EINVAL; } - return -EINVAL; + + wm8741->sysclk = freq; + return 0; } static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, -- cgit v0.10.2 From f611cdd8eb33ac6ca1196319b27b7f7f24ef98a9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 1 Aug 2015 10:03:42 +0800 Subject: ASoC: wm8731: Drop wm8731_writeable function When .max_register is set and .writeable_reg is not implement, registers between 0 and .max_register are writeable. This is the same as current implementation of wm8731_writeable(), so just drop implementation for .writeable_reg callback. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 628d50c..6c73d37 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -79,11 +79,6 @@ static bool wm8731_volatile(struct device *dev, unsigned int reg) return reg == WM8731_RESET; } -static bool wm8731_writeable(struct device *dev, unsigned int reg) -{ - return reg <= WM8731_RESET; -} - #define wm8731_reset(m) regmap_write(m, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; @@ -655,7 +650,6 @@ static const struct regmap_config wm8731_regmap = { .max_register = WM8731_RESET, .volatile_reg = wm8731_volatile, - .writeable_reg = wm8731_writeable, .cache_type = REGCACHE_RBTREE, .reg_defaults = wm8731_reg_defaults, -- cgit v0.10.2 From b970499878563437a43eab2dd2faa9217142fb98 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 1 Aug 2015 10:04:52 +0800 Subject: ASoC: wm8753: Drop wm8753_writeable function When .max_register is set and .writeable_reg is not implement, registers between 0 and .max_register are writeable. This is the same as current implementation of wm8753_writeable(), so just drop implementation for .writeable_reg callback. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index feb2997a..4c6eaeb 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -138,11 +138,6 @@ static bool wm8753_volatile(struct device *dev, unsigned int reg) return reg == WM8753_RESET; } -static bool wm8753_writeable(struct device *dev, unsigned int reg) -{ - return reg <= WM8753_ADCTL2; -} - /* codec private data */ struct wm8753_priv { struct regmap *regmap; @@ -1510,7 +1505,6 @@ static const struct regmap_config wm8753_regmap = { .val_bits = 9, .max_register = WM8753_ADCTL2, - .writeable_reg = wm8753_writeable, .volatile_reg = wm8753_volatile, .cache_type = REGCACHE_RBTREE, -- cgit v0.10.2 From 8833c01af6aa8e42fcbc74d76646ead05d0183a7 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Mon, 3 Aug 2015 17:27:34 +0530 Subject: ASoC: tegra: Use devm_clk_get This patch introduces the use of managed resource function devm_clk_get instead of clk_get and removes corresponding calls to clk_put in the probe and remove functions. To be compatible with the change various gotos are replaced with direct returns, and unneeded labels are dropped. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index bc94e5d..989b1e8 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -549,54 +549,51 @@ static int tegra30_ahub_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't get reset %s\n", configlink_mods[i].rst_name); ret = PTR_ERR(rst); - goto err; + return ret; } ret = reset_control_deassert(rst); reset_control_put(rst); if (ret) - goto err; + return ret; } ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), GFP_KERNEL); if (!ahub) { dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } dev_set_drvdata(&pdev->dev, ahub); ahub->soc_data = soc_data; ahub->dev = &pdev->dev; - ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio"); + ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio"); if (IS_ERR(ahub->clk_d_audio)) { dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n"); ret = PTR_ERR(ahub->clk_d_audio); - goto err; + return ret; } - ahub->clk_apbif = clk_get(&pdev->dev, "apbif"); + ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif"); if (IS_ERR(ahub->clk_apbif)) { dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n"); ret = PTR_ERR(ahub->clk_apbif); - goto err_clk_put_d_audio; + return ret; } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res0) { dev_err(&pdev->dev, "No apbif memory resource\n"); - ret = -ENODEV; - goto err_clk_put_apbif; + return -ENODEV; } region = devm_request_mem_region(&pdev->dev, res0->start, resource_size(res0), DRV_NAME); if (!region) { dev_err(&pdev->dev, "request region apbif failed\n"); - ret = -EBUSY; - goto err_clk_put_apbif; + return -EBUSY; } ahub->apbif_addr = res0->start; @@ -604,8 +601,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) resource_size(res0)); if (!regs_apbif) { dev_err(&pdev->dev, "ioremap apbif failed\n"); - ret = -ENOMEM; - goto err_clk_put_apbif; + return -ENOMEM; } ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, @@ -613,31 +609,28 @@ static int tegra30_ahub_probe(struct platform_device *pdev) if (IS_ERR(ahub->regmap_apbif)) { dev_err(&pdev->dev, "apbif regmap init failed\n"); ret = PTR_ERR(ahub->regmap_apbif); - goto err_clk_put_apbif; + return ret; } regcache_cache_only(ahub->regmap_apbif, true); res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res1) { dev_err(&pdev->dev, "No ahub memory resource\n"); - ret = -ENODEV; - goto err_clk_put_apbif; + return -ENODEV; } region = devm_request_mem_region(&pdev->dev, res1->start, resource_size(res1), DRV_NAME); if (!region) { dev_err(&pdev->dev, "request region ahub failed\n"); - ret = -EBUSY; - goto err_clk_put_apbif; + return -EBUSY; } regs_ahub = devm_ioremap(&pdev->dev, res1->start, resource_size(res1)); if (!regs_ahub) { dev_err(&pdev->dev, "ioremap ahub failed\n"); - ret = -ENOMEM; - goto err_clk_put_apbif; + return -ENOMEM; } ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, @@ -645,7 +638,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) if (IS_ERR(ahub->regmap_ahub)) { dev_err(&pdev->dev, "ahub regmap init failed\n"); ret = PTR_ERR(ahub->regmap_ahub); - goto err_clk_put_apbif; + return ret; } regcache_cache_only(ahub->regmap_ahub, true); @@ -662,12 +655,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk_put_apbif: - clk_put(ahub->clk_apbif); -err_clk_put_d_audio: - clk_put(ahub->clk_d_audio); - ahub = NULL; -err: + return ret; } @@ -680,11 +668,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev) if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_ahub_runtime_suspend(&pdev->dev); - clk_put(ahub->clk_apbif); - clk_put(ahub->clk_d_audio); - - ahub = NULL; - return 0; } -- cgit v0.10.2 From a4b45b25f18d1e798965efec429ba5fc01b9f0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 30 Jul 2015 20:41:57 +0200 Subject: hwmon: (dell-smm) Blacklist Dell Studio XPS 8100 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPU fan speed going up and down on Dell Studio XPS 8100 for unknown reasons. Without further debugging on the affected machine, it is not possible to find the problem. Link: https://bugzilla.kernel.org/show_bug.cgi?id=100121 Signed-off-by: Pali Rohár Tested-by: Jan C Peters Cc: stable@vger.kernel.org # v4.0+, will need backport [groeck: cleaned up description, comments] Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 37c16af..c848789 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -929,6 +929,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); +static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = { + { + /* + * CPU fan speed going up and down on Dell Studio XPS 8100 + * for unknown reasons. + */ + .ident = "Dell Studio XPS 8100", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"), + }, + }, + { } +}; + /* * Probe for the presence of a supported laptop. */ @@ -940,7 +955,8 @@ static int __init i8k_probe(void) /* * Get DMI information */ - if (!dmi_check_system(i8k_dmi_table)) { + if (!dmi_check_system(i8k_dmi_table) || + dmi_check_system(i8k_blacklist_dmi_table)) { if (!ignore_dmi && !force) return -ENODEV; -- cgit v0.10.2 From 1252be9ce0ab4f622b8692b648894d09c0df71ce Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:39 +0200 Subject: hwmon: (nct7904) Export I2C module alias information The I2C core always reports the MODALIAS uevent as "i2c: Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 6153df73..08ff89d 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -575,6 +575,7 @@ static const struct i2c_device_id nct7904_id[] = { {"nct7904", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, nct7904_id); static struct i2c_driver nct7904_driver = { .class = I2C_CLASS_HWMON, -- cgit v0.10.2 From de66b380977eb9daa925aeb21756a9b00f700e45 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:43 +0200 Subject: hwmon: (g762) Export OF module alias information The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 9b55e67..85d106f 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -582,6 +582,7 @@ static const struct of_device_id g762_dt_match[] = { { .compatible = "gmt,g763" }, { }, }; +MODULE_DEVICE_TABLE(of, g762_dt_match); /* * Grab clock (a required property), enable it, get (fixed) clock frequency -- cgit v0.10.2 From e661d0a04462dd98667f8947141bd8defab5b34a Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 29 Jul 2015 14:02:19 -0700 Subject: Input: twl4030-vibra - fix ERROR: Bad of_node_put() warning Fix following: [ 8.862274] ERROR: Bad of_node_put() on /ocp/i2c@48070000/twl@48/audio [ 8.869293] CPU: 0 PID: 1003 Comm: modprobe Not tainted 4.2.0-rc2-letux+ #1175 [ 8.876922] Hardware name: Generic OMAP36xx (Flattened Device Tree) [ 8.883514] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 8.891693] [] (show_stack) from [] (dump_stack+0x78/0x94) [ 8.899322] [] (dump_stack) from [] (kobject_release+0x68/0x7c) [ 8.907409] [] (kobject_release) from [] (twl4030_vibra_probe+0x74/0x188 [twl4030_vibra]) [ 8.917877] [] (twl4030_vibra_probe [twl4030_vibra]) from [] (platform_drv_probe+0x48/0x90) [ 8.928497] [] (platform_drv_probe) from [] (really_probe+0xd4/0x238) [ 8.937103] [] (really_probe) from [] (driver_probe_device+0x30/0x48) [ 8.945678] [] (driver_probe_device) from [] (__driver_attach+0x68/0x8c) [ 8.954589] [] (__driver_attach) from [] (bus_for_each_dev+0x50/0x84) [ 8.963226] [] (bus_for_each_dev) from [] (bus_add_driver+0xcc/0x1e4) [ 8.971832] [] (bus_add_driver) from [] (driver_register+0x9c/0xe0) [ 8.980255] [] (driver_register) from [] (do_one_initcall+0x100/0x1b8) [ 8.988983] [] (do_one_initcall) from [] (do_init_module+0x58/0x1c0) [ 8.997497] [] (do_init_module) from [] (SyS_init_module+0x54/0x64) [ 9.005950] [] (SyS_init_module) from [] (ret_fast_syscall+0x0/0x54) [ 9.015838] input: twl4030:vibrator as /devices/platform/68000000.ocp/48070000.i2c/i2c-0/0-0048/48070000.i2c:twl@48:audio/input/input2 node passed to of_find_node_by_name is put inside that function and new node is returned if found. Free returned node not already freed node. Signed-off-by: Marek Belisko Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index fc17b95..10c4e3d 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, if (pdata && pdata->coexist) return true; - if (of_find_node_by_name(node, "codec")) { + node = of_find_node_by_name(node, "codec"); + if (node) { of_node_put(node); return true; } -- cgit v0.10.2 From a0e2f50bdb588d91a553f2f6bd56be7bedc94b1a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 8 Jul 2015 22:23:38 -0400 Subject: drm/amdgpu: fix rb setting for CZ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always set num_rbs to 2 for CZ. The 1 RB parts are often harvest configs. The will get sorted out in mesa when we program PA_SC_RASTER_CONFIG[_1]. Acked-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 9e1d4dd..f7538dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1983,6 +1983,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) adev->gfx.config.max_shader_engines = 1; adev->gfx.config.max_tile_pipes = 2; adev->gfx.config.max_sh_per_se = 1; + adev->gfx.config.max_backends_per_se = 2; switch (adev->pdev->revision) { case 0xc4: @@ -1991,7 +1992,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) case 0xcc: /* B10 */ adev->gfx.config.max_cu_per_sh = 8; - adev->gfx.config.max_backends_per_se = 2; break; case 0xc5: case 0x81: @@ -2000,14 +2000,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) case 0xcd: /* B8 */ adev->gfx.config.max_cu_per_sh = 6; - adev->gfx.config.max_backends_per_se = 2; break; case 0xc6: case 0xca: case 0xce: /* B6 */ adev->gfx.config.max_cu_per_sh = 6; - adev->gfx.config.max_backends_per_se = 2; break; case 0xc7: case 0x87: @@ -2015,7 +2013,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) default: /* B4 */ adev->gfx.config.max_cu_per_sh = 4; - adev->gfx.config.max_backends_per_se = 1; break; } -- cgit v0.10.2 From 0fd64291031d3587753b8adc53123b277855c777 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 1 Aug 2015 21:55:38 +0800 Subject: drm/amdgpu: increment queue when iterating on this variable. gfx_v7_0_print_status contains a for loop on variable queue which does not update this variable between each iteration. This is bug is reported by clang while building allmodconfig LLVMLinux on x86_64: drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c:5126:19: error: variable 'queue' used in loop condition not modified in loop body [-Werror,-Wloop-analysis] for (queue = 0; queue < 8; i++) { ^~~~~ Fix this by incrementing variable queue instead of i in this loop. Signed-off-by: Nicolas Iooss Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 2db6ab0..5c03420 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -5122,7 +5122,7 @@ static void gfx_v7_0_print_status(void *handle) dev_info(adev->dev, " CP_HPD_EOP_CONTROL=0x%08X\n", RREG32(mmCP_HPD_EOP_CONTROL)); - for (queue = 0; queue < 8; i++) { + for (queue = 0; queue < 8; queue++) { cik_srbm_select(adev, me, pipe, queue, 0); dev_info(adev->dev, " queue: %d\n", queue); dev_info(adev->dev, " CP_PQ_WPTR_POLL_CNTL=0x%08X\n", -- cgit v0.10.2 From 351643d7dd8a48b1053aac5fe3a1aebac614c301 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 4 Aug 2015 10:43:50 +0800 Subject: drm/amdgpu: add feature version for RLC and MEC v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose feature version to user space for RLC/MEC/MEC2 ucode as well v2: fix coding style Signed-off-by: Jammy Zhou Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 31b00f9..8db642b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1130,6 +1130,9 @@ struct amdgpu_gfx { uint32_t me_feature_version; uint32_t ce_feature_version; uint32_t pfp_feature_version; + uint32_t rlc_feature_version; + uint32_t mec_feature_version; + uint32_t mec2_feature_version; struct amdgpu_ring gfx_ring[AMDGPU_MAX_GFX_RINGS]; unsigned num_gfx_rings; struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 9736892..79eba82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -317,16 +317,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_INFO_FW_GFX_RLC: fw_info.ver = adev->gfx.rlc_fw_version; - fw_info.feature = 0; + fw_info.feature = adev->gfx.rlc_feature_version; break; case AMDGPU_INFO_FW_GFX_MEC: - if (info->query_fw.index == 0) + if (info->query_fw.index == 0) { fw_info.ver = adev->gfx.mec_fw_version; - else if (info->query_fw.index == 1) + fw_info.feature = adev->gfx.mec_feature_version; + } else if (info->query_fw.index == 1) { fw_info.ver = adev->gfx.mec2_fw_version; - else + fw_info.feature = adev->gfx.mec2_feature_version; + } else return -EINVAL; - fw_info.feature = 0; break; case AMDGPU_INFO_FW_SMC: fw_info.ver = adev->pm.fw_version; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 5c03420..0d8bf2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3080,6 +3080,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; amdgpu_ucode_print_gfx_hdr(&mec_hdr->header); adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version); + adev->gfx.mec_feature_version = le32_to_cpu( + mec_hdr->ucode_feature_version); gfx_v7_0_cp_compute_enable(adev, false); @@ -3102,6 +3104,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header); adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version); + adev->gfx.mec2_feature_version = le32_to_cpu( + mec2_hdr->ucode_feature_version); /* MEC2 */ fw_data = (const __le32 *) @@ -4066,6 +4070,8 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev) hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data; amdgpu_ucode_print_rlc_hdr(&hdr->header); adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gfx.rlc_feature_version = le32_to_cpu( + hdr->ucode_feature_version); gfx_v7_0_rlc_stop(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index f7538dd..0ac38ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -2273,6 +2273,8 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev) hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; amdgpu_ucode_print_rlc_hdr(&hdr->header); adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gfx.rlc_feature_version = le32_to_cpu( + hdr->ucode_feature_version); fw_data = (const __le32 *)(adev->gfx.rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); @@ -2620,6 +2622,8 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; amdgpu_ucode_print_gfx_hdr(&mec_hdr->header); adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version); + adev->gfx.mec_feature_version = le32_to_cpu( + mec_hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->gfx.mec_fw->data + @@ -2639,6 +2643,8 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header); adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version); + adev->gfx.mec2_feature_version = le32_to_cpu( + mec2_hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->gfx.mec2_fw->data + -- cgit v0.10.2 From cfa2104fbcb87ab0abbdaba608087df1e24fe195 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 4 Aug 2015 10:50:47 +0800 Subject: drm/amdgpu: add feature version for SDMA ucode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jammy Zhou Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 8db642b..f7b49d5c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1642,6 +1642,7 @@ struct amdgpu_sdma { /* SDMA firmware */ const struct firmware *fw; uint32_t fw_version; + uint32_t feature_version; struct amdgpu_ring ring; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 79eba82..3bfe67d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -337,7 +337,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file if (info->query_fw.index >= 2) return -EINVAL; fw_info.ver = adev->sdma[info->query_fw.index].fw_version; - fw_info.feature = 0; + fw_info.feature = adev->sdma[info->query_fw.index].feature_version; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index ab83cc1..15df46c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -500,6 +500,7 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev) amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index d789588..01bd5c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -542,6 +542,7 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev) amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->sdma[i].fw->data + diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 7bb37b9..cf9bc2e 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -631,6 +631,7 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev) amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->sdma[i].fw->data + -- cgit v0.10.2 From 595fd013f795daeed0c7ddda02d8e0c51d8ce76c Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 4 Aug 2015 11:44:19 +0800 Subject: drm/amdgpu: set fw_version and feature_version for smu fw loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fw_version and feature_verion should be set correctly when the firmwares are loaded by SMU on Tonga/Carrzio/Iceland Signed-off-by: Jammy Zhou Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 0ac38ee..f5a42ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -587,6 +587,7 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) int err; struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; + const struct gfx_firmware_header_v1_0 *cp_hdr; DRM_DEBUG("\n"); @@ -611,6 +612,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.pfp_fw); if (err) goto out; + cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data; + adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); @@ -619,6 +623,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.me_fw); if (err) goto out; + cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data; + adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); @@ -627,12 +634,18 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.ce_fw); if (err) goto out; + cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data; + adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; err = amdgpu_ucode_validate(adev->gfx.rlc_fw); + cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.rlc_fw->data; + adev->gfx.rlc_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.rlc_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); @@ -641,6 +654,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.mec_fw); if (err) goto out; + cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; + adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); + adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); @@ -648,6 +664,12 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->gfx.mec2_fw); if (err) goto out; + cp_hdr = (const struct gfx_firmware_header_v1_0 *) + adev->gfx.mec2_fw->data; + adev->gfx.mec2_fw_version = le32_to_cpu( + cp_hdr->header.ucode_version); + adev->gfx.mec2_feature_version = le32_to_cpu( + cp_hdr->ucode_feature_version); } else { err = 0; adev->gfx.mec2_fw = NULL; @@ -2272,9 +2294,6 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev) hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data; amdgpu_ucode_print_rlc_hdr(&hdr->header); - adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->gfx.rlc_feature_version = le32_to_cpu( - hdr->ucode_feature_version); fw_data = (const __le32 *)(adev->gfx.rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); @@ -2360,12 +2379,6 @@ static int gfx_v8_0_cp_gfx_load_microcode(struct amdgpu_device *adev) amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header); amdgpu_ucode_print_gfx_hdr(&ce_hdr->header); amdgpu_ucode_print_gfx_hdr(&me_hdr->header); - adev->gfx.pfp_fw_version = le32_to_cpu(pfp_hdr->header.ucode_version); - adev->gfx.ce_fw_version = le32_to_cpu(ce_hdr->header.ucode_version); - adev->gfx.me_fw_version = le32_to_cpu(me_hdr->header.ucode_version); - adev->gfx.me_feature_version = le32_to_cpu(me_hdr->ucode_feature_version); - adev->gfx.ce_feature_version = le32_to_cpu(ce_hdr->ucode_feature_version); - adev->gfx.pfp_feature_version = le32_to_cpu(pfp_hdr->ucode_feature_version); gfx_v8_0_cp_gfx_enable(adev, false); @@ -2621,9 +2634,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data; amdgpu_ucode_print_gfx_hdr(&mec_hdr->header); - adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version); - adev->gfx.mec_feature_version = le32_to_cpu( - mec_hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->gfx.mec_fw->data + @@ -2642,9 +2652,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev) mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data; amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header); - adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version); - adev->gfx.mec2_feature_version = le32_to_cpu( - mec2_hdr->ucode_feature_version); fw_data = (const __le32 *) (adev->gfx.mec2_fw->data + diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 01bd5c9..a988dfb 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -121,6 +121,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) int err, i; struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; + const struct sdma_firmware_header_v1_0 *hdr; DRM_DEBUG("\n"); @@ -142,6 +143,9 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->sdma[i].fw); if (err) goto out; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; + adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; @@ -541,9 +545,6 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev) hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; - adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - fw_data = (const __le32 *) (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index cf9bc2e..2b86569 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -159,6 +159,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) int err, i; struct amdgpu_firmware_info *info = NULL; const struct common_firmware_header *header = NULL; + const struct sdma_firmware_header_v1_0 *hdr; DRM_DEBUG("\n"); @@ -183,6 +184,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) err = amdgpu_ucode_validate(adev->sdma[i].fw); if (err) goto out; + hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; + adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; @@ -630,9 +634,6 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev) hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; amdgpu_ucode_print_sdma_hdr(&hdr->header); fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; - adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); - adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); - fw_data = (const __le32 *) (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); -- cgit v0.10.2 From df4198b1e0c4a7d1adde1e5c2ceb67ac10b391bb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 6 Aug 2015 13:54:21 +0800 Subject: virtio-input: reset device and detach unused during remove Spec requires a device reset during cleanup, so do it and avoid warn in virtio core. And detach unused buffers to avoid memory leak. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index 60e2a16..c96944b 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -313,6 +313,7 @@ err_init_vq: static void virtinput_remove(struct virtio_device *vdev) { struct virtio_input *vi = vdev->priv; + void *buf; unsigned long flags; spin_lock_irqsave(&vi->lock, flags); @@ -320,6 +321,9 @@ static void virtinput_remove(struct virtio_device *vdev) spin_unlock_irqrestore(&vi->lock, flags); input_unregister_device(vi->idev); + vdev->config->reset(vdev); + while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL) + kfree(buf); vdev->config->del_vqs(vdev); kfree(vi); } -- cgit v0.10.2 From bf64dd262eaaece2ff560e86fabf94c6725f3b5c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 3 Aug 2015 09:26:41 +0200 Subject: ARM: ux500: add an SMP enablement type and move cpu nodes The "cpus" node cannot be inside the "soc" node, while this works for the CoreSight blocks, the early boot code will look for "cpus" directly under the root node, so this is a hard convention. So move the CPU nodes. Augment the "reg" property to match what is actually in the hardware: 0x300 and 0x301 respectively. Then add an SMP enablement type to be used by the SMP init code, "ste,dbx500-smp". Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index d6b794c..91e6e5c 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -199,6 +199,7 @@ nodes to be present and contain the properties described below. "qcom,kpss-acc-v1" "qcom,kpss-acc-v2" "rockchip,rk3066-smp" + "ste,dbx500-smp" - cpu-release-addr Usage: required for systems that have an "enable-method" diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index a75f328..b8f81fb 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -15,6 +15,33 @@ #include "skeleton.dtsi" / { + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "ste,dbx500-smp"; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + }; + }; + CPU0: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0x300>; + }; + CPU1: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0x301>; + }; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -22,32 +49,6 @@ interrupt-parent = <&intc>; ranges; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu-map { - cluster0 { - core0 { - cpu = <&CPU0>; - }; - core1 { - cpu = <&CPU1>; - }; - }; - }; - CPU0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <0>; - }; - CPU1: cpu@1 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <1>; - }; - }; - ptm@801ae000 { compatible = "arm,coresight-etm3x", "arm,primecell"; reg = <0x801ae000 0x1000>; -- cgit v0.10.2 From 1a9fa190956f45c1e58c4d8bfa5ac051691ea590 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 5 Aug 2015 18:54:37 +0200 Subject: ARM: imx6: correct i.MX6 PCIe interrupt routing The PCIe interrupts are also routed through the GPC. This has been missed from the conversion to stacked IRQ domains as the PCIe controller uses an explicit interrupt map and thus doesn't inherit the SoC global interrupt parent. Signed-off-by: Lucas Stach Cc: # 4.1 Signed-off-by: Shawn Guo diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index e6d1359..b57033e 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -181,10 +181,10 @@ interrupt-names = "msi"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; - interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map = <0 0 0 1 &gpc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &gpc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &gpc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &gpc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6QDL_CLK_PCIE_AXI>, <&clks IMX6QDL_CLK_LVDS1_GATE>, <&clks IMX6QDL_CLK_PCIE_REF_125M>; -- cgit v0.10.2 From ac1125daf02b81cabb19f35963906335e3d4a155 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 5 Aug 2015 14:58:33 -0700 Subject: ASoC: rl6231: Simplify DMIC divider calculation expression Existing implementation checks all divider values and tracks 'red' proximity value for the frequency. But as divider array is monotonically increasing the first divider that gives DMIC rate in 3MHz range is the best one we should use. No need for 'red' zone tracking. Additionally make sure that DMIC frequency is higher 1MHz. Signed-off-by: Anatol Pomozov Acked-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 57e51c1..aca479f 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -62,31 +62,31 @@ int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft) EXPORT_SYMBOL_GPL(rl6231_get_pre_div); /** - * rl6231_calc_dmic_clk - Calculate the parameter of dmic. + * rl6231_calc_dmic_clk - Calculate the frequency divider parameter of dmic. * * @rate: base clock rate. * - * Choose dmic clock between 1MHz and 3MHz. - * It is better for clock to approximate 3MHz. + * Choose divider parameter that gives the highest possible DMIC frequency in + * 1MHz - 3MHz range. */ int rl6231_calc_dmic_clk(int rate) { - int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL; - int i, red, bound, temp; + int div[] = {2, 3, 4, 6, 8, 12}; + int i; + + if (rate < 1000000 * div[0]) { + pr_warn("Base clock rate %d is too low\n", rate); + return -EINVAL; + } - red = 3000000 * 12; for (i = 0; i < ARRAY_SIZE(div); i++) { - bound = div[i] * 3000000; - if (rate > bound) - continue; - temp = bound - rate; - if (temp < red) { - red = temp; - idx = i; - } + /* find divider that gives DMIC frequency below 3MHz */ + if (3000000 * div[i] >= rate) + return i; } - return idx; + pr_warn("Base clock rate %d is too high\n", rate); + return -EINVAL; } EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk); -- cgit v0.10.2 From 4ca7deb1e15e0030d04051cf4285e88249ebe252 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Aug 2015 22:34:22 +0800 Subject: ASoC: topology: Use kcalloc instead of kzalloc for array allocation Also remove unnecessary memset. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index d096068..f038c6e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1070,7 +1070,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( struct snd_soc_tplg_mixer_control *mc; int i, err; - kc = kzalloc(sizeof(*kc) * num_kcontrols, GFP_KERNEL); + kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); if (kc == NULL) return NULL; @@ -1251,7 +1251,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( struct snd_kcontrol_new *kc; int i, err; - kc = kzalloc(sizeof(*kc) * count, GFP_KERNEL); + kc = kcalloc(count, sizeof(*kc), GFP_KERNEL); if (!kc) return NULL; @@ -1274,7 +1274,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( "ASoC: adding bytes kcontrol %s with access 0x%x\n", be->hdr.name, be->hdr.access); - memset(kc, 0, sizeof(*kc)); kc[i].name = be->hdr.name; kc[i].private_value = (long)sbe; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; -- cgit v0.10.2 From cb92205bad2e4dd630b884142dd707b72504c200 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Wed, 5 Aug 2015 23:16:29 +0200 Subject: Bluetooth: fix MGMT_EV_NEW_LONG_TERM_KEY event This patch fixes how MGMT_EV_NEW_LONG_TERM_KEY event is build. Right now val vield is filled with only 1 byte, instead of whole value. This bug was introduced in commit 1fc62c526a57 ("Bluetooth: Fix exposing full value of shortened LTKs") Before that patch, if you paired with device using bluetoothd using simple pairing, and then restarted bluetoothd, you would be able to re-connect, but device would fail to establish encryption and would terminate connection. After this patch connecting after bluetoothd restart works fine. Signed-off-by: Jakub Pawlowski Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7998fb2..92720f3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7820,7 +7820,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent) /* Make sure we copy only the significant bytes based on the * encryption key size, and set the rest of the value to zeroes. */ - memcpy(ev.key.val, key->val, sizeof(key->enc_size)); + memcpy(ev.key.val, key->val, key->enc_size); memset(ev.key.val + key->enc_size, 0, sizeof(ev.key.val) - key->enc_size); -- cgit v0.10.2 From 047fe6e6db9161e69271f56daaafdaf2add023b1 Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Tue, 4 Aug 2015 16:55:52 +0300 Subject: drm/i915: Allow parsing of variable size child device entries from VBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VBT version 196 increased the size of common_child_dev_config. The parser code assumed that the size of this structure would not change. The modified code now copies the amount needed based on the VBT version, and emits a debug message if the VBT version is unknown (too new); since the struct config block won't shrink in newer versions it should be harmless to copy the maximum known size in such cases, so that's what we do, but emitting the warning is probably sensible anyway. In the longer run it might make sense to modify the parser code to use a version/feature mapping, rather than hardcoding things like this, but for now the variants are fairly managable. This fixes a regression introduced in commit 90e4f1592bb6e82f6690f0e05a8aadcf04d7bce7 Author: Ville Syrjälä Date: Wed Mar 25 18:45:58 2015 +0200 drm/i915: Fix the VBT child device parsing for BSW since we're hitting a DRM_ERROR on older platforms with this. v2: Stricter size checks Signed-off-by: David Weinehall [danvet: Fixup format string.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 198fc3c..3dcd59e 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1075,15 +1075,34 @@ parse_device_mapping(struct drm_i915_private *dev_priv, const union child_device_config *p_child; union child_device_config *child_dev_ptr; int i, child_device_num, count; - u16 block_size; + u8 expected_size; + u16 block_size; p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (!p_defs) { DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); return; } - if (p_defs->child_dev_size < sizeof(*p_child)) { - DRM_ERROR("General definiton block child device size is too small.\n"); + if (bdb->version < 195) { + expected_size = 33; + } else if (bdb->version == 195) { + expected_size = 37; + } else if (bdb->version <= 197) { + expected_size = 38; + } else { + expected_size = 38; + DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n", + expected_size, bdb->version); + } + + if (expected_size > sizeof(*p_child)) { + DRM_ERROR("child_device_config cannot fit in p_child\n"); + return; + } + + if (p_defs->child_dev_size != expected_size) { + DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n", + p_defs->child_dev_size, expected_size, bdb->version); return; } /* get the block size of general definitions */ @@ -1130,7 +1149,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, child_dev_ptr = dev_priv->vbt.child_dev + count; count++; - memcpy(child_dev_ptr, p_child, sizeof(*p_child)); + memcpy(child_dev_ptr, p_child, p_defs->child_dev_size); } return; } -- cgit v0.10.2 From bb44e154e25125bef31fa956785e90fccd24610b Mon Sep 17 00:00:00 2001 From: Tomer Barletz Date: Mon, 3 Aug 2015 12:18:13 -0700 Subject: sata_sx4: Check return code from pdc20621_i2c_read() The variable spd0 might be used uninitialized when pdc20621_i2c_read() fails. This also generates a compilation warning with gcc 5.1. tj: use pr_err() Signed-off-by: Tomer Barletz Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 3a18a8a..fab504f 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1238,8 +1238,12 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host) readl(mmio + PDC_SDRAM_CONTROL); /* Turn on for ECC */ - pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, - PDC_DIMM_SPD_TYPE, &spd0); + if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, + PDC_DIMM_SPD_TYPE, &spd0)) { + pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n", + PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE); + return 1; + } if (spd0 == 0x02) { data |= (0x01 << 16); writel(data, mmio + PDC_SDRAM_CONTROL); @@ -1380,8 +1384,12 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) /* ECC initiliazation. */ - pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, - PDC_DIMM_SPD_TYPE, &spd0); + if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, + PDC_DIMM_SPD_TYPE, &spd0)) { + pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n", + PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE); + return 1; + } if (spd0 == 0x02) { void *buf; VPRINTK("Start ECC initialization\n"); -- cgit v0.10.2 From f9114d357858c1429dcde022706db7443918f49f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Aug 2015 12:28:18 +0800 Subject: ata: ahci_brcmstb: Fix misuse of IS_ENABLED While IS_ENABLED() is perfectly fine for CONFIG_* symbols, it is not for other symbols such as __BIG_ENDIAN that is provided directly by the compiler. Switch to use CONFIG_CPU_BIG_ENDIAN instead of __BIG_ENDIAN. Signed-off-by: Axel Lin Acked-by: Florian Fainelli Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 42b6cf4..14b7305 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -92,7 +92,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr) * Other architectures (e.g., ARM) either do not support big endian, or * else leave I/O in little endian mode. */ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) return __raw_readl(addr); else return readl_relaxed(addr); @@ -101,7 +101,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr) static inline void brcm_sata_writereg(u32 val, void __iomem *addr) { /* See brcm_sata_readreg() comments */ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) __raw_writel(val, addr); else writel_relaxed(val, addr); -- cgit v0.10.2 From c05f9429e12da7c7de2649ef8c8c16bf8c12061f Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 3 Aug 2015 14:44:29 +0800 Subject: btrfs: qgroup: Fix a regression in qgroup reserved space. During the change to new btrfs extent-oriented qgroup implement, due to it doesn't use the old __qgroup_excl_accounting() for exclusive extent, it didn't free the reserved bytes. The bug will cause limit function go crazy as the reserved space is never freed, increasing limit will have no effect and still cause EQOUT. The fix is easy, just free reserved bytes for newly created exclusive extent as what it does before. Reported-by: Tsutomu Itoh Signed-off-by: Yang Dongsheng Signed-off-by: Qu Wenruo Signed-off-by: Chris Mason diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e9ace09..8a82029 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1651,6 +1651,11 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info, /* Exclusive -> exclusive, nothing changed */ } } + + /* For exclusive extent, free its reserved bytes too */ + if (nr_old_roots == 0 && nr_new_roots == 1 && + cur_new_count == nr_new_roots) + qg->reserved -= num_bytes; if (dirty) qgroup_dirty(fs_info, qg); } -- cgit v0.10.2 From de54b9ac253787c366bbfb28d901a31954eb3511 Mon Sep 17 00:00:00 2001 From: Marcus Gelderie Date: Thu, 6 Aug 2015 15:46:10 -0700 Subject: ipc: modify message queue accounting to not take kernel data structures into account A while back, the message queue implementation in the kernel was improved to use btrees to speed up retrieval of messages, in commit d6629859b36d ("ipc/mqueue: improve performance of send/recv"). That patch introducing the improved kernel handling of message queues (using btrees) has, as a by-product, changed the meaning of the QSIZE field in the pseudo-file created for the queue. Before, this field reflected the size of the user-data in the queue. Since, it also takes kernel data structures into account. For example, if 13 bytes of user data are in the queue, on my machine the file reports a size of 61 bytes. There was some discussion on this topic before (for example https://lkml.org/lkml/2014/10/1/115). Commenting on a th lkml, Michael Kerrisk gave the following background (https://lkml.org/lkml/2015/6/16/74): The pseudofiles in the mqueue filesystem (usually mounted at /dev/mqueue) expose fields with metadata describing a message queue. One of these fields, QSIZE, as originally implemented, showed the total number of bytes of user data in all messages in the message queue, and this feature was documented from the beginning in the mq_overview(7) page. In 3.5, some other (useful) work happened to break the user-space API in a couple of places, including the value exposed via QSIZE, which now includes a measure of kernel overhead bytes for the queue, a figure that renders QSIZE useless for its original purpose, since there's no way to deduce the number of overhead bytes consumed by the implementation. (The other user-space breakage was subsequently fixed.) This patch removes the accounting of kernel data structures in the queue. Reporting the size of these data-structures in the QSIZE field was a breaking change (see Michael's comment above). Without the QSIZE field reporting the total size of user-data in the queue, there is no way to deduce this number. It should be noted that the resource limit RLIMIT_MSGQUEUE is counted against the worst-case size of the queue (in both the old and the new implementation). Therefore, the kernel overhead accounting in QSIZE is not necessary to help the user understand the limitations RLIMIT imposes on the processes. Signed-off-by: Marcus Gelderie Acked-by: Doug Ledford Acked-by: Michael Kerrisk Acked-by: Davidlohr Bueso Cc: David Howells Cc: Alexander Viro Cc: John Duffy Cc: Arto Bendiken Cc: Manfred Spraul Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/ipc/mqueue.c b/ipc/mqueue.c index a24ba9f..161a180 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info) if (!leaf) return -ENOMEM; INIT_LIST_HEAD(&leaf->msg_list); - info->qsize += sizeof(*leaf); } leaf->priority = msg->m_type; rb_link_node(&leaf->rb_node, parent, p); @@ -187,7 +186,6 @@ try_again: "lazy leaf delete!\n"); rb_erase(&leaf->rb_node, &info->msg_tree); if (info->node_cache) { - info->qsize -= sizeof(*leaf); kfree(leaf); } else { info->node_cache = leaf; @@ -200,7 +198,6 @@ try_again: if (list_empty(&leaf->msg_list)) { rb_erase(&leaf->rb_node, &info->msg_tree); if (info->node_cache) { - info->qsize -= sizeof(*leaf); kfree(leaf); } else { info->node_cache = leaf; @@ -1034,7 +1031,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, /* Save our speculative allocation into the cache */ INIT_LIST_HEAD(&new_leaf->msg_list); info->node_cache = new_leaf; - info->qsize += sizeof(*new_leaf); new_leaf = NULL; } else { kfree(new_leaf); @@ -1142,7 +1138,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, /* Save our speculative allocation into the cache */ INIT_LIST_HEAD(&new_leaf->msg_list); info->node_cache = new_leaf; - info->qsize += sizeof(*new_leaf); } else { kfree(new_leaf); } -- cgit v0.10.2 From 7ace99170789bc53cbb7e9e352d7a3851208fbcf Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 6 Aug 2015 15:46:13 -0700 Subject: mm, meminit: allow early_pfn_to_nid to be used during runtime early_pfn_to_nid() historically was inherently not SMP safe but only used during boot which is inherently single threaded or during hotplug which is protected by a giant mutex. With deferred memory initialisation there was a thread-safe version introduced and the early_pfn_to_nid would trigger a BUG_ON if used unsafely. Memory hotplug hit that check. This patch makes early_pfn_to_nid introduces a lock to make it safe to use during hotplug. Signed-off-by: Mel Gorman Reported-by: Alex Ng Tested-by: Alex Ng Acked-by: Peter Zijlstra (Intel) Cc: Nicolai Stange Cc: Dave Hansen Cc: Fengguang Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ef19f22..ea0e6a6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -981,21 +981,21 @@ static void __init __free_pages_boot_core(struct page *page, #if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \ defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) -/* Only safe to use early in boot when initialisation is single-threaded */ + static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata; int __meminit early_pfn_to_nid(unsigned long pfn) { + static DEFINE_SPINLOCK(early_pfn_lock); int nid; - /* The system will behave unpredictably otherwise */ - BUG_ON(system_state != SYSTEM_BOOTING); - + spin_lock(&early_pfn_lock); nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache); - if (nid >= 0) - return nid; - /* just returns 0 */ - return 0; + if (nid < 0) + nid = 0; + spin_unlock(&early_pfn_lock); + + return nid; } #endif -- cgit v0.10.2 From d3cd131d935ab3bab700491edbbd7cad4040ce50 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Thu, 6 Aug 2015 15:46:16 -0700 Subject: mm, meminit: replace rwsem with completion Commit 0e1cc95b4cc7 ("mm: meminit: finish initialisation of struct pages before basic setup") introduced a rwsem to signal completion of the initialization workers. Lockdep complains about possible recursive locking: ============================================= [ INFO: possible recursive locking detected ] 4.1.0-12802-g1dc51b8 #3 Not tainted --------------------------------------------- swapper/0/1 is trying to acquire lock: (pgdat_init_rwsem){++++.+}, at: [] page_alloc_init_late+0xc7/0xe6 but task is already holding lock: (pgdat_init_rwsem){++++.+}, at: [] page_alloc_init_late+0x3e/0xe6 Replace the rwsem by a completion together with an atomic "outstanding work counter". [peterz@infradead.org: Barrier removal on the grounds of being pointless] [mgorman@suse.de: Applied review feedback] Signed-off-by: Nicolai Stange Signed-off-by: Mel Gorman Acked-by: Peter Zijlstra (Intel) Cc: Dave Hansen Cc: Alex Ng Cc: Fengguang Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ea0e6a6..3226282 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page, __free_pages_boot_core(page, pfn, 0); } -static __initdata DECLARE_RWSEM(pgdat_init_rwsem); +/* Completion tracking for deferred_init_memmap() threads */ +static atomic_t pgdat_init_n_undone __initdata; +static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp); + +static inline void __init pgdat_init_report_one_done(void) +{ + if (atomic_dec_and_test(&pgdat_init_n_undone)) + complete(&pgdat_init_all_done_comp); +} /* Initialise remaining memory on a node */ static int __init deferred_init_memmap(void *data) @@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data) const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); if (first_init_pfn == ULONG_MAX) { - up_read(&pgdat_init_rwsem); + pgdat_init_report_one_done(); return 0; } @@ -1177,7 +1184,8 @@ free_range: pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages, jiffies_to_msecs(jiffies - start)); - up_read(&pgdat_init_rwsem); + + pgdat_init_report_one_done(); return 0; } @@ -1185,14 +1193,14 @@ void __init page_alloc_init_late(void) { int nid; + /* There will be num_node_state(N_MEMORY) threads */ + atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY)); for_each_node_state(nid, N_MEMORY) { - down_read(&pgdat_init_rwsem); kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid); } /* Block until all are initialised */ - down_write(&pgdat_init_rwsem); - up_write(&pgdat_init_rwsem); + wait_for_completion(&pgdat_init_all_done_comp); } #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ -- cgit v0.10.2 From 4248b0da460839e30eaaad78992b9a1dd3e63e21 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 6 Aug 2015 15:46:20 -0700 Subject: fs, file table: reinit files_stat.max_files after deferred memory initialisation Dave Hansen reported the following; My laptop has been behaving strangely with 4.2-rc2. Once I log in to my X session, I start getting all kinds of strange errors from applications and see this in my dmesg: VFS: file-max limit 8192 reached The problem is that the file-max is calculated before memory is fully initialised and miscalculates how much memory the kernel is using. This patch recalculates file-max after deferred memory initialisation. Note that using memory hotplug infrastructure would not have avoided this problem as the value is not recalculated after memory hot-add. 4.1: files_stat.max_files = 6582781 4.2-rc2: files_stat.max_files = 8192 4.2-rc2 patched: files_stat.max_files = 6562467 Small differences with the patch applied and 4.1 but not enough to matter. Signed-off-by: Mel Gorman Reported-by: Dave Hansen Cc: Nicolai Stange Cc: Dave Hansen Cc: Alex Ng Cc: Fengguang Wu Cc: Peter Zijlstra (Intel) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/dcache.c b/fs/dcache.c index 5c8ea15..9b5fe50 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3442,22 +3442,15 @@ void __init vfs_caches_init_early(void) inode_init_early(); } -void __init vfs_caches_init(unsigned long mempages) +void __init vfs_caches_init(void) { - unsigned long reserve; - - /* Base hash sizes on available memory, with a reserve equal to - 150% of current kernel size */ - - reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1); - mempages -= reserve; - names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); dcache_init(); inode_init(); - files_init(mempages); + files_init(); + files_maxfiles_init(); mnt_init(); bdev_cache_init(); chrdev_init(); diff --git a/fs/file_table.c b/fs/file_table.c index 7f9d407..ad17e05 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -308,19 +309,24 @@ void put_filp(struct file *file) } } -void __init files_init(unsigned long mempages) +void __init files_init(void) { - unsigned long n; - filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + percpu_counter_init(&nr_files, 0, GFP_KERNEL); +} - /* - * One file with associated inode and dcache is very roughly 1K. - * Per default don't use more than 10% of our memory for files. - */ +/* + * One file with associated inode and dcache is very roughly 1K. Per default + * do not use more than 10% of our memory for files. + */ +void __init files_maxfiles_init(void) +{ + unsigned long n; + unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2; + + memreserve = min(memreserve, totalram_pages - 1); + n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10; - n = (mempages * (PAGE_SIZE / 1024)) / 10; files_stat.max_files = max_t(unsigned long, n, NR_FILE); - percpu_counter_init(&nr_files, 0, GFP_KERNEL); } diff --git a/include/linux/fs.h b/include/linux/fs.h index cc008c3..84b783f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -55,7 +55,8 @@ struct vm_fault; extern void __init inode_init(void); extern void __init inode_init_early(void); -extern void __init files_init(unsigned long); +extern void __init files_init(void); +extern void __init files_maxfiles_init(void); extern struct files_stat_struct files_stat; extern unsigned long get_max_files(void); @@ -2245,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp); /* fs/dcache.c */ extern void __init vfs_caches_init_early(void); -extern void __init vfs_caches_init(unsigned long); +extern void __init vfs_caches_init(void); extern struct kmem_cache *names_cachep; diff --git a/init/main.c b/init/main.c index c5d5626..5650655 100644 --- a/init/main.c +++ b/init/main.c @@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void) key_init(); security_init(); dbg_late_init(); - vfs_caches_init(totalram_pages); + vfs_caches_init(); signals_init(); /* rootfs populating might need page-writeback */ page_writeback_init(); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3226282..cb61f44e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1201,6 +1201,9 @@ void __init page_alloc_init_late(void) /* Block until all are initialised */ wait_for_completion(&pgdat_init_all_done_comp); + + /* Reinit limits that are based on free pages after the kernel is up */ + files_maxfiles_init(); } #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ -- cgit v0.10.2 From 209f7512d007980fd111a74a064d70a3656079cf Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Thu, 6 Aug 2015 15:46:23 -0700 Subject: ocfs2: fix BUG in ocfs2_downconvert_thread_do_work() The "BUG_ON(list_empty(&osb->blocked_lock_list))" in ocfs2_downconvert_thread_do_work can be triggered in the following case: ocfs2dc has firstly saved osb->blocked_lock_count to local varibale processed, and then processes the dentry lockres. During the dentry put, it calls iput and then deletes rw, inode and open lockres from blocked list in ocfs2_mark_lockres_freeing. And this causes the variable `processed' to not reflect the number of blocked lockres to be processed, which triggers the BUG. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 8b23aa2..23157e4 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -4025,9 +4025,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) osb->dc_work_sequence = osb->dc_wake_sequence; processed = osb->blocked_lock_count; - while (processed) { - BUG_ON(list_empty(&osb->blocked_lock_list)); - + /* + * blocked lock processing in this loop might call iput which can + * remove items off osb->blocked_lock_list. Downconvert up to + * 'processed' number of locks, but stop short if we had some + * removed in ocfs2_mark_lockres_freeing when downconverting. + */ + while (processed && !list_empty(&osb->blocked_lock_list)) { lockres = list_entry(osb->blocked_lock_list.next, struct ocfs2_lock_res, l_blocked_list); list_del_init(&lockres->l_blocked_list); -- cgit v0.10.2 From 3c00cb5e68dc719f2fc73a33b1b230aadfcb1309 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 6 Aug 2015 15:46:26 -0700 Subject: signal: fix information leak in copy_siginfo_from_user32 This function can leak kernel stack data when the user siginfo_t has a positive si_code value. The top 16 bits of si_code descibe which fields in the siginfo_t union are active, but they are treated inconsistently between copy_siginfo_from_user32, copy_siginfo_to_user32 and copy_siginfo_to_user. copy_siginfo_from_user32 is called from rt_sigqueueinfo and rt_tgsigqueueinfo in which the user has full control overthe top 16 bits of si_code. This fixes the following information leaks: x86: 8 bytes leaked when sending a signal from a 32-bit process to itself. This leak grows to 16 bytes if the process uses x32. (si_code = __SI_CHLD) x86: 100 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = -1) sparc: 4 bytes leaked when sending a signal from a 32-bit process to a 64-bit process. (si_code = any) parsic and s390 have similar bugs, but they are not vulnerable because rt_[tg]sigqueueinfo have checks that prevent sending a positive si_code to a different process. These bugs are also fixed for consistency. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Chris Metcalf Cc: Paul Mackerras Cc: Michael Ellerman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 1670f15..81fd38f 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -201,8 +201,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE)) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 19a7705..5d7f263 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -409,8 +409,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, 3*sizeof(int)) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE32)) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index d3a831a..da50e0c 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -966,8 +966,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s) int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) { - memset(to, 0, sizeof *to); - if (copy_from_user(to, from, 3*sizeof(int)) || copy_from_user(to->_sifields._pad, from->_sifields._pad, SI_PAD_SIZE32)) diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index e8c2c04..c667e10 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -113,8 +113,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) return -EFAULT; - memset(to, 0, sizeof(*to)); - err = __get_user(to->si_signo, &from->si_signo); err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); diff --git a/kernel/signal.c b/kernel/signal.c index 836df8d..00524cf 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3017,7 +3017,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + siginfo_t info = {}; int ret = copy_siginfo_from_user32(&info, uinfo); if (unlikely(ret)) return ret; @@ -3061,7 +3061,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, int, sig, struct compat_siginfo __user *, uinfo) { - siginfo_t info; + siginfo_t info = {}; if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; -- cgit v0.10.2 From 26135022f85105ad725cda103fa069e29e83bd16 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 6 Aug 2015 15:46:29 -0700 Subject: signal: fix information leak in copy_siginfo_to_user This function may copy the si_addr_lsb, si_lower and si_upper fields to user mode when they haven't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 81fd38f..948f0ad 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -168,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) * Other callers might not initialize the si_lsb field, * so check explicitely for the right codes here. */ - if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO) + if (from->si_signo == SIGBUS && + (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); #endif break; diff --git a/kernel/signal.c b/kernel/signal.c index 00524cf..0f6bbbe 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2748,12 +2748,15 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ - if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO) + if (from->si_signo == SIGBUS && + (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); #endif #ifdef SEGV_BNDERR - err |= __put_user(from->si_lower, &to->si_lower); - err |= __put_user(from->si_upper, &to->si_upper); + if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) { + err |= __put_user(from->si_lower, &to->si_lower); + err |= __put_user(from->si_upper, &to->si_upper); + } #endif break; case __SI_CHLD: -- cgit v0.10.2 From 3ead7c52bdb0ab44f4bb1feed505a8323cc12ba7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 6 Aug 2015 15:46:33 -0700 Subject: signalfd: fix information leak in signalfd_copyinfo This function may copy the si_addr_lsb field to user mode when it hasn't been initialized, which can leak kernel stack data to user mode. Just checking the value of si_code is insufficient because the same si_code value is shared between multiple signals. This is solved by checking the value of si_signo in addition to si_code. Signed-off-by: Amanieu d'Antras Cc: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/signalfd.c b/fs/signalfd.c index 7e412ad..270221f 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ - if (kinfo->si_code == BUS_MCEERR_AR || - kinfo->si_code == BUS_MCEERR_AO) + if (kinfo->si_signo == SIGBUS && + (kinfo->si_code == BUS_MCEERR_AR || + kinfo->si_code == BUS_MCEERR_AO)) err |= __put_user((short) kinfo->si_addr_lsb, &uinfo->ssi_addr_lsb); #endif -- cgit v0.10.2 From 3e810ae2db76ccde770fd8e5a0de6408ea36e211 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 6 Aug 2015 15:46:36 -0700 Subject: mm/slub: allow merging when SLAB_DEBUG_FREE is set This patch fixes creation of new kmem-caches after enabling sanity_checks for existing mergeable kmem-caches in runtime: before that patch creation fails because unique name in sysfs already taken by existing kmem-cache. Unlike other debug options this doesn't change object layout and could be enabled and disabled at any time. Signed-off-by: Konstantin Khlebnikov Acked-by: Christoph Lameter Cc: Pekka Enberg Acked-by: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/slab_common.c b/mm/slab_common.c index 3e5f8f2..8683110 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -37,8 +37,7 @@ struct kmem_cache *kmem_cache; SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \ SLAB_FAILSLAB) -#define SLAB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \ - SLAB_CACHE_DMA | SLAB_NOTRACK) +#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK) /* * Merge control. If this is set then no merging of slab caches will occur. -- cgit v0.10.2 From 447f6a95a9c80da7faaec3e66e656eab8f262640 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 6 Aug 2015 15:46:39 -0700 Subject: lib/iommu-common.c: do not use 0xffffffffffffffffl for computing align_mask Using a 64 bit constant generates "warning: integer constant is too large for 'long' type" on 32 bit platforms. Instead use ~0ul and BITS_PER_LONG. Detected by Andrew Morton on ARMD. Signed-off-by: Sowmini Varadhan Cc: Benjamin Herrenschmidt Cc: David S. Miller Cc: Guenter Roeck Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/iommu-common.c b/lib/iommu-common.c index df30632..ff19f66 100644 --- a/lib/iommu-common.c +++ b/lib/iommu-common.c @@ -119,7 +119,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev, unsigned long align_mask = 0; if (align_order > 0) - align_mask = 0xffffffffffffffffl >> (64 - align_order); + align_mask = ~0ul >> (BITS_PER_LONG - align_order); /* Sanity check */ if (unlikely(npages == 0)) { -- cgit v0.10.2 From 8f2f3eb59dff4ec538de55f2e0592fec85966aab Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 6 Aug 2015 15:46:42 -0700 Subject: fsnotify: fix oops in fsnotify_clear_marks_by_group_flags() fsnotify_clear_marks_by_group_flags() can race with fsnotify_destroy_marks() so that when fsnotify_destroy_mark_locked() drops mark_mutex, a mark from the list iterated by fsnotify_clear_marks_by_group_flags() can be freed and thus the next entry pointer we have cached may become stale and we dereference free memory. Fix the problem by first moving marks to free to a special private list and then always free the first entry in the special list. This method is safe even when entries from the list can disappear once we drop the lock. Signed-off-by: Jan Kara Reported-by: Ashish Sangwan Reviewed-by: Ashish Sangwan Cc: Lino Sanfilippo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 92e48c7..39ddcaf 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -412,16 +412,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags) { struct fsnotify_mark *lmark, *mark; + LIST_HEAD(to_free); + /* + * We have to be really careful here. Anytime we drop mark_mutex, e.g. + * fsnotify_clear_marks_by_inode() can come and free marks. Even in our + * to_free list so we have to use mark_mutex even when accessing that + * list. And freeing mark requires us to drop mark_mutex. So we can + * reliably free only the first mark in the list. That's why we first + * move marks to free to to_free list in one go and then free marks in + * to_free list one by one. + */ mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { - if (mark->flags & flags) { - fsnotify_get_mark(mark); - fsnotify_destroy_mark_locked(mark, group); - fsnotify_put_mark(mark); - } + if (mark->flags & flags) + list_move(&mark->g_list, &to_free); } mutex_unlock(&group->mark_mutex); + + while (1) { + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); + if (list_empty(&to_free)) { + mutex_unlock(&group->mark_mutex); + break; + } + mark = list_first_entry(&to_free, struct fsnotify_mark, g_list); + fsnotify_get_mark(mark); + fsnotify_destroy_mark_locked(mark, group); + mutex_unlock(&group->mark_mutex); + fsnotify_put_mark(mark); + } } /* -- cgit v0.10.2 From 18896451eaeee497ef5c397d76902c6376a8787d Mon Sep 17 00:00:00 2001 From: David Kershner Date: Thu, 6 Aug 2015 15:46:45 -0700 Subject: kthread: export kthread functions The s-Par visornic driver, currently in staging, processes a queue being serviced by the an s-Par service partition. We can get a message that something has happened with the Service Partition, when that happens, we must not access the channel until we get a message that the service partition is back again. The visornic driver has a thread for processing the channel, when we get the message, we need to be able to park the thread and then resume it when the problem clears. We can do this with kthread_park and unpark but they are not exported from the kernel, this patch exports the needed functions. Signed-off-by: David Kershner Acked-by: Ingo Molnar Acked-by: Neil Horman Acked-by: Thomas Gleixner Cc: Richard Weinberger Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/kthread.c b/kernel/kthread.c index 10e489c..fdea0be 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -97,6 +97,7 @@ bool kthread_should_park(void) { return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags); } +EXPORT_SYMBOL_GPL(kthread_should_park); /** * kthread_freezable_should_stop - should this freezable kthread return now? @@ -171,6 +172,7 @@ void kthread_parkme(void) { __kthread_parkme(to_kthread(current)); } +EXPORT_SYMBOL_GPL(kthread_parkme); static int kthread(void *_create) { @@ -411,6 +413,7 @@ void kthread_unpark(struct task_struct *k) if (kthread) __kthread_unpark(k, kthread); } +EXPORT_SYMBOL_GPL(kthread_unpark); /** * kthread_park - park a thread created by kthread_create(). @@ -441,6 +444,7 @@ int kthread_park(struct task_struct *k) } return ret; } +EXPORT_SYMBOL_GPL(kthread_park); /** * kthread_stop - stop a thread created by kthread_create(). -- cgit v0.10.2 From 32e5a2a2be6b085febaac36efff495ad65a55e6c Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Thu, 6 Aug 2015 15:46:48 -0700 Subject: ocfs2: fix shift left overflow When using a large volume, for example 9T volume with 2T already used, frequent creation of small files with O_DIRECT when the IO is not cluster aligned may clear sectors in the wrong place. This will cause filesystem corruption. This is because p_cpos is a u32. When calculating the corresponding sector it should be converted to u64 first, otherwise it may overflow. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: [4.0+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 1a35c61..0f5fd9d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -685,7 +685,7 @@ static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb, if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) { u64 s = i_size_read(inode); - sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) + + sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) + (do_div(s, osb->s_clustersize) >> 9); ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector, @@ -910,7 +910,7 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN)); ret = blkdev_issue_zeroout(osb->sb->s_bdev, - p_cpos << (osb->s_clustersize_bits - 9), + (u64)p_cpos << (osb->s_clustersize_bits - 9), zero_len_head >> 9, GFP_NOFS, false); if (ret < 0) mlog_errno(ret); -- cgit v0.10.2 From e298ff75f133f2524bb6a9a305b17c5f6ff1a6b2 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 6 Aug 2015 15:46:51 -0700 Subject: mm: initialize hotplugged pages as reserved Commit 92923ca3aace ("mm: meminit: only set page reserved in the memblock region") broke memory hotplug which expects the memmap for newly added sections to be reserved until onlined by online_pages_range(). This patch marks hotplugged pages as reserved when adding new zones. Signed-off-by: Mel Gorman Reported-by: David Vrabel Tested-by: David Vrabel Cc: Nathan Zimmer Cc: Robin Holt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 26fbba7..003dbe4 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -446,7 +446,7 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn) int nr_pages = PAGES_PER_SECTION; int nid = pgdat->node_id; int zone_type; - unsigned long flags; + unsigned long flags, pfn; int ret; zone_type = zone - pgdat->node_zones; @@ -461,6 +461,14 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn) pgdat_resize_unlock(zone->zone_pgdat, &flags); memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn, MEMMAP_HOTPLUG); + + /* online_page_range is called later and expects pages reserved */ + for (pfn = phys_start_pfn; pfn < phys_start_pfn + nr_pages; pfn++) { + if (!pfn_valid(pfn)) + continue; + + SetPageReserved(pfn_to_page(pfn)); + } return 0; } -- cgit v0.10.2 From e1832f2923ec92d0e590e496c8890675457f8568 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 6 Aug 2015 15:46:55 -0700 Subject: ipc: use private shmem or hugetlbfs inodes for shm segments. The shm implementation internally uses shmem or hugetlbfs inodes for shm segments. As these inodes are never directly exposed to userspace and only accessed through the shm operations which are already hooked by security modules, mark the inodes with the S_PRIVATE flag so that inode security initialization and permission checking is skipped. This was motivated by the following lockdep warning: ====================================================== [ INFO: possible circular locking dependency detected ] 4.2.0-0.rc3.git0.1.fc24.x86_64+debug #1 Tainted: G W ------------------------------------------------------- httpd/1597 is trying to acquire lock: (&ids->rwsem){+++++.}, at: shm_close+0x34/0x130 but task is already holding lock: (&mm->mmap_sem){++++++}, at: SyS_shmdt+0x4b/0x180 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&mm->mmap_sem){++++++}: lock_acquire+0xc7/0x270 __might_fault+0x7a/0xa0 filldir+0x9e/0x130 xfs_dir2_block_getdents.isra.12+0x198/0x1c0 [xfs] xfs_readdir+0x1b4/0x330 [xfs] xfs_file_readdir+0x2b/0x30 [xfs] iterate_dir+0x97/0x130 SyS_getdents+0x91/0x120 entry_SYSCALL_64_fastpath+0x12/0x76 -> #2 (&xfs_dir_ilock_class){++++.+}: lock_acquire+0xc7/0x270 down_read_nested+0x57/0xa0 xfs_ilock+0x167/0x350 [xfs] xfs_ilock_attr_map_shared+0x38/0x50 [xfs] xfs_attr_get+0xbd/0x190 [xfs] xfs_xattr_get+0x3d/0x70 [xfs] generic_getxattr+0x4f/0x70 inode_doinit_with_dentry+0x162/0x670 sb_finish_set_opts+0xd9/0x230 selinux_set_mnt_opts+0x35c/0x660 superblock_doinit+0x77/0xf0 delayed_superblock_init+0x10/0x20 iterate_supers+0xb3/0x110 selinux_complete_init+0x2f/0x40 security_load_policy+0x103/0x600 sel_write_load+0xc1/0x750 __vfs_write+0x37/0x100 vfs_write+0xa9/0x1a0 SyS_write+0x58/0xd0 entry_SYSCALL_64_fastpath+0x12/0x76 ... Signed-off-by: Stephen Smalley Reported-by: Morten Stevens Acked-by: Hugh Dickins Acked-by: Paul Moore Cc: Manfred Spraul Cc: Davidlohr Bueso Cc: Prarit Bhargava Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 0cf74df..973c24c 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -1010,6 +1010,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size, inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0); if (!inode) goto out_dentry; + if (creat_flags == HUGETLB_SHMFS_INODE) + inode->i_flags |= S_PRIVATE; file = ERR_PTR(-ENOMEM); if (hugetlb_reserve_pages(inode, 0, diff --git a/ipc/shm.c b/ipc/shm.c index 06e5cf2..4aef24d 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -545,7 +545,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) if ((shmflg & SHM_NORESERVE) && sysctl_overcommit_memory != OVERCOMMIT_NEVER) acctflag = VM_NORESERVE; - file = shmem_file_setup(name, size, acctflag); + file = shmem_kernel_file_setup(name, size, acctflag); } error = PTR_ERR(file); if (IS_ERR(file)) diff --git a/mm/shmem.c b/mm/shmem.c index 4caf8ed..dbe0c1e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3363,8 +3363,8 @@ put_path: * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be * kernel internal. There will be NO LSM permission checks against the * underlying inode. So users of this interface must do LSM checks at a - * higher layer. The one user is the big_key implementation. LSM checks - * are provided at the key level rather than the inode level. + * higher layer. The users are the big_key and shm implementations. LSM + * checks are provided at the key or shm level rather than the inode. * @name: name for dentry (to be seen in /proc//maps * @size: size to be set for the file * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size -- cgit v0.10.2 From a09233f3e1b77dbf50851660533e008056553a2a Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 6 Aug 2015 15:46:58 -0700 Subject: mm/memory-failure: unlock_page before put_page Recently I addressed a few of hwpoison race problems and the patches are merged on v4.2-rc1. It made progress, but unfortunately some problems still remain due to less coverage of my testing. So I'm trying to fix or avoid them in this series. One point I'm expecting to discuss is that patch 4/5 changes the page flag set to be checked on free time. In current behavior, __PG_HWPOISON is not supposed to be set when the page is freed. I think that there is no strong reason for this behavior, and it causes a problem hard to fix only in error handler side (because __PG_HWPOISON could be set at arbitrary timing.) So I suggest to change it. With this patchset, hwpoison stress testing in official mce-test testsuite (which previously failed) passes. This patch (of 5): In "just unpoisoned" path, we do put_page and then unlock_page, which is a wrong order and causes "freeing locked page" bug. So let's fix it. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Dean Nelson Cc: Tony Luck Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index c53543d..04d6770 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1209,9 +1209,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags) if (!PageHWPoison(p)) { printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn); atomic_long_sub(nr_pages, &num_poisoned_pages); + unlock_page(hpage); put_page(hpage); - res = 0; - goto out; + return 0; } if (hwpoison_filter(p)) { if (TestClearPageHWPoison(p)) -- cgit v0.10.2 From a209ef09af0dc921311d0cc4a1d4f926321d91b8 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 6 Aug 2015 15:47:01 -0700 Subject: mm/memory-failure: fix race in counting num_poisoned_pages When memory_failure() is called on a page which are just freed after page migration from soft offlining, the counter num_poisoned_pages is raised twi= ce. So let's fix it with using TestSetPageHWPoison. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Dean Nelson Cc: Tony Luck Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 04d6770..f72d2fa 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1671,8 +1671,8 @@ static int __soft_offline_page(struct page *page, int flags) if (ret > 0) ret = -EIO; } else { - SetPageHWPoison(page); - atomic_long_inc(&num_poisoned_pages); + if (!TestSetPageHWPoison(page)) + atomic_long_inc(&num_poisoned_pages); } } else { pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n", -- cgit v0.10.2 From 98ed2b0052e68420f1bad6c81e3f2600d25023e7 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 6 Aug 2015 15:47:04 -0700 Subject: mm/memory-failure: give up error handling for non-tail-refcounted thp "non anonymous thp" case is still racy with freeing thp, which causes panic due to put_page() for refcount-0 page. It seems that closing up this race might be hard (and/or not worth doing,) so let's give up the error handling for this case. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Dean Nelson Cc: Tony Luck Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index f72d2fa..cd98553 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -909,6 +909,18 @@ int get_hwpoison_page(struct page *page) * directly for tail pages. */ if (PageTransHuge(head)) { + /* + * Non anonymous thp exists only in allocation/free time. We + * can't handle such a case correctly, so let's give it up. + * This should be better than triggering BUG_ON when kernel + * tries to touch the "partially handled" page. + */ + if (!PageAnon(head)) { + pr_err("MCE: %#lx: non anonymous thp\n", + page_to_pfn(page)); + return 0; + } + if (get_page_unless_zero(head)) { if (PageTail(page)) get_page(page); @@ -1134,15 +1146,6 @@ int memory_failure(unsigned long pfn, int trapno, int flags) } if (!PageHuge(p) && PageTransHuge(hpage)) { - if (!PageAnon(hpage)) { - pr_err("MCE: %#lx: non anonymous thp\n", pfn); - if (TestClearPageHWPoison(p)) - atomic_long_sub(nr_pages, &num_poisoned_pages); - put_page(p); - if (p != hpage) - put_page(hpage); - return -EBUSY; - } if (unlikely(split_huge_page(hpage))) { pr_err("MCE: %#lx: thp split failed\n", pfn); if (TestClearPageHWPoison(p)) -- cgit v0.10.2 From f4c18e6f7b5bbb5b528b3334115806b0d76f50f9 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 6 Aug 2015 15:47:08 -0700 Subject: mm: check __PG_HWPOISON separately from PAGE_FLAGS_CHECK_AT_* The race condition addressed in commit add05cecef80 ("mm: soft-offline: don't free target page in successful page migration") was not closed completely, because that can happen not only for soft-offline, but also for hard-offline. Consider that a slab page is about to be freed into buddy pool, and then an uncorrected memory error hits the page just after entering __free_one_page(), then VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP) is triggered, despite the fact that it's not necessary because the data on the affected page is not consumed. To solve it, this patch drops __PG_HWPOISON from page flag checks at allocation/free time. I think it's justified because __PG_HWPOISON flags is defined to prevent the page from being reused, and setting it outside the page's alloc-free cycle is a designed behavior (not a bug.) For recent months, I was annoyed about BUG_ON when soft-offlined page remains on lru cache list for a while, which is avoided by calling put_page() instead of putback_lru_page() in page migration's success path. This means that this patch reverts a major change from commit add05cecef80 about the new refcounting rule of soft-offlined pages, so "reuse window" revives. This will be closed by a subsequent patch. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Dean Nelson Cc: Tony Luck Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index f34e040..41c9384 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -631,15 +631,19 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) 1 << PG_private | 1 << PG_private_2 | \ 1 << PG_writeback | 1 << PG_reserved | \ 1 << PG_slab | 1 << PG_swapcache | 1 << PG_active | \ - 1 << PG_unevictable | __PG_MLOCKED | __PG_HWPOISON | \ + 1 << PG_unevictable | __PG_MLOCKED | \ __PG_COMPOUND_LOCK) /* * Flags checked when a page is prepped for return by the page allocator. - * Pages being prepped should not have any flags set. It they are set, + * Pages being prepped should not have these flags set. It they are set, * there has been a kernel bug or struct page corruption. + * + * __PG_HWPOISON is exceptional because it needs to be kept beyond page's + * alloc-free cycle to prevent from reusing the page. */ -#define PAGE_FLAGS_CHECK_AT_PREP ((1 << NR_PAGEFLAGS) - 1) +#define PAGE_FLAGS_CHECK_AT_PREP \ + (((1 << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) #define PAGE_FLAGS_PRIVATE \ (1 << PG_private | 1 << PG_private_2) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c107094..097c7a4 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1676,12 +1676,7 @@ static void __split_huge_page_refcount(struct page *page, /* after clearing PageTail the gup refcount can be released */ smp_mb__after_atomic(); - /* - * retain hwpoison flag of the poisoned tail page: - * fix for the unsuitable process killed on Guest Machine(KVM) - * by the memory-failure. - */ - page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON; + page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; page_tail->flags |= (page->flags & ((1L << PG_referenced) | (1L << PG_swapbacked) | diff --git a/mm/migrate.c b/mm/migrate.c index ee401e4..f2415be 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -950,7 +950,10 @@ out: list_del(&page->lru); dec_zone_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); - if (reason != MR_MEMORY_FAILURE) + /* Soft-offlined page shouldn't go through lru cache list */ + if (reason == MR_MEMORY_FAILURE) + put_page(page); + else putback_lru_page(page); } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index cb61f44e..beda417 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1296,6 +1296,10 @@ static inline int check_new_page(struct page *page) bad_reason = "non-NULL mapping"; if (unlikely(atomic_read(&page->_count) != 0)) bad_reason = "nonzero _count"; + if (unlikely(page->flags & __PG_HWPOISON)) { + bad_reason = "HWPoisoned (hardware-corrupted)"; + bad_flags = __PG_HWPOISON; + } if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) { bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set"; bad_flags = PAGE_FLAGS_CHECK_AT_PREP; -- cgit v0.10.2 From 4491f7126063ef51081f5662bd4fcae31621a333 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 6 Aug 2015 15:47:11 -0700 Subject: mm/memory-failure: set PageHWPoison before migrate_pages() Now page freeing code doesn't consider PageHWPoison as a bad page, so by setting it before completing the page containment, we can prevent the error page from being reused just after successful page migration. I added TTU_IGNORE_HWPOISON for try_to_unmap() to make sure that the page table entry is transformed into migration entry, not to hwpoison entry. Signed-off-by: Naoya Horiguchi Cc: Andi Kleen Cc: Dean Nelson Cc: Tony Luck Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index cd98553..ea5a936 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1659,6 +1659,8 @@ static int __soft_offline_page(struct page *page, int flags) inc_zone_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); list_add(&page->lru, &pagelist); + if (!TestSetPageHWPoison(page)) + atomic_long_inc(&num_poisoned_pages); ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL, MIGRATE_SYNC, MR_MEMORY_FAILURE); if (ret) { @@ -1673,9 +1675,8 @@ static int __soft_offline_page(struct page *page, int flags) pfn, ret, page->flags); if (ret > 0) ret = -EIO; - } else { - if (!TestSetPageHWPoison(page)) - atomic_long_inc(&num_poisoned_pages); + if (TestClearPageHWPoison(page)) + atomic_long_dec(&num_poisoned_pages); } } else { pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n", diff --git a/mm/migrate.c b/mm/migrate.c index f2415be..eb42671 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -880,7 +880,8 @@ static int __unmap_and_move(struct page *page, struct page *newpage, /* Establish migration ptes or remove ptes */ if (page_mapped(page)) { try_to_unmap(page, - TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); + TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS| + TTU_IGNORE_HWPOISON); page_was_mapped = 1; } -- cgit v0.10.2 From a50fcb512d9539b5179b1e523641420339086995 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 6 Aug 2015 15:47:14 -0700 Subject: writeback: fix initial dirty limit The initial value of global_wb_domain.dirty_limit set by writeback_set_ratelimit() is zeroed out by the memset in wb_domain_init(). Signed-off-by: Rabin Vincent Acked-by: Tejun Heo Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 22cddd3..5cccc12 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2063,10 +2063,10 @@ static struct notifier_block ratelimit_nb = { */ void __init page_writeback_init(void) { + BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL)); + writeback_set_ratelimit(); register_cpu_notifier(&ratelimit_nb); - - BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL)); } /** -- cgit v0.10.2 From 14d2b7c1a96ef37eb571599c73d4a1a606b964d6 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Aug 2015 17:50:11 +0200 Subject: net: fec: fix initial runtime PM refcount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clocks are initially active and thus the device is marked active. This still keeps the PM refcount at 0, the pm_runtime_put_autosuspend() call at the end of probe then leaves us with an invalid refcount of -1, which in turn leads to the device staying in suspended state even though netdev open had been called. Fix this by initializing the refcount to be coherent with the initial device status. Fixes: 8fff755e9f8 (net: fec: Ensure clocks are enabled while using mdio bus) Signed-off-by: Lucas Stach Tested-by: Uwe Kleine-König Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 32e3807c..271bb58 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3433,6 +3433,7 @@ fec_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); -- cgit v0.10.2 From 44922150d87cef616fd183220d43d8fde4d41390 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 6 Aug 2015 19:13:25 -0700 Subject: sparc64: Fix userspace FPU register corruptions. If we have a series of events from userpsace, with %fprs=FPRS_FEF, like follows: ETRAP ETRAP VIS_ENTRY(fprs=0x4) VIS_EXIT RTRAP (kernel FPU restore with fpu_saved=0x4) RTRAP We will not restore the user registers that were clobbered by the FPU using kernel code in the inner-most trap. Traps allocate FPU save slots in the thread struct, and FPU using sequences save the "dirty" FPU registers only. This works at the initial trap level because all of the registers get recorded into the top-level FPU save area, and we'll return to userspace with the FPU disabled so that any FPU use by the user will take an FPU disabled trap wherein we'll load the registers back up properly. But this is not how trap returns from kernel to kernel operate. The simplest fix for this bug is to always save all FPU register state for anything other than the top-most FPU save area. Getting rid of the optimized inner-slot FPU saving code ends up making VISEntryHalf degenerate into plain VISEntry. Longer term we need to do something smarter to reinstate the partial save optimizations. Perhaps the fundament error is having trap entry and exit allocate FPU save slots and restore register state. Instead, the VISEntry et al. calls should be doing that work. This bug is about two decades old. Reported-by: James Y Knight Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h index 1f0aa20..6424249 100644 --- a/arch/sparc/include/asm/visasm.h +++ b/arch/sparc/include/asm/visasm.h @@ -28,16 +28,10 @@ * Must preserve %o5 between VISEntryHalf and VISExitHalf */ #define VISEntryHalf \ - rd %fprs, %o5; \ - andcc %o5, FPRS_FEF, %g0; \ - be,pt %icc, 297f; \ - sethi %hi(298f), %g7; \ - sethi %hi(VISenterhalf), %g1; \ - jmpl %g1 + %lo(VISenterhalf), %g0; \ - or %g7, %lo(298f), %g7; \ - clr %o5; \ -297: wr %o5, FPRS_FEF, %fprs; \ -298: + VISEntry + +#define VISExitHalf \ + VISExit #define VISEntryHalfFast(fail_label) \ rd %fprs, %o5; \ @@ -47,7 +41,7 @@ ba,a,pt %xcc, fail_label; \ 297: wr %o5, FPRS_FEF, %fprs; -#define VISExitHalf \ +#define VISExitHalfFast \ wr %o5, 0, %fprs; #ifndef __ASSEMBLY__ diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S index 140527a..83aeeb1 100644 --- a/arch/sparc/lib/NG4memcpy.S +++ b/arch/sparc/lib/NG4memcpy.S @@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */ add %o0, 0x40, %o0 bne,pt %icc, 1b LOAD(prefetch, %g1 + 0x200, #n_reads_strong) +#ifdef NON_USER_COPY + VISExitHalfFast +#else VISExitHalf - +#endif brz,pn %o2, .Lexit cmp %o2, 19 ble,pn %icc, .Lsmall_unaligned diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S index b320ae9..a063d84 100644 --- a/arch/sparc/lib/VISsave.S +++ b/arch/sparc/lib/VISsave.S @@ -44,9 +44,8 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 stx %g3, [%g6 + TI_GSR] 2: add %g6, %g1, %g3 - cmp %o5, FPRS_DU - be,pn %icc, 6f - sll %g1, 3, %g1 + mov FPRS_DU | FPRS_DL | FPRS_FEF, %o5 + sll %g1, 3, %g1 stb %o5, [%g3 + TI_FPSAVED] rd %gsr, %g2 add %g6, %g1, %g3 @@ -80,65 +79,3 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 .align 32 80: jmpl %g7 + %g0, %g0 nop - -6: ldub [%g3 + TI_FPSAVED], %o5 - or %o5, FPRS_DU, %o5 - add %g6, TI_FPREGS+0x80, %g2 - stb %o5, [%g3 + TI_FPSAVED] - - sll %g1, 5, %g1 - add %g6, TI_FPREGS+0xc0, %g3 - wr %g0, FPRS_FEF, %fprs - membar #Sync - stda %f32, [%g2 + %g1] ASI_BLK_P - stda %f48, [%g3 + %g1] ASI_BLK_P - membar #Sync - ba,pt %xcc, 80f - nop - - .align 32 -80: jmpl %g7 + %g0, %g0 - nop - - .align 32 -VISenterhalf: - ldub [%g6 + TI_FPDEPTH], %g1 - brnz,a,pn %g1, 1f - cmp %g1, 1 - stb %g0, [%g6 + TI_FPSAVED] - stx %fsr, [%g6 + TI_XFSR] - clr %o5 - jmpl %g7 + %g0, %g0 - wr %g0, FPRS_FEF, %fprs - -1: bne,pn %icc, 2f - srl %g1, 1, %g1 - ba,pt %xcc, vis1 - sub %g7, 8, %g7 -2: addcc %g6, %g1, %g3 - sll %g1, 3, %g1 - andn %o5, FPRS_DU, %g2 - stb %g2, [%g3 + TI_FPSAVED] - - rd %gsr, %g2 - add %g6, %g1, %g3 - stx %g2, [%g3 + TI_GSR] - add %g6, %g1, %g2 - stx %fsr, [%g2 + TI_XFSR] - sll %g1, 5, %g1 -3: andcc %o5, FPRS_DL, %g0 - be,pn %icc, 4f - add %g6, TI_FPREGS, %g2 - - add %g6, TI_FPREGS+0x40, %g3 - membar #Sync - stda %f0, [%g2 + %g1] ASI_BLK_P - stda %f16, [%g3 + %g1] ASI_BLK_P - membar #Sync - ba,pt %xcc, 4f - nop - - .align 32 -4: and %o5, FPRS_DU, %o5 - jmpl %g7 + %g0, %g0 - wr %o5, FPRS_FEF, %fprs diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 1d649a9..8069ce1 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -135,10 +135,6 @@ EXPORT_SYMBOL(copy_user_page); void VISenter(void); EXPORT_SYMBOL(VISenter); -/* CRYPTO code needs this */ -void VISenterhalf(void); -EXPORT_SYMBOL(VISenterhalf); - extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, unsigned long *); -- cgit v0.10.2 From a0a2a6602496a45ae838a96db8b8173794b5d398 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 4 Aug 2015 15:42:47 +0800 Subject: net: Fix skb_set_peeked use-after-free bug The commit 738ac1ebb96d02e0d23bc320302a6ea94c612dec ("net: Clone skb before setting peeked flag") introduced a use-after-free bug in skb_recv_datagram. This is because skb_set_peeked may create a new skb and free the existing one. As it stands the caller will continue to use the old freed skb. This patch fixes it by making skb_set_peeked return the new skb (or the old one if unchanged). Fixes: 738ac1ebb96d ("net: Clone skb before setting peeked flag") Reported-by: Brenden Blanco Signed-off-by: Herbert Xu Tested-by: Brenden Blanco Reviewed-by: Konstantin Khlebnikov Signed-off-by: David S. Miller diff --git a/net/core/datagram.c b/net/core/datagram.c index 4967262..617088a 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -131,12 +131,12 @@ out_noerr: goto out; } -static int skb_set_peeked(struct sk_buff *skb) +static struct sk_buff *skb_set_peeked(struct sk_buff *skb) { struct sk_buff *nskb; if (skb->peeked) - return 0; + return skb; /* We have to unshare an skb before modifying it. */ if (!skb_shared(skb)) @@ -144,7 +144,7 @@ static int skb_set_peeked(struct sk_buff *skb) nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); skb->prev->next = nskb; skb->next->prev = nskb; @@ -157,7 +157,7 @@ static int skb_set_peeked(struct sk_buff *skb) done: skb->peeked = 1; - return 0; + return skb; } /** @@ -229,8 +229,9 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, continue; } - error = skb_set_peeked(skb); - if (error) + skb = skb_set_peeked(skb); + error = PTR_ERR(skb); + if (IS_ERR(skb)) goto unlock_err; atomic_inc(&skb->users); -- cgit v0.10.2 From 57b229063ae6dc65036209018dc7f4290cc026bb Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 4 Aug 2015 15:40:59 +0100 Subject: xen/netback: Wake dealloc thread after completing zerocopy work Waking the dealloc thread before decrementing inflight_packets is racy because it means the thread may go to sleep before inflight_packets is decremented. If kthread_stop() has already been called, the dealloc thread may wait forever with nothing to wake it. Instead, wake the thread only after decrementing inflight_packets. Signed-off-by: Ross Lagerwall Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 1a83e19..28577a3 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -61,6 +61,12 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue) { atomic_dec(&queue->inflight_packets); + + /* Wake the dealloc thread _after_ decrementing inflight_packets so + * that if kthread_stop() has already been called, the dealloc thread + * does not wait forever with nothing to wake it. + */ + wake_up(&queue->dealloc_wq); } int xenvif_schedulable(struct xenvif *vif) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1b406e7..3f44b52 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1541,7 +1541,6 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) smp_wmb(); queue->dealloc_prod++; } while (ubuf); - wake_up(&queue->dealloc_wq); spin_unlock_irqrestore(&queue->callback_lock, flags); if (likely(zerocopy_success)) -- cgit v0.10.2 From 7ba8bd75ddc6b041b5716dbb29e49df3e9cc2928 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 4 Aug 2015 18:33:34 +0200 Subject: net: pktgen: don't abuse current->state in pktgen_thread_worker() Commit 1fbe4b46caca "net: pktgen: kill the Wait for kthread_stop code in pktgen_thread_worker()" removed (in particular) the final __set_current_state(TASK_RUNNING) and I didn't notice the previous set_current_state(TASK_INTERRUPTIBLE). This triggers the warning in __might_sleep() after return. Afaics, we can simply remove both set_current_state()'s, and we could do this a long ago right after ef87979c273a2 "pktgen: better scheduler friendliness" which changed pktgen_thread_worker() to use wait_event_interruptible_timeout(). Reported-by: Huang Ying Signed-off-by: Oleg Nesterov Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 1ebdf1c..1cbd209 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3514,8 +3514,6 @@ static int pktgen_thread_worker(void *arg) set_freezable(); - __set_current_state(TASK_RUNNING); - while (!kthread_should_stop()) { pkt_dev = next_to_run(t); @@ -3560,7 +3558,6 @@ static int pktgen_thread_worker(void *arg) try_to_freeze(); } - set_current_state(TASK_INTERRUPTIBLE); pr_debug("%s stopping all device\n", t->tsk->comm); pktgen_stop(t); -- cgit v0.10.2 From 355b9f9df1f0311f20087350aee8ad96eedca8a9 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 4 Aug 2015 19:06:32 +0200 Subject: bridge: netlink: account for the IFLA_BRPORT_PROXYARP attribute size and policy The attribute size wasn't accounted for in the get_slave_size() callback (br_port_get_slave_size) when it was introduced, so fix it now. Also add a policy entry for it in br_port_policy. Signed-off-by: Nikolay Aleksandrov Fixes: 958501163ddd ("bridge: Add support for IEEE 802.11 Proxy ARP") Signed-off-by: David S. Miller diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 3da5525..5390536 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -112,6 +112,7 @@ static inline size_t br_port_info_size(void) + nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */ + nla_total_size(1) /* IFLA_BRPORT_LEARNING */ + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */ + + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */ + 0; } @@ -506,6 +507,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 }, [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, + [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 }, }; /* Change the state of the port and notify spanning tree */ -- cgit v0.10.2 From 786c2077ec8e9eab37a88fc14aac4309a8061e18 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 4 Aug 2015 19:06:33 +0200 Subject: bridge: netlink: account for the IFLA_BRPORT_PROXYARP_WIFI attribute size and policy The attribute size wasn't accounted for in the get_slave_size() callback (br_port_get_slave_size) when it was introduced, so fix it now. Also add a policy entry for it in br_port_policy. Signed-off-by: Nikolay Aleksandrov Fixes: 842a9ae08a25 ("bridge: Extend Proxy ARP design to allow optional rules for Wi-Fi") Signed-off-by: David S. Miller diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 5390536..4d74a06 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -113,6 +113,7 @@ static inline size_t br_port_info_size(void) + nla_total_size(1) /* IFLA_BRPORT_LEARNING */ + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */ + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */ + + nla_total_size(1) /* IFLA_BRPORT_PROXYARP_WIFI */ + 0; } @@ -508,6 +509,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 }, + [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 }, }; /* Change the state of the port and notify spanning tree */ -- cgit v0.10.2 From 7ebc482202fd54e7cf718619e869f4320b8e3bb6 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 4 Aug 2015 22:11:43 +0200 Subject: r8169: enforce RX_MULTI_EN on rtl8168ep/8111ep chips Enforcing this flag in RxConfig for the mentioned chips fixes netdev watchdog issues prepended with AMD IOMMU message(s) like: AMD-Vi: Event logged [IO_PAGE_FAULT device=01:00.0 domain=0x001d address=0x0000000000003000 flags=0x0050] Note that this flag is also set in Realtek's own driver for these chips. Signed-off-by: Ivan Vecera Tested-by: Alexander Lindqvist Acked-by: Francois Romieu Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 3df51fa..f790f61 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -4875,10 +4875,12 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_46: case RTL_GIGA_MAC_VER_47: case RTL_GIGA_MAC_VER_48: + RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF); + break; case RTL_GIGA_MAC_VER_49: case RTL_GIGA_MAC_VER_50: case RTL_GIGA_MAC_VER_51: - RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF); + RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); break; default: RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST); -- cgit v0.10.2 From 22f54bf932a0eed73134b696b238db4bdcff5cd4 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 4 Aug 2015 20:25:55 +0100 Subject: net: thunderx: remove effective "default y" from Kconfig if ARCH_THUNDER=y As well as for kernels built only for ThunderX ARCH_THUNDERX is also enabled for kernels which support multiple platforms (such as distro kernels). Thus "default ARCH_THUNDER" is inappropriate. I believe default m is equally frowned upon, so remove the line completely rather than "default m if ARCH_THUNDER". Signed-off-by: Ian Campbell Cc: Sunil Goutham Cc: Robert Richter Cc: Derek Chickles Cc: Satanand Burla Cc: Felix Manlunas Cc: Raghu Vatsavayi Cc: Arnd Bergmann Cc: linux-arm-kernel@lists.infradead.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index c4d6bbe..02e23e6 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -16,7 +16,6 @@ if NET_VENDOR_CAVIUM config THUNDER_NIC_PF tristate "Thunder Physical function driver" depends on 64BIT - default ARCH_THUNDER select THUNDER_NIC_BGX ---help--- This driver supports Thunder's NIC physical function. @@ -29,14 +28,12 @@ config THUNDER_NIC_PF config THUNDER_NIC_VF tristate "Thunder Virtual function driver" depends on 64BIT - default ARCH_THUNDER ---help--- This driver supports Thunder's NIC virtual function config THUNDER_NIC_BGX tristate "Thunder MAC interface driver (BGX)" depends on 64BIT - default ARCH_THUNDER ---help--- This driver supports programming and controlling of MAC interface from NIC physical function driver. -- cgit v0.10.2 From 866b8b18e380f810ba96e21d25843b841271bb07 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Tue, 4 Aug 2015 16:56:53 -0400 Subject: net: netcp: fix unused interface rx buffer size configuration Prior to this patch, rx buffer size for each rx queue of an interface is configurable through dts bindings. But for an interface, the first rx queue's rx buffer size is always the usual MTU size (plus usual overhead) and page size for the remaining rx queues (if they are enabled by specifying a non-zero rx queue depth dts binding of the corresponding interface). This patch removes the rx buffer size configuration capability. Signed-off-by: WingMan Kwok Acked-by: Murali Karicheri Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h index a8a7306..bb1bb72 100644 --- a/drivers/net/ethernet/ti/netcp.h +++ b/drivers/net/ethernet/ti/netcp.h @@ -85,7 +85,6 @@ struct netcp_intf { struct list_head rxhook_list_head; unsigned int rx_queue_id; void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN]; - u32 rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN]; struct napi_struct rx_napi; struct napi_struct tx_napi; diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 9749dfd..4755838 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -34,6 +34,7 @@ #define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD) #define NETCP_NAPI_WEIGHT 64 #define NETCP_TX_TIMEOUT (5 * HZ) +#define NETCP_PACKET_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN) #define NETCP_MIN_PACKET_SIZE ETH_ZLEN #define NETCP_MAX_MCAST_ADDR 16 @@ -804,30 +805,28 @@ static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq) if (likely(fdq == 0)) { unsigned int primary_buf_len; /* Allocate a primary receive queue entry */ - buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET; + buf_len = NETCP_PACKET_SIZE + NETCP_SOP_OFFSET; primary_buf_len = SKB_DATA_ALIGN(buf_len) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - if (primary_buf_len <= PAGE_SIZE) { - bufptr = netdev_alloc_frag(primary_buf_len); - pad[1] = primary_buf_len; - } else { - bufptr = kmalloc(primary_buf_len, GFP_ATOMIC | - GFP_DMA32 | __GFP_COLD); - pad[1] = 0; - } + bufptr = netdev_alloc_frag(primary_buf_len); + pad[1] = primary_buf_len; if (unlikely(!bufptr)) { - dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n"); + dev_warn_ratelimited(netcp->ndev_dev, + "Primary RX buffer alloc failed\n"); goto fail; } dma = dma_map_single(netcp->dev, bufptr, buf_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(netcp->dev, dma))) + goto fail; + pad[0] = (u32)bufptr; } else { /* Allocate a secondary receive queue entry */ - page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD); + page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD); if (unlikely(!page)) { dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n"); goto fail; @@ -1010,7 +1009,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp) /* Map the linear buffer */ dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE); - if (unlikely(!dma_addr)) { + if (unlikely(dma_mapping_error(dev, dma_addr))) { dev_err(netcp->ndev_dev, "Failed to map skb buffer\n"); return NULL; } @@ -1546,8 +1545,8 @@ static int netcp_setup_navigator_resources(struct net_device *ndev) knav_queue_disable_notify(netcp->rx_queue); /* open Rx FDQs */ - for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && - netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) { + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_queue_depths[i]; + ++i) { snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i); netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0); if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) { @@ -1941,14 +1940,6 @@ static int netcp_create_interface(struct netcp_device *netcp_device, netcp->rx_queue_depths[0] = 128; } - ret = of_property_read_u32_array(node_interface, "rx-buffer-size", - netcp->rx_buffer_sizes, - KNAV_DMA_FDQ_PER_CHAN); - if (ret) { - dev_err(dev, "missing \"rx-buffer-size\" parameter\n"); - netcp->rx_buffer_sizes[0] = 1536; - } - ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2); if (ret < 0) { dev_err(dev, "missing \"rx-pool\" parameter\n"); -- cgit v0.10.2 From 4f7eb70f7be1099236670f36b2f1f90a63e29699 Mon Sep 17 00:00:00 2001 From: Mathieu Olivari Date: Tue, 4 Aug 2015 17:25:02 -0700 Subject: stmmac: dwmac-ipq806x: fix static checker warning The patch b1c17215d718: "stmmac: add ipq806x glue layer", leads to the following static checker warning: .../stmmac/dwmac-ipq806x.c:314 ipq806x_gmac_probe() warn: double left shift '1 << (1 << gmac->id)' The NSS_COMMON_CLK_SRC_CTRL_OFFSET macro is used once as an offset, and once as a mask, which is a bug indeed. We'll fix it by defining the offset as the real offset value and computing the mask from it when required. Tested on IPQ806x ref designs AP148 & DB149. Reported-by: Dan Carpenter Signed-off-by: Mathieu Olivari Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 7e3129e..f0e4bb4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -42,7 +42,7 @@ #define NSS_COMMON_CLK_DIV_MASK 0x7f #define NSS_COMMON_CLK_SRC_CTRL 0x14 -#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (1 << x) +#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x) /* Mode is coded on 1 bit but is different depending on the MAC ID: * MAC0: QSGMII=0 RGMII=1 * MAC1: QSGMII=0 SGMII=0 RGMII=1 @@ -291,7 +291,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev) /* Configure the clock src according to the mode */ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val); - val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id); + val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id)); switch (gmac->phy_mode) { case PHY_INTERFACE_MODE_RGMII: val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) << -- cgit v0.10.2 From 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 5 Aug 2015 10:34:04 +0800 Subject: virtio-net: drop NETIF_F_FRAGLIST virtio declares support for NETIF_F_FRAGLIST, but assumes that there are at most MAX_SKB_FRAGS + 2 fragments which isn't always true with a fraglist. A longer fraglist in the skb will make the call to skb_to_sgvec overflow the sg array, leading to memory corruption. Drop NETIF_F_FRAGLIST so we only get what we can handle. Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7fbca37..237f8e5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1756,9 +1756,9 @@ static int virtnet_probe(struct virtio_device *vdev) /* Do we support "hardware" checksums? */ if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ - dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (csum) - dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO -- cgit v0.10.2 From 10971638701dedadb58c88ce4d31c9375b224ed6 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 7 Aug 2015 13:01:39 +0530 Subject: ARCv2: spinlock/rwlock/atomics: reduce 1 instruction in exponential backoff The increment of delay counter was 2 instructions: Arithmatic Shfit Left (ASL) + set to 1 on overflow This can be done in 1 using ROtate Left (ROL) Suggested-by: Nigel Topham Cc: Peter Zijlstra (Intel) Cc: linux-kernel@vger.kernel.org Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 629dfd0..87d18ae 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -34,8 +34,7 @@ " mov %[tmp], %[delay] \n" /* tmp = delay */ \ "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \ " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \ - " asl.f %[delay], %[delay], 1 \n" /* delay *= 2 */ \ - " mov.z %[delay], 1 \n" /* handle overflow */ \ + " rol %[delay], %[delay] \n" /* delay *= 2 */ \ " b 1b \n" /* start over */ \ "4: ; --- success --- \n" \ diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index 7071fc0..db8c59d 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -260,8 +260,7 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) " mov %[tmp], %[delay] \n" /* tmp = delay */ \ "2: brne.d %[tmp], 0, 2b \n" /* while (tmp != 0) */ \ " sub %[tmp], %[tmp], 1 \n" /* tmp-- */ \ - " asl.f %[delay], %[delay], 1 \n" /* delay *= 2 */ \ - " mov.z %[delay], 1 \n" /* handle overflow */ \ + " rol %[delay], %[delay] \n" /* delay *= 2 */ \ " b 1b \n" /* start over */ \ " \n" \ "4: ; --- done --- \n" \ -- cgit v0.10.2 From 18c3626e3d5dfa8b90e2dc6dbc30064c0e1c97ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 7 Aug 2015 12:27:54 +0200 Subject: KVM: x86: zero IDT limit on entry to SMM The recent BlackHat 2015 presentation "The Memory Sinkhole" mentions that the IDT limit is zeroed on entry to SMM. This is not documented, and must have changed some time after 2010 (see http://www.ssi.gouv.fr/uploads/IMG/pdf/IT_Defense_2010_final.pdf). KVM was not doing it, but the fix is easy. Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5ef2560..c5e88a8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6327,6 +6327,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf) static void process_smi(struct kvm_vcpu *vcpu) { struct kvm_segment cs, ds; + struct desc_ptr dt; char buf[512]; u32 cr0; @@ -6359,6 +6360,10 @@ static void process_smi(struct kvm_vcpu *vcpu) kvm_x86_ops->set_cr4(vcpu, 0); + /* Undocumented: IDT limit is set to zero on entry to SMM. */ + dt.address = dt.size = 0; + kvm_x86_ops->set_idt(vcpu, &dt); + __kvm_set_dr(vcpu, 7, DR7_FIXED_1); cs.selector = (vcpu->arch.smbase >> 4) & 0xffff; -- cgit v0.10.2 From d7add05458084a5e3d65925764a02ca9c8202c1e Mon Sep 17 00:00:00 2001 From: Haozhong Zhang Date: Fri, 7 Aug 2015 11:24:32 +0800 Subject: KVM: x86: Use adjustment in guest cycles when handling MSR_IA32_TSC_ADJUST When kvm_set_msr_common() handles a guest's write to MSR_IA32_TSC_ADJUST, it will calcuate an adjustment based on the data written by guest and then use it to adjust TSC offset by calling a call-back adjust_tsc_offset(). The 3rd parameter of adjust_tsc_offset() indicates whether the adjustment is in host TSC cycles or in guest TSC cycles. If SVM TSC scaling is enabled, adjust_tsc_offset() [i.e. svm_adjust_tsc_offset()] will first scale the adjustment; otherwise, it will just use the unscaled one. As the MSR write here comes from the guest, the adjustment is in guest TSC cycles. However, the current kvm_set_msr_common() uses it as a value in host TSC cycles (by using true as the 3rd parameter of adjust_tsc_offset()), which can result in an incorrect adjustment of TSC offset if SVM TSC scaling is enabled. This patch fixes this problem. Signed-off-by: Haozhong Zhang Cc: stable@vger.linux.org Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c5e88a8..8f0f6ec 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2105,7 +2105,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (guest_cpuid_has_tsc_adjust(vcpu)) { if (!msr_info->host_initiated) { s64 adj = data - vcpu->arch.ia32_tsc_adjust_msr; - kvm_x86_ops->adjust_tsc_offset(vcpu, adj, true); + adjust_tsc_offset_guest(vcpu, adj); } vcpu->arch.ia32_tsc_adjust_msr = data; } -- cgit v0.10.2 From b42e093e59c320e91b9c2de73bf3f0429fc45307 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:36 +0200 Subject: ASoC: intel: use kmemdup rather than duplicating its implementation The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Signed-off-by: Mark Brown diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 5a27861..3dc7358 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -352,10 +352,9 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, * copy from mailbox **/ if (msg_high.part.large) { - data = kzalloc(msg_low, GFP_KERNEL); + data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL); if (!data) return; - memcpy(data, (void *) msg->mailbox_data, msg_low); /* Copy command id so that we can use to put sst to reset */ dsp_hdr = (struct ipc_dsp_hdr *)data; cmd_id = dsp_hdr->cmd_id; -- cgit v0.10.2 From 376c0afe2f0047d091956a95e382e1edd104ea72 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:37 +0200 Subject: ASoC: topology: use kmemdup rather than duplicating its implementation The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Signed-off-by: Mark Brown diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f038c6e..8620dbf 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -832,12 +832,12 @@ static int soc_tplg_denum_create_values(struct soc_enum *se, if (ec->items > sizeof(*ec->values)) return -EINVAL; - se->dobj.control.dvalues = - kmalloc(ec->items * sizeof(u32), GFP_KERNEL); + se->dobj.control.dvalues = kmemdup(ec->values, + ec->items * sizeof(u32), + GFP_KERNEL); if (!se->dobj.control.dvalues) return -ENOMEM; - memcpy(se->dobj.control.dvalues, ec->values, ec->items * sizeof(u32)); return 0; } -- cgit v0.10.2 From 209e4dbc8dcdb2b1839f18fd1cf07ec7bedadf4d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Aug 2015 12:31:17 +0200 Subject: drm/vblank: Use u32 consistently for vblank counters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 99264a61dfcda41d86d0960cf2d4c0fc2758a773 Author: Daniel Vetter Date: Wed Apr 15 19:34:43 2015 +0200 drm/vblank: Fixup and document timestamp update/read barriers I've switched vblank->count from atomic_t to unsigned long and accidentally created an integer comparison bug in drm_vblank_count_and_time since vblanke->count might overflow the u32 local copy and hence the retry loop never succeed. Fix this by consistently using u32. Cc: Michel Dänzer Reported-by: Michel Dänzer Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f9cc68f..b50fa0a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -75,7 +75,7 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600) module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); static void store_vblank(struct drm_device *dev, int crtc, - unsigned vblank_count_inc, + u32 vblank_count_inc, struct timeval *t_vblank) { struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 48db6a5..5aa5197 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -691,7 +691,7 @@ struct drm_vblank_crtc { struct timer_list disable_timer; /* delayed disable timer */ /* vblank counter, protected by dev->vblank_time_lock for writes */ - unsigned long count; + u32 count; /* vblank timestamps, protected by dev->vblank_time_lock for writes */ struct timeval time[DRM_VBLANKTIME_RBSIZE]; -- cgit v0.10.2 From 9f2dd0270d81b283e11e39f9276113aef391e420 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 1 Aug 2015 19:40:39 +0530 Subject: ASoC: Intel: Skylake: Fix the NHLT rate size Sampling rate type needs to be u32 instead of u8, nhlt wav format description expected u32 for rate, passing u8 will fetch NULL config in skl_get_ep_blob(). Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 5c0895e..a14009b 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -56,7 +56,7 @@ void skl_nhlt_free(void __iomem *addr) static struct nhlt_specific_cfg *skl_get_specific_cfg( struct device *dev, struct nhlt_fmt *fmt, - u8 no_ch, u8 rate, u16 bps) + u8 no_ch, u32 rate, u16 bps) { struct nhlt_specific_cfg *sp_config; struct wav_fmt *wfmt; -- cgit v0.10.2 From aba3dd5ace59d038a9d69e0f5319b6fec61012c8 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 1 Aug 2015 19:40:40 +0530 Subject: ASoC: Intel: Skylake: Use acpi header for NHLT header Instead of defining own acpi header, use the available acpi header defined in acpi framework. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index a14009b..13036b1 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -17,7 +17,6 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ -#include #include "skl.h" /* Unique identification for getting NHLT blobs */ diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h index b0e2e4d..3769f9f 100644 --- a/sound/soc/intel/skylake/skl-nhlt.h +++ b/sound/soc/intel/skylake/skl-nhlt.h @@ -20,17 +20,7 @@ #ifndef __SKL_NHLT_H__ #define __SKL_NHLT_H__ -struct acpi_desc_header { - u32 signature; - u32 length; - u8 revision; - u8 checksum; - u8 oem_id[6]; - u64 oem_table_id; - u32 oem_revision; - u32 creator_id; - u32 creator_revision; -} __packed; +#include struct wav_fmt { u16 fmt_tag; @@ -98,7 +88,7 @@ struct nhlt_endpoint { } __packed; struct nhlt_acpi_table { - struct acpi_desc_header header; + struct acpi_table_header header; u8 endpoint_count; struct nhlt_endpoint desc[0]; } __packed; -- cgit v0.10.2 From 23db472bba549dcd1c7592b5af95cc9ba4b9b5c9 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 1 Aug 2015 19:40:41 +0530 Subject: ASoC: Intel: Skylake: Add helpers for DSP module configuration This adds helper functions to calculate parameters required for base module format and copier module. A generic module is modelled by base module. Copier module is responsible for getting/sending data to FE (host DMAs) and BE (link HDA DMA, SSP, PDM) This also ads module pin management helpers which help in finding pins to use or freeing them up Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 7c07b76..0ba13f1 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -26,6 +26,8 @@ #include "skl.h" #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "skl-topology.h" +#include "skl-tplg-interface.h" static int skl_alloc_dma_buf(struct device *dev, struct snd_dma_buffer *dmab, size_t size) @@ -131,3 +133,387 @@ int skl_resume_dsp(struct skl *skl) return skl_dsp_wake(ctx->dsp); } + +enum skl_bitdepth skl_get_bit_depth(int params) +{ + switch (params) { + case 8: + return SKL_DEPTH_8BIT; + + case 16: + return SKL_DEPTH_16BIT; + + case 24: + return SKL_DEPTH_24BIT; + + case 32: + return SKL_DEPTH_32BIT; + + default: + return SKL_DEPTH_INVALID; + + } +} + +static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg) +{ + u32 config; + + switch (ch_cfg) { + case SKL_CH_CFG_MONO: + config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT); + break; + + case SKL_CH_CFG_STEREO: + config = (0xFFFFFF00 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_RIGHT << 4)); + break; + + case SKL_CH_CFG_2_1: + config = (0xFFFFF000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_RIGHT << 4) + | (SKL_CHANNEL_LFE << 8)); + break; + + case SKL_CH_CFG_3_0: + config = (0xFFFFF000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_CENTER << 4) + | (SKL_CHANNEL_RIGHT << 8)); + break; + + case SKL_CH_CFG_3_1: + config = (0xFFFF0000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_CENTER << 4) + | (SKL_CHANNEL_RIGHT << 8) + | (SKL_CHANNEL_LFE << 12)); + break; + + case SKL_CH_CFG_QUATRO: + config = (0xFFFF0000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_RIGHT << 4) + | (SKL_CHANNEL_LEFT_SURROUND << 8) + | (SKL_CHANNEL_RIGHT_SURROUND << 12)); + break; + + case SKL_CH_CFG_4_0: + config = (0xFFFF0000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_CENTER << 4) + | (SKL_CHANNEL_RIGHT << 8) + | (SKL_CHANNEL_CENTER_SURROUND << 12)); + break; + + case SKL_CH_CFG_5_0: + config = (0xFFF00000 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_CENTER << 4) + | (SKL_CHANNEL_RIGHT << 8) + | (SKL_CHANNEL_LEFT_SURROUND << 12) + | (SKL_CHANNEL_RIGHT_SURROUND << 16)); + break; + + case SKL_CH_CFG_5_1: + config = (0xFF000000 | SKL_CHANNEL_CENTER + | (SKL_CHANNEL_LEFT << 4) + | (SKL_CHANNEL_RIGHT << 8) + | (SKL_CHANNEL_LEFT_SURROUND << 12) + | (SKL_CHANNEL_RIGHT_SURROUND << 16) + | (SKL_CHANNEL_LFE << 20)); + break; + + case SKL_CH_CFG_DUAL_MONO: + config = (0xFFFFFF00 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_LEFT << 4)); + break; + + case SKL_CH_CFG_I2S_DUAL_STEREO_0: + config = (0xFFFFFF00 | SKL_CHANNEL_LEFT + | (SKL_CHANNEL_RIGHT << 4)); + break; + + case SKL_CH_CFG_I2S_DUAL_STEREO_1: + config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8) + | (SKL_CHANNEL_RIGHT << 12)); + break; + + default: + config = 0xFFFFFFFF; + break; + + } + + return config; +} + +/* + * Each module in DSP expects a base module configuration, which consists of + * PCM format information, which we calculate in driver and resource values + * which are read from widget information passed through topology binary + * This is send when we create a module with INIT_INSTANCE IPC msg + */ +static void skl_set_base_module_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_base_cfg *base_cfg) +{ + struct skl_module_fmt *format = &mconfig->in_fmt; + + base_cfg->audio_fmt.number_of_channels = (u8)format->channels; + + base_cfg->audio_fmt.s_freq = format->s_freq; + base_cfg->audio_fmt.bit_depth = format->bit_depth; + base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; + base_cfg->audio_fmt.ch_cfg = format->ch_cfg; + + dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", + format->bit_depth, format->valid_bit_depth, + format->ch_cfg); + + base_cfg->audio_fmt.channel_map = skl_create_channel_map( + base_cfg->audio_fmt.ch_cfg); + + base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL; + + base_cfg->cps = mconfig->mcps; + base_cfg->ibs = mconfig->ibs; + base_cfg->obs = mconfig->obs; +} + +/* + * Copies copier capabilities into copier module and updates copier module + * config size. + */ +static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, + struct skl_cpr_cfg *cpr_mconfig) +{ + if (mconfig->formats_config.caps_size == 0) + return; + + memcpy(cpr_mconfig->gtw_cfg.config_data, + mconfig->formats_config.caps, + mconfig->formats_config.caps_size); + + cpr_mconfig->gtw_cfg.config_length = + (mconfig->formats_config.caps_size) / 4; +} + +/* + * Calculate the gatewat settings required for copier module, type of + * gateway and index of gateway to use + */ +static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_cpr_cfg *cpr_mconfig) +{ + union skl_connector_node_id node_id = {0}; + struct skl_pipe_params *params = mconfig->pipe->p_params; + + switch (mconfig->dev_type) { + case SKL_DEVICE_BT: + node_id.node.dma_type = + (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? + SKL_DMA_I2S_LINK_OUTPUT_CLASS : + SKL_DMA_I2S_LINK_INPUT_CLASS; + node_id.node.vindex = params->host_dma_id + + (mconfig->vbus_id << 3); + break; + + case SKL_DEVICE_I2S: + node_id.node.dma_type = + (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? + SKL_DMA_I2S_LINK_OUTPUT_CLASS : + SKL_DMA_I2S_LINK_INPUT_CLASS; + node_id.node.vindex = params->host_dma_id + + (mconfig->time_slot << 1) + + (mconfig->vbus_id << 3); + break; + + case SKL_DEVICE_DMIC: + node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS; + node_id.node.vindex = mconfig->vbus_id + + (mconfig->time_slot); + break; + + case SKL_DEVICE_HDALINK: + node_id.node.dma_type = + (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? + SKL_DMA_HDA_LINK_OUTPUT_CLASS : + SKL_DMA_HDA_LINK_INPUT_CLASS; + node_id.node.vindex = params->link_dma_id; + break; + + default: + node_id.node.dma_type = + (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? + SKL_DMA_HDA_HOST_OUTPUT_CLASS : + SKL_DMA_HDA_HOST_INPUT_CLASS; + node_id.node.vindex = params->host_dma_id; + break; + } + + cpr_mconfig->gtw_cfg.node_id = node_id.val; + + if (SKL_CONN_SOURCE == mconfig->hw_conn_type) + cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; + else + cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs; + + cpr_mconfig->cpr_feature_mask = 0; + cpr_mconfig->gtw_cfg.config_length = 0; + + skl_copy_copier_caps(mconfig, cpr_mconfig); +} + +static void skl_setup_out_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_audio_data_format *out_fmt) +{ + struct skl_module_fmt *format = &mconfig->out_fmt; + + out_fmt->number_of_channels = (u8)format->channels; + out_fmt->s_freq = format->s_freq; + out_fmt->bit_depth = format->bit_depth; + out_fmt->valid_bit_depth = format->valid_bit_depth; + out_fmt->ch_cfg = format->ch_cfg; + + out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg); + out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL; + + dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", + out_fmt->number_of_channels, format->s_freq, format->bit_depth); +} + +/* + * 'copier' is DSP internal module which copies data from Host DMA (HDA host + * dma) or link (hda link, SSP, PDM) + * Here we calculate the copier module parameters, like PCM format, output + * format, gateway settings + * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg + */ +static void skl_set_copier_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_cpr_cfg *cpr_mconfig) +{ + struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; + struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; + + skl_set_base_module_format(ctx, mconfig, base_cfg); + + skl_setup_out_format(ctx, mconfig, out_fmt); + skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig); +} + +static u16 skl_get_module_param_size(struct skl_sst *ctx, + struct skl_module_cfg *mconfig) +{ + u16 param_size; + + switch (mconfig->m_type) { + case SKL_MODULE_TYPE_COPIER: + param_size = sizeof(struct skl_cpr_cfg); + param_size += mconfig->formats_config.caps_size; + return param_size; + + default: + /* + * return only base cfg when no specific module type is + * specified + */ + return sizeof(struct skl_base_cfg); + } + + return 0; +} + +/* + * DSP firmware supports various modules like copier etc. These modules + * required various parameters to be calculated and sent for the module + * initialization to DSP. By default a generic module needs only base module + * format configuration + */ +static int skl_set_module_format(struct skl_sst *ctx, + struct skl_module_cfg *module_config, + u16 *module_config_size, + void **param_data) +{ + u16 param_size; + + param_size = skl_get_module_param_size(ctx, module_config); + + *param_data = kzalloc(param_size, GFP_KERNEL); + if (NULL == *param_data) + return -ENOMEM; + + *module_config_size = param_size; + + switch (module_config->m_type) { + case SKL_MODULE_TYPE_COPIER: + skl_set_copier_format(ctx, module_config, *param_data); + break; + + default: + skl_set_base_module_format(ctx, module_config, *param_data); + break; + + } + + dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", + module_config->id.module_id, param_size); + print_hex_dump(KERN_DEBUG, "Module params:", DUMP_PREFIX_OFFSET, 8, 4, + *param_data, param_size, false); + return 0; +} + +static int skl_get_queue_index(struct skl_module_pin *mpin, + struct skl_module_inst_id id, int max) +{ + int i; + + for (i = 0; i < max; i++) { + if (mpin[i].id.module_id == id.module_id && + mpin[i].id.instance_id == id.instance_id) + return i; + } + + return -EINVAL; +} + +/* + * Allocates queue for each module. + * if dynamic, the pin_index is allocated 0 to max_pin. + * In static, the pin_index is fixed based on module_id and instance id + */ +static int skl_alloc_queue(struct skl_module_pin *mpin, + struct skl_module_inst_id id, int max) +{ + int i; + + /* + * if pin in dynamic, find first free pin + * otherwise find match module and instance id pin as topology will + * ensure a unique pin is assigned to this so no need to + * allocate/free + */ + for (i = 0; i < max; i++) { + if (mpin[i].is_dynamic) { + if (!mpin[i].in_use) { + mpin[i].in_use = true; + mpin[i].id.module_id = id.module_id; + mpin[i].id.instance_id = id.instance_id; + return i; + } + } else { + if (mpin[i].id.module_id == id.module_id && + mpin[i].id.instance_id == id.instance_id) + return i; + } + } + + return -EINVAL; +} + +static void skl_free_queue(struct skl_module_pin *mpin, int q_index) +{ + if (mpin[q_index].is_dynamic) { + mpin[q_index].in_use = false; + mpin[q_index].id.module_id = 0; + mpin[q_index].id.instance_id = 0; + } +} diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h new file mode 100644 index 0000000..6ba137a --- /dev/null +++ b/sound/soc/intel/skylake/skl-topology.h @@ -0,0 +1,251 @@ +/* + * skl_topology.h - Intel HDA Platform topology header file + * + * Copyright (C) 2014-15 Intel Corp + * Author: Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#ifndef __SKL_TOPOLOGY_H__ +#define __SKL_TOPOLOGY_H__ + +#include + +#include +#include +#include "skl.h" +#include "skl-tplg-interface.h" + +#define BITS_PER_BYTE 8 +#define MAX_TS_GROUPS 8 +#define MAX_DMIC_TS_GROUPS 4 +#define MAX_FIXED_DMIC_PARAMS_SIZE 727 + +/* Maximum number of coefficients up down mixer module */ +#define UP_DOWN_MIXER_MAX_COEFF 6 + +enum skl_channel_index { + SKL_CHANNEL_LEFT = 0, + SKL_CHANNEL_RIGHT = 1, + SKL_CHANNEL_CENTER = 2, + SKL_CHANNEL_LEFT_SURROUND = 3, + SKL_CHANNEL_CENTER_SURROUND = 3, + SKL_CHANNEL_RIGHT_SURROUND = 4, + SKL_CHANNEL_LFE = 7, + SKL_CHANNEL_INVALID = 0xF, +}; + +enum skl_bitdepth { + SKL_DEPTH_8BIT = 8, + SKL_DEPTH_16BIT = 16, + SKL_DEPTH_24BIT = 24, + SKL_DEPTH_32BIT = 32, + SKL_DEPTH_INVALID +}; + +enum skl_interleaving { + /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */ + SKL_INTERLEAVING_PER_CHANNEL = 0, + /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */ + SKL_INTERLEAVING_PER_SAMPLE = 1, +}; + +enum skl_s_freq { + SKL_FS_8000 = 8000, + SKL_FS_11025 = 11025, + SKL_FS_12000 = 12000, + SKL_FS_16000 = 16000, + SKL_FS_22050 = 22050, + SKL_FS_24000 = 24000, + SKL_FS_32000 = 32000, + SKL_FS_44100 = 44100, + SKL_FS_48000 = 48000, + SKL_FS_64000 = 64000, + SKL_FS_88200 = 88200, + SKL_FS_96000 = 96000, + SKL_FS_128000 = 128000, + SKL_FS_176400 = 176400, + SKL_FS_192000 = 192000, + SKL_FS_INVALID +}; + +enum skl_widget_type { + SKL_WIDGET_VMIXER = 1, + SKL_WIDGET_MIXER = 2, + SKL_WIDGET_PGA = 3, + SKL_WIDGET_MUX = 4 +}; + +struct skl_audio_data_format { + enum skl_s_freq s_freq; + enum skl_bitdepth bit_depth; + u32 channel_map; + enum skl_ch_cfg ch_cfg; + enum skl_interleaving interleaving; + u8 number_of_channels; + u8 valid_bit_depth; + u8 sample_type; + u8 reserved[1]; +} __packed; + +struct skl_base_cfg { + u32 cps; + u32 ibs; + u32 obs; + u32 is_pages; + struct skl_audio_data_format audio_fmt; +}; + +struct skl_cpr_gtw_cfg { + u32 node_id; + u32 dma_buffer_size; + u32 config_length; + /* not mandatory; required only for DMIC/I2S */ + u32 config_data[1]; +} __packed; + +struct skl_cpr_cfg { + struct skl_base_cfg base_cfg; + struct skl_audio_data_format out_fmt; + u32 cpr_feature_mask; + struct skl_cpr_gtw_cfg gtw_cfg; +} __packed; + +enum skl_dma_type { + SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, + SKL_DMA_HDA_HOST_INPUT_CLASS = 1, + SKL_DMA_HDA_HOST_INOUT_CLASS = 2, + SKL_DMA_HDA_LINK_OUTPUT_CLASS = 8, + SKL_DMA_HDA_LINK_INPUT_CLASS = 9, + SKL_DMA_HDA_LINK_INOUT_CLASS = 0xA, + SKL_DMA_DMIC_LINK_INPUT_CLASS = 0xB, + SKL_DMA_I2S_LINK_OUTPUT_CLASS = 0xC, + SKL_DMA_I2S_LINK_INPUT_CLASS = 0xD, +}; + +union skl_ssp_dma_node { + u8 val; + struct { + u8 dual_mono:1; + u8 time_slot:3; + u8 i2s_instance:4; + } dma_node; +}; + +union skl_connector_node_id { + u32 val; + struct { + u32 vindex:8; + u32 dma_type:4; + u32 rsvd:20; + } node; +}; + +struct skl_module_fmt { + u32 channels; + u32 s_freq; + u32 bit_depth; + u32 valid_bit_depth; + u32 ch_cfg; +}; + +struct skl_module_inst_id { + u32 module_id; + u32 instance_id; +}; + +struct skl_module_pin { + struct skl_module_inst_id id; + u8 pin_index; + bool is_dynamic; + bool in_use; +}; + +struct skl_specific_cfg { + u32 caps_size; + u32 *caps; +}; + +enum skl_pipe_state { + SKL_PIPE_INVALID = 0, + SKL_PIPE_CREATED = 1, + SKL_PIPE_PAUSED = 2, + SKL_PIPE_STARTED = 3 +}; + +struct skl_pipe_module { + struct snd_soc_dapm_widget *w; + struct list_head node; +}; + +struct skl_pipe_params { + u8 host_dma_id; + u8 link_dma_id; + u32 ch; + u32 s_freq; + u32 s_fmt; + u8 linktype; + int stream; +}; + +struct skl_pipe { + u8 ppl_id; + u8 pipe_priority; + u16 conn_type; + u32 memory_pages; + struct skl_pipe_params *p_params; + enum skl_pipe_state state; + struct list_head w_list; +}; + +enum skl_module_state { + SKL_MODULE_UNINIT = 0, + SKL_MODULE_INIT_DONE = 1, + SKL_MODULE_LOADED = 2, + SKL_MODULE_UNLOADED = 3, + SKL_MODULE_BIND_DONE = 4 +}; + +struct skl_module_cfg { + struct skl_module_inst_id id; + struct skl_module_fmt in_fmt; + struct skl_module_fmt out_fmt; + u8 max_in_queue; + u8 max_out_queue; + u8 in_queue_mask; + u8 out_queue_mask; + u8 in_queue; + u8 out_queue; + u32 mcps; + u32 ibs; + u32 obs; + u8 is_loadable; + u8 core_id; + u8 dev_type; + u8 dma_id; + u8 time_slot; + u32 params_fixup; + u32 converter; + u32 vbus_id; + struct skl_module_pin *m_in_pin; + struct skl_module_pin *m_out_pin; + enum skl_module_type m_type; + enum skl_hw_conn_type hw_conn_type; + enum skl_module_state m_state; + struct skl_pipe *pipe; + struct skl_specific_cfg formats_config; +}; +enum skl_bitdepth skl_get_bit_depth(int params); +#endif diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h new file mode 100644 index 0000000..a506898 --- /dev/null +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -0,0 +1,88 @@ +/* + * skl-tplg-interface.h - Intel DSP FW private data interface + * + * Copyright (C) 2015 Intel Corp + * Author: Jeeja KP + * Nilofer, Samreen + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __HDA_TPLG_INTERFACE_H__ +#define __HDA_TPLG_INTERFACE_H__ + +/** + * enum skl_ch_cfg - channel configuration + * + * @SKL_CH_CFG_MONO: One channel only + * @SKL_CH_CFG_STEREO: L & R + * @SKL_CH_CFG_2_1: L, R & LFE + * @SKL_CH_CFG_3_0: L, C & R + * @SKL_CH_CFG_3_1: L, C, R & LFE + * @SKL_CH_CFG_QUATRO: L, R, Ls & Rs + * @SKL_CH_CFG_4_0: L, C, R & Cs + * @SKL_CH_CFG_5_0: L, C, R, Ls & Rs + * @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE + * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two + * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ] + * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ] + * @SKL_CH_CFG_INVALID: Invalid + */ +enum skl_ch_cfg { + SKL_CH_CFG_MONO = 0, + SKL_CH_CFG_STEREO = 1, + SKL_CH_CFG_2_1 = 2, + SKL_CH_CFG_3_0 = 3, + SKL_CH_CFG_3_1 = 4, + SKL_CH_CFG_QUATRO = 5, + SKL_CH_CFG_4_0 = 6, + SKL_CH_CFG_5_0 = 7, + SKL_CH_CFG_5_1 = 8, + SKL_CH_CFG_DUAL_MONO = 9, + SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10, + SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11, + SKL_CH_CFG_INVALID +}; + +enum skl_module_type { + SKL_MODULE_TYPE_MIXER = 0, + SKL_MODULE_TYPE_COPIER, + SKL_MODULE_TYPE_UPDWMIX, + SKL_MODULE_TYPE_SRCINT +}; + +enum skl_core_affinity { + SKL_AFFINITY_CORE_0 = 0, + SKL_AFFINITY_CORE_1, + SKL_AFFINITY_CORE_MAX +}; + +enum skl_pipe_conn_type { + SKL_PIPE_CONN_TYPE_NONE = 0, + SKL_PIPE_CONN_TYPE_FE, + SKL_PIPE_CONN_TYPE_BE +}; + +enum skl_hw_conn_type { + SKL_CONN_NONE = 0, + SKL_CONN_SOURCE = 1, + SKL_CONN_SINK = 2 +}; + +enum skl_dev_type { + SKL_DEVICE_BT = 0x0, + SKL_DEVICE_DMIC = 0x1, + SKL_DEVICE_I2S = 0x2, + SKL_DEVICE_SLIMBUS = 0x3, + SKL_DEVICE_HDALINK = 0x4, + SKL_DEVICE_NONE +}; +#endif -- cgit v0.10.2 From a0ffe48bb5d45fcef444e8a03c75fb7b73a5af29 Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Sat, 1 Aug 2015 19:40:42 +0530 Subject: ASoC: Intel: Skylake: Add helpers for SRC and converter modules SRC and converter modules are required to do frequency and channel conversion in DSP. Both take base module configuration and additional SRC and converter parameters. The helpers here are added to calculate the values for these modules Signed-off-by: Hardik T Shah Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 0ba13f1..03a80ef 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -381,6 +381,47 @@ static void skl_setup_out_format(struct skl_sst *ctx, } /* + * DSP needs SRC module for frequency conversion, SRC takes base module + * configuration and the target frequency as extra parameter passed as src + * config + */ +static void skl_set_src_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_src_module_cfg *src_mconfig) +{ + struct skl_module_fmt *fmt = &mconfig->out_fmt; + + skl_set_base_module_format(ctx, mconfig, + (struct skl_base_cfg *)src_mconfig); + + src_mconfig->src_cfg = fmt->s_freq; +} + +/* + * DSP needs updown module to do channel conversion. updown module take base + * module configuration and channel configuration + * It also take coefficients and now we have defaults applied here + */ +static void skl_set_updown_mixer_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_up_down_mixer_cfg *mixer_mconfig) +{ + struct skl_module_fmt *fmt = &mconfig->out_fmt; + int i = 0; + + skl_set_base_module_format(ctx, mconfig, + (struct skl_base_cfg *)mixer_mconfig); + mixer_mconfig->out_ch_cfg = fmt->ch_cfg; + + /* Select F/W default coefficient */ + mixer_mconfig->coeff_sel = 0x0; + + /* User coeff, don't care since we are selecting F/W defaults */ + for (i = 0; i < UP_DOWN_MIXER_MAX_COEFF; i++) + mixer_mconfig->coeff[i] = 0xDEADBEEF; +} + +/* * 'copier' is DSP internal module which copies data from Host DMA (HDA host * dma) or link (hda link, SSP, PDM) * Here we calculate the copier module parameters, like PCM format, output @@ -411,6 +452,12 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, param_size += mconfig->formats_config.caps_size; return param_size; + case SKL_MODULE_TYPE_SRCINT: + return sizeof(struct skl_src_module_cfg); + + case SKL_MODULE_TYPE_UPDWMIX: + return sizeof(struct skl_up_down_mixer_cfg); + default: /* * return only base cfg when no specific module type is @@ -423,11 +470,12 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, } /* - * DSP firmware supports various modules like copier etc. These modules - * required various parameters to be calculated and sent for the module - * initialization to DSP. By default a generic module needs only base module - * format configuration + * DSP firmware supports various modules like copier, SRC, updown etc. + * These modules required various parameters to be calculated and sent for + * the module initialization to DSP. By default a generic module needs only + * base module format configuration */ + static int skl_set_module_format(struct skl_sst *ctx, struct skl_module_cfg *module_config, u16 *module_config_size, @@ -448,6 +496,14 @@ static int skl_set_module_format(struct skl_sst *ctx, skl_set_copier_format(ctx, module_config, *param_data); break; + case SKL_MODULE_TYPE_SRCINT: + skl_set_src_format(ctx, module_config, *param_data); + break; + + case SKL_MODULE_TYPE_UPDWMIX: + skl_set_updown_mixer_format(ctx, module_config, *param_data); + break; + default: skl_set_base_module_format(ctx, module_config, *param_data); break; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 6ba137a..e4b2a33 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -123,6 +123,21 @@ struct skl_cpr_cfg { struct skl_cpr_gtw_cfg gtw_cfg; } __packed; + +struct skl_src_module_cfg { + struct skl_base_cfg base_cfg; + enum skl_s_freq src_cfg; +} __packed; + +struct skl_up_down_mixer_cfg { + struct skl_base_cfg base_cfg; + enum skl_ch_cfg out_ch_cfg; + /* This should be set to 1 if user coefficients are required */ + u32 coeff_sel; + /* Pass the user coeff in this array */ + s32 coeff[UP_DOWN_MIXER_MAX_COEFF]; +} __packed; + enum skl_dma_type { SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, SKL_DMA_HDA_HOST_INPUT_CLASS = 1, @@ -247,5 +262,6 @@ struct skl_module_cfg { struct skl_pipe *pipe; struct skl_specific_cfg formats_config; }; + enum skl_bitdepth skl_get_bit_depth(int params); #endif -- cgit v0.10.2 From beb73b266a75602084361c5ef0baa5bc14637f4b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 1 Aug 2015 19:40:43 +0530 Subject: ASoC: Intel: Skylake: Add DSP module init and binding routines A module needs to be instantiated and then connected with other modules. On cleanup we need to disconnect the module. This is achieved by helpers module init, bind and unbind which are added here Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 03a80ef..c435a51 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -573,3 +573,186 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) mpin[q_index].id.instance_id = 0; } } + +/* + * A module needs to be instanataited in DSP. A mdoule is present in a + * collection of module referred as a PIPE. + * We first calculate the module format, based on module type and then + * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper + */ +int skl_init_module(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, char *param) +{ + u16 module_config_size = 0; + void *param_data = NULL; + int ret; + struct skl_ipc_init_instance_msg msg; + + dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, + mconfig->id.module_id, mconfig->id.instance_id); + + if (mconfig->pipe->state != SKL_PIPE_CREATED) { + dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", + mconfig->pipe->state, mconfig->pipe->ppl_id); + return -EIO; + } + + ret = skl_set_module_format(ctx, mconfig, + &module_config_size, ¶m_data); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set module format ret=%d\n", ret); + return ret; + } + + msg.module_id = mconfig->id.module_id; + msg.instance_id = mconfig->id.instance_id; + msg.ppl_instance_id = mconfig->pipe->ppl_id; + msg.param_data_size = module_config_size; + msg.core_id = mconfig->core_id; + + ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); + if (ret < 0) { + dev_err(ctx->dev, "Failed to init instance ret=%d\n", ret); + kfree(param_data); + return ret; + } + mconfig->m_state = SKL_MODULE_INIT_DONE; + + return ret; +} + +static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg + *src_module, struct skl_module_cfg *dst_module) +{ + dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", + __func__, src_module->id.module_id, src_module->id.instance_id); + dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__, + dst_module->id.module_id, dst_module->id.instance_id); + + dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", + src_module->m_state, dst_module->m_state); +} + +/* + * On module freeup, we need to unbind the module with modules + * it is already bind. + * Find the pin allocated and unbind then using bind_unbind IPC + */ +int skl_unbind_modules(struct skl_sst *ctx, + struct skl_module_cfg *src_mcfg, + struct skl_module_cfg *dst_mcfg) +{ + int ret; + struct skl_ipc_bind_unbind_msg msg; + struct skl_module_inst_id src_id = src_mcfg->id; + struct skl_module_inst_id dst_id = dst_mcfg->id; + int in_max = dst_mcfg->max_in_queue; + int out_max = src_mcfg->max_out_queue; + int src_index, dst_index; + + skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + + if (src_mcfg->m_state != SKL_MODULE_BIND_DONE) + return 0; + + /* + * if intra module unbind, check if both modules are BIND, + * then send unbind + */ + if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) && + dst_mcfg->m_state != SKL_MODULE_BIND_DONE) + return 0; + else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && + dst_mcfg->m_state < SKL_MODULE_INIT_DONE) + return 0; + + /* get src queue index */ + src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); + if (src_index < 0) + return -EINVAL; + + msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; + + /* get dst queue index */ + dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); + if (dst_index < 0) + return -EINVAL; + + msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + + msg.module_id = src_mcfg->id.module_id; + msg.instance_id = src_mcfg->id.instance_id; + msg.dst_module_id = dst_mcfg->id.module_id; + msg.dst_instance_id = dst_mcfg->id.instance_id; + msg.bind = false; + + ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + if (!ret) { + src_mcfg->m_state = SKL_MODULE_UNINIT; + /* free queue only if unbind is success */ + skl_free_queue(src_mcfg->m_out_pin, src_index); + skl_free_queue(dst_mcfg->m_in_pin, dst_index); + } + + return ret; +} + +/* + * Once a module is instantiated it need to be 'bind' with other modules in + * the pipeline. For binding we need to find the module pins which are bind + * together + * This function finds the pins and then sends bund_unbind IPC message to + * DSP using IPC helper + */ +int skl_bind_modules(struct skl_sst *ctx, + struct skl_module_cfg *src_mcfg, + struct skl_module_cfg *dst_mcfg) +{ + int ret; + struct skl_ipc_bind_unbind_msg msg; + struct skl_module_inst_id src_id = src_mcfg->id; + struct skl_module_inst_id dst_id = dst_mcfg->id; + int in_max = dst_mcfg->max_in_queue; + int out_max = src_mcfg->max_out_queue; + int src_index, dst_index; + + skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + + if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && + dst_mcfg->m_state < SKL_MODULE_INIT_DONE) + return 0; + + src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max); + if (src_index < 0) + return -EINVAL; + + msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; + dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max); + if (dst_index < 0) { + skl_free_queue(src_mcfg->m_out_pin, src_index); + return -EINVAL; + } + + msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + + dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", + msg.src_queue, msg.dst_queue); + + msg.module_id = src_mcfg->id.module_id; + msg.instance_id = src_mcfg->id.instance_id; + msg.dst_module_id = dst_mcfg->id.module_id; + msg.dst_instance_id = dst_mcfg->id.instance_id; + msg.bind = true; + + ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + + if (!ret) { + src_mcfg->m_state = SKL_MODULE_BIND_DONE; + } else { + /* error case , if IPC fails, clear the queue index */ + skl_free_queue(src_mcfg->m_out_pin, src_index); + skl_free_queue(dst_mcfg->m_in_pin, dst_index); + } + + return ret; +} diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index e4b2a33..b7e8aa8 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -263,5 +263,14 @@ struct skl_module_cfg { struct skl_specific_cfg formats_config; }; +int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config, + char *param); + +int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg + *src_module, struct skl_module_cfg *dst_module); + +int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg + *src_module, struct skl_module_cfg *dst_module); + enum skl_bitdepth skl_get_bit_depth(int params); #endif -- cgit v0.10.2 From c9b1e834bc8decaf979344e8121e4ad1ded8dc8a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sat, 1 Aug 2015 19:40:44 +0530 Subject: ASoC: Intel: Skylake: Add pipe management helpers To manage DSP we need to create processing pipeline and on cleanup destroy them. So we add create and destroy routines for pipelines The pipelines need to to be executed so we add pipeline run and stop routines All these send required IPCs to DSP using IPC routines added earlier Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index c435a51..826d4fd 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -756,3 +756,129 @@ int skl_bind_modules(struct skl_sst *ctx, return ret; } + +static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe, + enum skl_ipc_pipeline_state state) +{ + dev_dbg(ctx->dev, "%s: pipe_satate = %d\n", __func__, state); + + return skl_ipc_set_pipeline_state(&ctx->ipc, pipe->ppl_id, state); +} + +/* + * A pipeline is a collection of modules. Before a module in instantiated a + * pipeline needs to be created for it. + * This function creates pipeline, by sending create pipeline IPC messages + * to FW + */ +int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) +{ + int ret; + + dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); + + ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, + pipe->pipe_priority, pipe->ppl_id); + if (ret < 0) { + dev_err(ctx->dev, "Failed to create pipeline\n"); + return ret; + } + + pipe->state = SKL_PIPE_CREATED; + + return 0; +} + +/* + * A pipeline needs to be deleted on cleanup. If a pipeline is running, then + * pause the pipeline first and then delete it + * The pipe delete is done by sending delete pipeline IPC. DSP will stop the + * DMA engines and releases resources + */ +int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +{ + int ret; + + dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + + /* If pipe is not started, do not try to stop the pipe in FW. */ + if (pipe->state > SKL_PIPE_STARTED) { + ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + if (ret < 0) { + dev_err(ctx->dev, "Failed to stop pipeline\n"); + return ret; + } + + pipe->state = SKL_PIPE_PAUSED; + } else { + /* If pipe was not created in FW, do not try to delete it */ + if (pipe->state < SKL_PIPE_CREATED) + return 0; + + ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); + if (ret < 0) + dev_err(ctx->dev, "Failed to delete pipeline\n"); + } + + return ret; +} + +/* + * A pipeline is also a scheduling entity in DSP which can be run, stopped + * For processing data the pipe need to be run by sending IPC set pipe state + * to DSP + */ +int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +{ + int ret; + + dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + + /* If pipe was not created in FW, do not try to pause or delete */ + if (pipe->state < SKL_PIPE_CREATED) + return 0; + + /* Pipe has to be paused before it is started */ + ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + if (ret < 0) { + dev_err(ctx->dev, "Failed to pause pipe\n"); + return ret; + } + + pipe->state = SKL_PIPE_PAUSED; + + ret = skl_set_pipe_state(ctx, pipe, PPL_RUNNING); + if (ret < 0) { + dev_err(ctx->dev, "Failed to start pipe\n"); + return ret; + } + + pipe->state = SKL_PIPE_STARTED; + + return 0; +} + +/* + * Stop the pipeline by sending set pipe state IPC + * DSP doesnt implement stop so we always send pause message + */ +int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +{ + int ret; + + dev_dbg(ctx->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); + + /* If pipe was not created in FW, do not try to pause or delete */ + if (pipe->state < SKL_PIPE_PAUSED) + return 0; + + ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + if (ret < 0) { + dev_dbg(ctx->dev, "Failed to stop pipe\n"); + return ret; + } + + pipe->state = SKL_PIPE_CREATED; + + return 0; +} diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index b7e8aa8..8c7767b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -263,6 +263,16 @@ struct skl_module_cfg { struct skl_specific_cfg formats_config; }; +int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); + +int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); + +int skl_pause_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); + +int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); + +int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); + int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config, char *param); -- cgit v0.10.2 From 36cc093520b9a6348292c253d3ec03bb67a84da8 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:07 +0200 Subject: ASoC: sti: Add IEC control Add control to configure IEC60958 settings. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d8df906..f6eefe1 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -250,6 +250,7 @@ static void uni_player_set_channel_status(struct uniperif *player, * sampling frequency. If no sample rate is already specified, then * set one. */ + mutex_lock(&player->ctrl_lock); if (runtime && (player->stream_settings.iec958.status[3] == IEC958_AES3_CON_FS_NOTID)) { switch (runtime->rate) { @@ -327,6 +328,7 @@ static void uni_player_set_channel_status(struct uniperif *player, player->stream_settings.iec958.status[3 + (n * 4)] << 24; SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); } + mutex_unlock(&player->ctrl_lock); /* Update the channel status */ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) @@ -538,6 +540,63 @@ static int uni_player_prepare_pcm(struct uniperif *player, } /* + * ALSA uniperipheral iec958 controls + */ +static int uni_player_ctl_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int uni_player_ctl_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; + + mutex_lock(&player->ctrl_lock); + ucontrol->value.iec958.status[0] = iec958->status[0]; + ucontrol->value.iec958.status[1] = iec958->status[1]; + ucontrol->value.iec958.status[2] = iec958->status[2]; + ucontrol->value.iec958.status[3] = iec958->status[3]; + mutex_unlock(&player->ctrl_lock); + return 0; +} + +static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; + + mutex_lock(&player->ctrl_lock); + iec958->status[0] = ucontrol->value.iec958.status[0]; + iec958->status[1] = ucontrol->value.iec958.status[1]; + iec958->status[2] = ucontrol->value.iec958.status[2]; + iec958->status[3] = ucontrol->value.iec958.status[3]; + mutex_unlock(&player->ctrl_lock); + + uni_player_set_channel_status(player, NULL); + + return 0; +} + +static struct snd_kcontrol_new uni_player_iec958_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = uni_player_ctl_iec958_info, + .get = uni_player_ctl_iec958_get, + .put = uni_player_ctl_iec958_put, +}; + +/* * uniperif rate adjustement control */ static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol, @@ -559,7 +618,9 @@ static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol, struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + mutex_lock(&player->ctrl_lock); ucontrol->value.integer.value[0] = player->clk_adj; + mutex_unlock(&player->ctrl_lock); return 0; } @@ -594,7 +655,12 @@ static struct snd_kcontrol_new uni_player_clk_adj_ctl = { .put = snd_sti_clk_adjustment_put, }; -static struct snd_kcontrol_new *snd_sti_ctl[] = { +static struct snd_kcontrol_new *snd_sti_pcm_ctl[] = { + &uni_player_clk_adj_ctl, +}; + +static struct snd_kcontrol_new *snd_sti_iec_ctl[] = { + &uni_player_iec958_ctl, &uni_player_clk_adj_ctl, }; @@ -1031,10 +1097,13 @@ int uni_player_init(struct platform_device *pdev, player->stream_settings.iec958.status[4] = IEC958_AES4_CON_MAX_WORDLEN_24 | IEC958_AES4_CON_WORDLEN_24_20; - } - player->num_ctrls = ARRAY_SIZE(snd_sti_ctl); - player->snd_ctrls = snd_sti_ctl[0]; + player->num_ctrls = ARRAY_SIZE(snd_sti_iec_ctl); + player->snd_ctrls = snd_sti_iec_ctl[0]; + } else { + player->num_ctrls = ARRAY_SIZE(snd_sti_pcm_ctl); + player->snd_ctrls = snd_sti_pcm_ctl[0]; + } return 0; } -- cgit v0.10.2 From aa0cd28d057fd4cb686fbdd2475a6a3f609dd581 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 7 Aug 2015 16:33:01 +0100 Subject: dm btree remove: fix bug in remove_one() remove_one() was not incrementing the key for the beginning of the range, so not all entries were being removed. This resulted in discards that were not unmapping all blocks. Fixes: 4ec331c3ea ("dm btree: add dm_btree_remove_leaves()") Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 9836c0a..9ca9ecc 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -689,6 +689,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root, value_ptr(n, index)); delete_at(n, index); + keys[last_level] = k + 1ull; } else r = -ENODATA; -- cgit v0.10.2 From bcc84140a62c04f522eacceb793e6eef92965c84 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Wed, 5 Aug 2015 03:27:48 -0400 Subject: be2net: enable IFACE filters only after creating RXQs HW issues were observed on Lancer adapters if IFACE filters (flags, mac addrs etc) are enabled *before* creating RXQs. This patch changes the driver design by enabling filters in be_open() -- instead of be_setup() -- after RXQs are created and buffers posted. Two new wrapper functions, be_enable_if_filters() and be_disable_if_filters() are introduced to enable/disable IFACE filters in be_open()/be_close() respectively. In be_setup() the IFACE is now created only with the RSS flag. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 2716e6f..00e3a6b 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -620,6 +620,11 @@ enum be_if_flags { BE_IF_FLAGS_VLAN_PROMISCUOUS |\ BE_IF_FLAGS_MCAST_PROMISCUOUS) +#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\ + BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED) + +#define BE_IF_ALL_FILT_FLAGS (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS) + /* An RX interface is an object with one or more MAC addresses and * filtering capabilities. */ struct be_cmd_req_if_create { diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 6f64242..7730f21 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) if (ether_addr_equal(addr->sa_data, netdev->dev_addr)) return 0; + /* if device is not running, copy MAC to netdev->dev_addr */ + if (!netif_running(netdev)) + goto done; + /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT * privilege or if PF did not provision the new MAC address. * On BE3, this cmd will always fail if the VF doesn't have the @@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) status = -EPERM; goto err; } - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - dev_info(dev, "MAC address changed to %pM\n", mac); +done: + ether_addr_copy(netdev->dev_addr, addr->sa_data); + dev_info(dev, "MAC address changed to %pM\n", addr->sa_data); return 0; err: dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data); @@ -3361,6 +3365,33 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) } } +static void be_disable_if_filters(struct be_adapter *adapter) +{ + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[0], 0); + + be_clear_uc_list(adapter); + + /* The IFACE flags are enabled in the open path and cleared + * in the close path. When a VF gets detached from the host and + * assigned to a VM the following happens: + * - VF's IFACE flags get cleared in the detach path + * - IFACE create is issued by the VF in the attach path + * Due to a bug in the BE3/Skyhawk-R FW + * (Lancer FW doesn't have the bug), the IFACE capability flags + * specified along with the IFACE create cmd issued by a VF are not + * honoured by FW. As a consequence, if a *new* driver + * (that enables/disables IFACE flags in open/close) + * is loaded in the host and an *old* driver is * used by a VM/VF, + * the IFACE gets created *without* the needed flags. + * To avoid this, disable RX-filter flags only for Lancer. + */ + if (lancer_chip(adapter)) { + be_cmd_rx_filter(adapter, BE_IF_ALL_FILT_FLAGS, OFF); + adapter->if_flags &= ~BE_IF_ALL_FILT_FLAGS; + } +} + static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -3373,6 +3404,8 @@ static int be_close(struct net_device *netdev) if (!(adapter->flags & BE_FLAGS_SETUP_DONE)) return 0; + be_disable_if_filters(adapter); + be_roce_dev_close(adapter); if (adapter->flags & BE_FLAGS_NAPI_ENABLED) { @@ -3392,7 +3425,6 @@ static int be_close(struct net_device *netdev) be_tx_compl_clean(adapter); be_rx_qs_destroy(adapter); - be_clear_uc_list(adapter); for_all_evt_queues(adapter, eqo, i) { if (msix_enabled(adapter)) @@ -3477,6 +3509,31 @@ static int be_rx_qs_create(struct be_adapter *adapter) return 0; } +static int be_enable_if_filters(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON); + if (status) + return status; + + /* For BE3 VFs, the PF programs the initial MAC address */ + if (!(BEx_chip(adapter) && be_virtfn(adapter))) { + status = be_cmd_pmac_add(adapter, adapter->netdev->dev_addr, + adapter->if_handle, + &adapter->pmac_id[0], 0); + if (status) + return status; + } + + if (adapter->vlans_added) + be_vid_config(adapter); + + be_set_rx_mode(adapter->netdev); + + return 0; +} + static int be_open(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -3490,6 +3547,10 @@ static int be_open(struct net_device *netdev) if (status) goto err; + status = be_enable_if_filters(adapter); + if (status) + goto err; + status = be_irq_register(adapter); if (status) goto err; @@ -3686,16 +3747,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter) } } -static void be_mac_clear(struct be_adapter *adapter) -{ - if (adapter->pmac_id) { - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[0], 0); - kfree(adapter->pmac_id); - adapter->pmac_id = NULL; - } -} - #ifdef CONFIG_BE2NET_VXLAN static void be_disable_vxlan_offloads(struct be_adapter *adapter) { @@ -3770,8 +3821,8 @@ static int be_clear(struct be_adapter *adapter) #ifdef CONFIG_BE2NET_VXLAN be_disable_vxlan_offloads(adapter); #endif - /* delete the primary mac along with the uc-mac list */ - be_mac_clear(adapter); + kfree(adapter->pmac_id); + adapter->pmac_id = NULL; be_cmd_if_destroy(adapter, adapter->if_handle, 0); @@ -3782,25 +3833,11 @@ static int be_clear(struct be_adapter *adapter) return 0; } -static int be_if_create(struct be_adapter *adapter, u32 *if_handle, - u32 cap_flags, u32 vf) -{ - u32 en_flags; - - en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS | - BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS; - - en_flags &= cap_flags; - - return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf); -} - static int be_vfs_if_create(struct be_adapter *adapter) { struct be_resources res = {0}; + u32 cap_flags, en_flags, vf; struct be_vf_cfg *vf_cfg; - u32 cap_flags, vf; int status; /* If a FW profile exists, then cap_flags are updated */ @@ -3821,8 +3858,12 @@ static int be_vfs_if_create(struct be_adapter *adapter) } } - status = be_if_create(adapter, &vf_cfg->if_handle, - cap_flags, vf + 1); + en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED | + BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST | + BE_IF_FLAGS_PASS_L3L4_ERRORS); + status = be_cmd_if_create(adapter, cap_flags, en_flags, + &vf_cfg->if_handle, vf + 1); if (status) return status; } @@ -4194,15 +4235,8 @@ static int be_mac_setup(struct be_adapter *adapter) memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); - } else { - /* Maybe the HW was reset; dev_addr must be re-programmed */ - memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN); } - /* For BE3-R VFs, the PF programs the initial MAC address */ - if (!(BEx_chip(adapter) && be_virtfn(adapter))) - be_cmd_pmac_add(adapter, mac, adapter->if_handle, - &adapter->pmac_id[0], 0); return 0; } @@ -4342,6 +4376,7 @@ static int be_func_init(struct be_adapter *adapter) static int be_setup(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; + u32 en_flags; int status; status = be_func_init(adapter); @@ -4364,8 +4399,11 @@ static int be_setup(struct be_adapter *adapter) if (status) goto err; - status = be_if_create(adapter, &adapter->if_handle, - be_if_cap_flags(adapter), 0); + /* will enable all the needed filter flags in be_open() */ + en_flags = BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS; + en_flags = en_flags & be_if_cap_flags(adapter); + status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags, + &adapter->if_handle, 0); if (status) goto err; @@ -4391,11 +4429,6 @@ static int be_setup(struct be_adapter *adapter) dev_err(dev, "Please upgrade firmware to version >= 4.0\n"); } - if (adapter->vlans_added) - be_vid_config(adapter); - - be_set_rx_mode(adapter->netdev); - status = be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); if (status) -- cgit v0.10.2 From 99b44304f205a826501721d41928e87b0b9cf3b3 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Wed, 5 Aug 2015 03:27:49 -0400 Subject: be2net: post buffers before destroying RXQs in Lancer An RX stall issue was seen on Lancer adapters, when RXQs are destroyed while they are in an "out of buffer" state. This patch fixes this issue by posting 64 buffers to each RXQ before destroying them in the close path. This is done after ensuring that no more new packets are selected for transfer to the RXQs by disabling interface filters. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 7730f21..14ae67a 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2451,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo) be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0); } -static void be_rx_cq_clean(struct be_rx_obj *rxo) +/* Free posted rx buffers that were not used */ +static void be_rxq_clean(struct be_rx_obj *rxo) { - struct be_rx_page_info *page_info; struct be_queue_info *rxq = &rxo->q; + struct be_rx_page_info *page_info; + + while (atomic_read(&rxq->used) > 0) { + page_info = get_rx_page_info(rxo); + put_page(page_info->page); + memset(page_info, 0, sizeof(*page_info)); + } + BUG_ON(atomic_read(&rxq->used)); + rxq->tail = 0; + rxq->head = 0; +} + +static void be_rx_cq_clean(struct be_rx_obj *rxo) +{ struct be_queue_info *rx_cq = &rxo->cq; struct be_rx_compl_info *rxcp; struct be_adapter *adapter = rxo->adapter; @@ -2491,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) /* After cleanup, leave the CQ in unarmed state */ be_cq_notify(adapter, rx_cq->id, false, 0); - - /* Then free posted rx buffers that were not used */ - while (atomic_read(&rxq->used) > 0) { - page_info = get_rx_page_info(rxo); - put_page(page_info->page); - memset(page_info, 0, sizeof(*page_info)); - } - BUG_ON(atomic_read(&rxq->used)); - rxq->tail = 0; - rxq->head = 0; } static void be_tx_compl_clean(struct be_adapter *adapter) @@ -3358,8 +3362,22 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) for_all_rx_queues(adapter, rxo, i) { q = &rxo->q; if (q->created) { + /* If RXQs are destroyed while in an "out of buffer" + * state, there is a possibility of an HW stall on + * Lancer. So, post 64 buffers to each queue to relieve + * the "out of buffer" condition. + * Make sure there's space in the RXQ before posting. + */ + if (lancer_chip(adapter)) { + be_rx_cq_clean(rxo); + if (atomic_read(&q->used) == 0) + be_post_rx_frags(rxo, GFP_KERNEL, + MAX_RX_POST); + } + be_cmd_rxq_destroy(adapter, q); be_rx_cq_clean(rxo); + be_rxq_clean(rxo); } be_queue_free(adapter, q); } -- cgit v0.10.2 From 649886a36b5f023811321819eceaa8ba66444e3b Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Wed, 5 Aug 2015 03:27:50 -0400 Subject: be2net: protect eqo->affinity_mask from getting freed twice There are paths in the driver such as an unrecoverable error (UE) detection followed by a driver unload wherein be_clear() is invoked twice. Individual data structures are reset so that they are not cleaned/freed twice. This patch does the same for eqo->affinity_mask. It is freed only if EQs haven't yet been destroyed. This fixes a possible crash when affinity_mask is freed twice. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 14ae67a..c28e3bf 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2584,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ); napi_hash_del(&eqo->napi); netif_napi_del(&eqo->napi); + free_cpumask_var(eqo->affinity_mask); } - free_cpumask_var(eqo->affinity_mask); be_queue_free(adapter, &eqo->q); } } @@ -2602,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter) for_all_evt_queues(adapter, eqo, i) { int numa_node = dev_to_node(&adapter->pdev->dev); - if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL)) - return -ENOMEM; - cpumask_set_cpu(cpumask_local_spread(i, numa_node), - eqo->affinity_mask); - netif_napi_add(adapter->netdev, &eqo->napi, be_poll, - BE_NAPI_WEIGHT); - napi_hash_add(&eqo->napi); + aic = &adapter->aic_obj[i]; eqo->adapter = adapter; eqo->idx = i; @@ -2624,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter) rc = be_cmd_eq_create(adapter, eqo); if (rc) return rc; + + if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL)) + return -ENOMEM; + cpumask_set_cpu(cpumask_local_spread(i, numa_node), + eqo->affinity_mask); + netif_napi_add(adapter->netdev, &eqo->napi, be_poll, + BE_NAPI_WEIGHT); + napi_hash_add(&eqo->napi); } return 0; } -- cgit v0.10.2 From 998ef5d81c74c752d74c7925bc370909b84adb9d Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 6 Aug 2015 15:07:04 +0100 Subject: ARM: 8408/1: Fix the secondary_startup function in Big Endian case Since the commit "b2c3e38a5471 ARM: redo TTBR setup code for LPAE", the setup code had been reworked. As a result the secondary CPUs failed to come online in Big Endian. As explained by Russell, the new code expected the value in r4/r5 to be the least significant 32bits in r4 and the most significant 32bits in r5. However, in the secondary code, we load this using ldrd, which on BE reverses that. This patch swap r4/r5 after the ldrd. It is done using the xor instructions in order to not use a temporary register. Signed-off-by: Gregory CLEMENT Signed-off-by: Russell King diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index bd755d9..29e2991 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -399,6 +399,9 @@ ENTRY(secondary_startup) sub lr, r4, r5 @ mmu has been enabled add r3, r7, lr ldrd r4, [r3, #0] @ get secondary_data.pgdir +ARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE: +ARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps +ARM_BE8(eor r4, r4, r5) @ without using a temp reg. ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir badr lr, __enable_mmu @ return address mov r13, r12 @ __secondary_switched address -- cgit v0.10.2 From e83dd3770021910293edea6fb2dc2fa306b1bf34 Mon Sep 17 00:00:00 2001 From: Drew Richardson Date: Thu, 6 Aug 2015 18:50:27 +0100 Subject: ARM: 8409/1: Mark ret_fast_syscall as a function ret_fast_syscall runs when user space makes a syscall. However it needs to be marked as such so the ELF information is correct. Before it was: 101: 8000f300 0 NOTYPE LOCAL DEFAULT 2 ret_fast_syscall But with this change it correctly shows as: 101: 8000f300 96 FUNC LOCAL DEFAULT 2 ret_fast_syscall I see this function when using perf to unwind call stacks from kernel space to user space. Without this change I would need to add some special case logic when using the vmlinux ELF information. Signed-off-by: Drew Richardson Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 92828a1..b48dd4f 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -61,6 +61,7 @@ work_pending: movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE) ldmia sp, {r0 - r6} @ have to reload r0 - r6 b local_restart @ ... and off we go +ENDPROC(ret_fast_syscall) /* * "slow" syscall return path. "why" tells us if this was a real syscall. -- cgit v0.10.2 From 6b30c73e9f37183ad60c7f7050acf8e8edf91e9c Mon Sep 17 00:00:00 2001 From: Duson Lin Date: Fri, 7 Aug 2015 14:37:24 -0700 Subject: Input: elantech - add special check for fw_version 0x470f01 touchpad It is no need to check the packet[0] for sanity check when doing elantech_packet_check_v4() function for fw_version = 0x470f01 touchpad. Signed-off by: Duson Lin Reviewed-by: Ulrik De Bie Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 22b9ca9..2955f1d 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) struct elantech_data *etd = psmouse->private; unsigned char *packet = psmouse->packet; unsigned char packet_type = packet[3] & 0x03; + unsigned int ic_version; bool sanity_check; if (etd->tp_dev && (packet[3] & 0x0f) == 0x06) return PACKET_TRACKPOINT; + /* This represents the version of IC body. */ + ic_version = (etd->fw_version & 0x0f0000) >> 16; + /* * Sanity check based on the constant bits of a packet. * The constant bits change depending on the value of - * the hardware flag 'crc_enabled' but are the same for - * every packet, regardless of the type. + * the hardware flag 'crc_enabled' and the version of + * the IC body, but are the same for every packet, + * regardless of the type. */ if (etd->crc_enabled) sanity_check = ((packet[3] & 0x08) == 0x00); + else if (ic_version == 7 && etd->samples[1] == 0x2A) + sanity_check = ((packet[3] & 0x1c) == 0x10); else sanity_check = ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0x1c) == 0x10); @@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * Avatar AVIU-145A2 0x361f00 ? clickpad * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) @@ -1651,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse) etd->capabilities[0], etd->capabilities[1], etd->capabilities[2]); + if (etd->hw_version != 1) { + if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) { + psmouse_err(psmouse, "failed to query sample data\n"); + goto init_fail; + } + psmouse_info(psmouse, + "Elan sample query result %02x, %02x, %02x\n", + etd->samples[0], etd->samples[1], etd->samples[2]); + } + if (elantech_set_absolute_mode(psmouse)) { psmouse_err(psmouse, "failed to put touchpad into absolute mode.\n"); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index f965d15..e1cbf40 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -129,6 +129,7 @@ struct elantech_data { unsigned char reg_26; unsigned char debug; unsigned char capabilities[3]; + unsigned char samples[3]; bool paritycheck; bool jumpy_cursor; bool reports_pressure; -- cgit v0.10.2 From fe1e1876d8f6d8d4b45e3940e6dd43cd3b18d958 Mon Sep 17 00:00:00 2001 From: Carol L Soto Date: Wed, 5 Aug 2015 11:05:32 -0500 Subject: net/mlx5_core: Set log_uar_page_sz for non 4K page size architecture failed to configure the page size for architectures with page size different than 4K. Fixes: 938fe83 ("net/mlx5_core: New device capabilities handling") Signed-off-by: Carol L Soto Acked-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index afad529..06e3e1e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -391,6 +391,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) /* disable cmdif checksum */ MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0); + MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12); + err = set_caps(dev, set_ctx, set_sz); query_ex: -- cgit v0.10.2 From b93028c9af807b9474789e6aba34a6135b6cb708 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Tue, 4 Aug 2015 08:21:33 +0200 Subject: clk: pxa: pxa3xx: fix CKEN register access Clocks 0 to 31 are on CKENA, and not CKENB. The clock register names were inadequately inverted. As a consequence, all clock operations were happening on CKENB, because almost all but 2 clocks are on CKENA. As the clocks were activated by the bootloader in the former tests, it escaped the testing that the wrong clock gate was manipulated. The error was revealed by changing the pxa3xx-nand driver to a module, where upon unloading, the wrong clock was disabled in CKENB. Fixes: 9bbb8a338fb2 ("clk: pxa: add pxa3xx clock driver") Signed-off-by: Robert Jarzmik Signed-off-by: Stephen Boyd diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c index 4b93a1e..ac03ba4 100644 --- a/drivers/clk/pxa/clk-pxa3xx.c +++ b/drivers/clk/pxa/clk-pxa3xx.c @@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" }; PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" }; PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" }; -#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB) +#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA) #define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \ div_hp, bit, is_lp, flags) \ PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \ -- cgit v0.10.2 From 136d9d83c07c5e30ac49fc83b27e8c4842f108fc Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 6 Aug 2015 10:04:38 +0200 Subject: x86/ldt: Correct LDT access in single stepping logic Commit 37868fe113ff ("x86/ldt: Make modify_ldt synchronous") introduced a new struct ldt_struct anchored at mm->context.ldt. convert_ip_to_linear() was changed to reflect this, but indexing into the ldt has to be changed as the pointer is no longer void *. Signed-off-by: Juergen Gross Reviewed-by: Andy Lutomirski Cc: # On top of: 37868fe113ff: x86/ldt: Make modify_ldt synchronous Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: bp@suse.de Link: http://lkml.kernel.org/r/1438848278-12906-1-git-send-email-jgross@suse.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index 6273324..0ccb53a 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -28,11 +28,11 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re struct desc_struct *desc; unsigned long base; - seg &= ~7UL; + seg >>= 3; mutex_lock(&child->mm->context.lock); if (unlikely(!child->mm->context.ldt || - (seg >> 3) >= child->mm->context.ldt->size)) + seg >= child->mm->context.ldt->size)) addr = -1L; /* bogus selector, access would fault */ else { desc = &child->mm->context.ldt->entries[seg]; -- cgit v0.10.2 From 4809146b86c3d41ce588fdb767d021e2a80600dd Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 6 Aug 2015 19:54:34 +0200 Subject: x86/ldt: Correct FPU emulation access to LDT Commit 37868fe113ff ("x86/ldt: Make modify_ldt synchronous") introduced a new struct ldt_struct anchored at mm->context.ldt. Adapt the x86 fpu emulation code to use that new structure. Signed-off-by: Juergen Gross Reviewed-by: Andy Lutomirski Cc: # On top of: 37868fe113ff: x86/ldt: Make modify_ldt synchronous Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: billm@melbpc.org.au Link: http://lkml.kernel.org/r/1438883674-1240-1-git-send-email-jgross@suse.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c index f37e84a..3d8f2e4 100644 --- a/arch/x86/math-emu/fpu_entry.c +++ b/arch/x86/math-emu/fpu_entry.c @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -181,7 +180,7 @@ void math_emulate(struct math_emu_info *info) math_abort(FPU_info, SIGILL); } - code_descriptor = LDT_DESCRIPTOR(FPU_CS); + code_descriptor = FPU_get_ldt_descriptor(FPU_CS); if (SEG_D_SIZE(code_descriptor)) { /* The above test may be wrong, the book is not clear */ /* Segmented 32 bit protected mode */ diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h index 9ccecb6..5e044d5 100644 --- a/arch/x86/math-emu/fpu_system.h +++ b/arch/x86/math-emu/fpu_system.h @@ -16,9 +16,24 @@ #include #include -/* s is always from a cpu register, and the cpu does bounds checking - * during register load --> no further bounds checks needed */ -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) +#include +#include + +static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg) +{ + static struct desc_struct zero_desc; + struct desc_struct ret = zero_desc; + +#ifdef CONFIG_MODIFY_LDT_SYSCALL + seg >>= 3; + mutex_lock(¤t->mm->context.lock); + if (current->mm->context.ldt && seg < current->mm->context.ldt->size) + ret = current->mm->context.ldt->entries[seg]; + mutex_unlock(¤t->mm->context.lock); +#endif + return ret; +} + #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c index 6ef5e99..d13cab2 100644 --- a/arch/x86/math-emu/get_address.c +++ b/arch/x86/math-emu/get_address.c @@ -20,7 +20,6 @@ #include #include -#include #include "fpu_system.h" #include "exception.h" @@ -158,7 +157,7 @@ static long pm_address(u_char FPU_modrm, u_char segment, addr->selector = PM_REG_(segment); } - descriptor = LDT_DESCRIPTOR(PM_REG_(segment)); + descriptor = FPU_get_ldt_descriptor(segment); base_address = SEG_BASE_ADDR(descriptor); address = base_address + offset; limit = base_address -- cgit v0.10.2 From 54d46b7fbcbd00fe4b20a27208e5909facc714e3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 Aug 2015 17:32:06 +0200 Subject: clockevents/drivers/sh_cmt: Only perform clocksource suspend/resume if enabled Currently the sh_cmt clocksource timer is disabled or enabled unconditionally on clocksource suspend resp. resume, even if a better clocksource is present (e.g. arch_sys_counter) and the sh_cmt clocksource is not enabled. As sh_cmt is a syscore device when its timer is enabled, this may lead to a genpd.prepared_count imbalance in the presence of PM Domains, which may cause a lock-up during reboot after s2ram. During suspend: - pm_genpd_prepare() is called for all non-syscore devices (incl. sh_cmt), increasing genpd.prepared_count for each device, - clocksource.suspend() is called for all clocksource devices, - sh_cmt_clocksource_suspend() calls sh_cmt_stop(), which is a no-op as the clocksource was not enabled. During resume: - clocksource.resume() is called for all clocksource devices, - sh_cmt_clocksource_resume() calls sh_cmt_start(), which enables the clocksource timer, and turns sh_cmt into a syscore device, - pm_genpd_complete() is called for all non-syscore devices (excl. sh_cmt now!), decreasing genpd.prepared_count for each device but sh_cmt. Now genpd.prepared_count of the PM Domain containing sh_cmt is still 1 instead of zero. On subsequent suspend/resume cycles, sh_cmt is still a syscore device, hence it's skipped for pm_genpd_{prepare,complete}(), keeping the imbalance of genpd.prepared_count at 1. During reboot: - platform_drv_shutdown() is called for any platform device that has a driver with a .shutdown() method (only rcar-dmac on R-Car Gen2), - platform_drv_shutdown() calls dev_pm_domain_detach(), which calls genpd_dev_pm_detach(), - genpd_dev_pm_detach() keeps calling pm_genpd_remove_device() until it doesn't return -EAGAIN[*], - If the device is part of the same PM Domain as sh_cmt, pm_genpd_remove_device() always fails with -EAGAIN due to genpd.prepared_count > 0. - Infinite loop in genpd_dev_pm_detach()[*]. [*] Commit 93af5e9354432828 ("PM / Domains: Avoid infinite loops in attach/detach code") already limited the number of loop iterations, avoiding the lock-up. To fix this, only disable or enable the clocksource timer on clocksource suspend resp. resume if the clocksource was enabled. This was tested on r8a7791/koelsch with the CPG Clock Domain: - using arch_sys_counter as the clocksource, which is the default, and which showed the problem, - using sh_cmt as a clocksource ("echo ffca0000.timer > \ /sys/devices/system/clocksource/clocksource0/current_clocksource"), which behaves the same as before. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Acked-by: Laurent Pinchart Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1438875126-12596-2-git-send-email-daniel.lezcano@linaro.org Signed-off-by: Ingo Molnar diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index b8ff3c6..c96de14 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -661,6 +661,9 @@ static void sh_cmt_clocksource_suspend(struct clocksource *cs) { struct sh_cmt_channel *ch = cs_to_sh_cmt(cs); + if (!ch->cs_enabled) + return; + sh_cmt_stop(ch, FLAG_CLOCKSOURCE); pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev); } @@ -669,6 +672,9 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs) { struct sh_cmt_channel *ch = cs_to_sh_cmt(cs); + if (!ch->cs_enabled) + return; + pm_genpd_syscore_poweron(&ch->cmt->pdev->dev); sh_cmt_start(ch, FLAG_CLOCKSOURCE); } -- cgit v0.10.2 From f7644cbfcdf03528f0f450f3940c4985b2291f49 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 9 Aug 2015 15:54:30 -0400 Subject: Linux 4.2-rc6 diff --git a/Makefile b/Makefile index 15d3201..35b4c19 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* -- cgit v0.10.2 From da2e5ae56164b86823c1bff5b4d28430ca4a7108 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 13 Jul 2015 08:07:08 -0400 Subject: NTB: Fix ntb_transport out-of-order RX update It was possible for a synchronous update of the RX index in the error case to get ahead of the asynchronous RX index update in the normal case. Change the RX processing to preserve an RX completion order. There were two error cases. First, if a buffer is not present to receive data, there would be no queue entry to preserve the RX completion order. Instead of dropping the RX frame, leave the RX frame in the ring. Schedule RX processing when RX entries are enqueued, in case there are RX frames waiting in the ring to be received. Second, if a buffer is too small to receive data, drop the frame in the ring, mark the RX entry as done, and indicate the error in the RX entry length. Check for a negative length in the receive callback in ntb_netdev, and count occurrences as rx_length_errors. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 3cc316cb..5f1ee7c 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -102,6 +102,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data, netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len); + if (len < 0) { + ndev->stats.rx_errors++; + ndev->stats.rx_length_errors++; + goto enqueue_again; + } + skb_put(skb, len); skb->protocol = eth_type_trans(skb, ndev); skb->ip_summed = CHECKSUM_NONE; @@ -121,6 +127,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data, return; } +enqueue_again: rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN); if (rc) { dev_kfree_skb(skb); diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index efe3ad4..98e58c7 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -142,10 +142,11 @@ struct ntb_transport_qp { void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, void *data, int len); + struct list_head rx_post_q; struct list_head rx_pend_q; struct list_head rx_free_q; - spinlock_t ntb_rx_pend_q_lock; - spinlock_t ntb_rx_free_q_lock; + /* ntb_rx_q_lock: synchronize access to rx_XXXX_q */ + spinlock_t ntb_rx_q_lock; void *rx_buff; unsigned int rx_index; unsigned int rx_max_entry; @@ -534,6 +535,27 @@ out: return entry; } +static struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock, + struct list_head *list, + struct list_head *to_list) +{ + struct ntb_queue_entry *entry; + unsigned long flags; + + spin_lock_irqsave(lock, flags); + + if (list_empty(list)) { + entry = NULL; + } else { + entry = list_first_entry(list, struct ntb_queue_entry, entry); + list_move_tail(&entry->entry, to_list); + } + + spin_unlock_irqrestore(lock, flags); + + return entry; +} + static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, unsigned int qp_num) { @@ -941,10 +963,10 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work); INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work); - spin_lock_init(&qp->ntb_rx_pend_q_lock); - spin_lock_init(&qp->ntb_rx_free_q_lock); + spin_lock_init(&qp->ntb_rx_q_lock); spin_lock_init(&qp->ntb_tx_free_q_lock); + INIT_LIST_HEAD(&qp->rx_post_q); INIT_LIST_HEAD(&qp->rx_pend_q); INIT_LIST_HEAD(&qp->rx_free_q); INIT_LIST_HEAD(&qp->tx_free_q); @@ -1107,22 +1129,47 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev) kfree(nt); } -static void ntb_rx_copy_callback(void *data) +static void ntb_complete_rxc(struct ntb_transport_qp *qp) { - struct ntb_queue_entry *entry = data; - struct ntb_transport_qp *qp = entry->qp; - void *cb_data = entry->cb_data; - unsigned int len = entry->len; - struct ntb_payload_header *hdr = entry->rx_hdr; + struct ntb_queue_entry *entry; + void *cb_data; + unsigned int len; + unsigned long irqflags; + + spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags); + + while (!list_empty(&qp->rx_post_q)) { + entry = list_first_entry(&qp->rx_post_q, + struct ntb_queue_entry, entry); + if (!(entry->flags & DESC_DONE_FLAG)) + break; + + entry->rx_hdr->flags = 0; + iowrite32(entry->index, &qp->rx_info->entry); + + cb_data = entry->cb_data; + len = entry->len; + + list_move_tail(&entry->entry, &qp->rx_free_q); - hdr->flags = 0; + spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags); - iowrite32(entry->index, &qp->rx_info->entry); + if (qp->rx_handler && qp->client_ready) + qp->rx_handler(qp, qp->cb_data, cb_data, len); - ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q); + spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags); + } - if (qp->rx_handler && qp->client_ready) - qp->rx_handler(qp, qp->cb_data, cb_data, len); + spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags); +} + +static void ntb_rx_copy_callback(void *data) +{ + struct ntb_queue_entry *entry = data; + + entry->flags |= DESC_DONE_FLAG; + + ntb_complete_rxc(entry->qp); } static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset) @@ -1138,19 +1185,18 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset) ntb_rx_copy_callback(entry); } -static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset, - size_t len) +static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset) { struct dma_async_tx_descriptor *txd; struct ntb_transport_qp *qp = entry->qp; struct dma_chan *chan = qp->dma_chan; struct dma_device *device; - size_t pay_off, buff_off; + size_t pay_off, buff_off, len; struct dmaengine_unmap_data *unmap; dma_cookie_t cookie; void *buf = entry->buf; - entry->len = len; + len = entry->len; if (!chan) goto err; @@ -1226,7 +1272,6 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; void *offset; - int rc; offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index; hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header); @@ -1255,65 +1300,43 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) return -EIO; } - entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); + entry = ntb_list_mv(&qp->ntb_rx_q_lock, &qp->rx_pend_q, &qp->rx_post_q); if (!entry) { dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n"); qp->rx_err_no_buf++; - - rc = -ENOMEM; - goto err; + return -EAGAIN; } + entry->rx_hdr = hdr; + entry->index = qp->rx_index; + if (hdr->len > entry->len) { dev_dbg(&qp->ndev->pdev->dev, "receive buffer overflow! Wanted %d got %d\n", hdr->len, entry->len); qp->rx_err_oflow++; - rc = -EIO; - goto err; - } + entry->len = -EIO; + entry->flags |= DESC_DONE_FLAG; - dev_dbg(&qp->ndev->pdev->dev, - "RX OK index %u ver %u size %d into buf size %d\n", - qp->rx_index, hdr->ver, hdr->len, entry->len); + ntb_complete_rxc(qp); + } else { + dev_dbg(&qp->ndev->pdev->dev, + "RX OK index %u ver %u size %d into buf size %d\n", + qp->rx_index, hdr->ver, hdr->len, entry->len); - qp->rx_bytes += hdr->len; - qp->rx_pkts++; + qp->rx_bytes += hdr->len; + qp->rx_pkts++; - entry->index = qp->rx_index; - entry->rx_hdr = hdr; + entry->len = hdr->len; - ntb_async_rx(entry, offset, hdr->len); + ntb_async_rx(entry, offset); + } qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return 0; - -err: - /* FIXME: if this syncrhonous update of the rx_index gets ahead of - * asyncrhonous ntb_rx_copy_callback of previous entry, there are three - * scenarios: - * - * 1) The peer might miss this update, but observe the update - * from the memcpy completion callback. In this case, the buffer will - * not be freed on the peer to be reused for a different packet. The - * successful rx of a later packet would clear the condition, but the - * condition could persist if several rx fail in a row. - * - * 2) The peer may observe this update before the asyncrhonous copy of - * prior packets is completed. The peer may overwrite the buffers of - * the prior packets before they are copied. - * - * 3) Both: the peer may observe the update, and then observe the index - * decrement by the asynchronous completion callback. Who knows what - * badness that will cause. - */ - hdr->flags = 0; - iowrite32(qp->rx_index, &qp->rx_info->entry); - - return rc; } static void ntb_transport_rxc_db(unsigned long data) @@ -1333,7 +1356,7 @@ static void ntb_transport_rxc_db(unsigned long data) break; } - if (qp->dma_chan) + if (i && qp->dma_chan) dma_async_issue_pending(qp->dma_chan); if (i == qp->rx_max_entry) { @@ -1609,7 +1632,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, goto err1; entry->qp = qp; - ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, + ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_free_q); } @@ -1634,7 +1657,7 @@ err2: while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); err1: - while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) + while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) kfree(entry); if (qp->dma_chan) dma_release_channel(qp->dma_chan); @@ -1689,11 +1712,16 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) qp->tx_handler = NULL; qp->event_handler = NULL; - while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) + while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) kfree(entry); - while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) { - dev_warn(&pdev->dev, "Freeing item from a non-empty queue\n"); + while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q))) { + dev_warn(&pdev->dev, "Freeing item from non-empty rx_pend_q\n"); + kfree(entry); + } + + while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q))) { + dev_warn(&pdev->dev, "Freeing item from non-empty rx_post_q\n"); kfree(entry); } @@ -1724,14 +1752,14 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len) if (!qp || qp->client_ready) return NULL; - entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); + entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q); if (!entry) return NULL; buf = entry->cb_data; *len = entry->len; - ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q); + ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_free_q); return buf; } @@ -1757,15 +1785,18 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, if (!qp) return -EINVAL; - entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q); + entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q); if (!entry) return -ENOMEM; entry->cb_data = cb; entry->buf = data; entry->len = len; + entry->flags = 0; + + ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q); - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q); + tasklet_schedule(&qp->rxc_db_work); return 0; } -- cgit v0.10.2 From c8650fd03d320e9c39f44435a583933cacea5259 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:09 -0400 Subject: NTB: Fix transport stats for multiple devices Currently the debugfs does not have files for all NTB transport queue pairs. When there are multiple NTBs present in a system, the QP names of the last transport clobber the names of previously added transport QPs. Only the last added QPs can be observed via debugfs. Create a directory per NTB transport to associate the QPs with that transport. Name the directory the same as the PCI device. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 98e58c7..25e973f 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -212,6 +212,8 @@ struct ntb_transport_ctx { bool link_is_up; struct delayed_work link_work; struct work_struct link_cleanup; + + struct dentry *debugfs_node_dir; }; enum { @@ -945,12 +947,12 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, qp->tx_max_frame = min(transport_mtu, tx_size / 2); qp->tx_max_entry = tx_size / qp->tx_max_frame; - if (nt_debugfs_dir) { + if (nt->debugfs_node_dir) { char debugfs_name[4]; snprintf(debugfs_name, 4, "qp%d", qp_num); qp->debugfs_dir = debugfs_create_dir(debugfs_name, - nt_debugfs_dir); + nt->debugfs_node_dir); qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR, qp->debugfs_dir, qp, @@ -1053,6 +1055,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) goto err2; } + if (nt_debugfs_dir) { + nt->debugfs_node_dir = + debugfs_create_dir(pci_name(ndev->pdev), + nt_debugfs_dir); + } + for (i = 0; i < qp_count; i++) { rc = ntb_transport_init_queue(nt, i); if (rc) -- cgit v0.10.2 From da4eb27a2c2efd034bdd645650114b82c479329c Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:10 -0400 Subject: NTB: ntb_netdev not covering all receive errors ntb_netdev is allowing the link to come up even when -ENOMEM is returned from ntb_transport_rx_enqueue. Fix to cover all possible errors. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 5f1ee7c..d8757bf 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -191,7 +191,7 @@ static int ntb_netdev_open(struct net_device *ndev) rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data, ndev->mtu + ETH_HLEN); - if (rc == -EINVAL) { + if (rc) { dev_kfree_skb(skb); goto err; } -- cgit v0.10.2 From 260bee9451b4f0f5f9845c5b3024f0bfb8de8f22 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:11 -0400 Subject: NTB: Fix oops in debugfs when transport is half-up When the remote side is not up, we do not have all the context for the transport, and that causes NULL ptr access. Have the debugfs reads check to see if transport is up before we make access. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 25e973f..a049f96 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -439,13 +439,17 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, char *buf; ssize_t ret, out_offset, out_count; + qp = filp->private_data; + + if (!qp || !qp->link_is_up) + return 0; + out_count = 1000; buf = kmalloc(out_count, GFP_KERNEL); if (!buf) return -ENOMEM; - qp = filp->private_data; out_offset = 0; out_offset += snprintf(buf + out_offset, out_count - out_offset, "NTB QP stats\n"); -- cgit v0.10.2 From 8b5a22d8f18496f5921ccb92554a7051cbfd9b0c Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 13 Jul 2015 08:07:12 -0400 Subject: NTB: Schedule to receive on QP link up Schedule to receive on QP link up, to make sure that the doorbell is properly cleared for interrupts. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index a049f96..b82171e 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -895,6 +895,8 @@ static void ntb_qp_link_work(struct work_struct *work) if (qp->event_handler) qp->event_handler(qp->cb_data, qp->link_is_up); + + tasklet_schedule(&qp->rxc_db_work); } else if (nt->link_is_up) schedule_delayed_work(&qp->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); -- cgit v0.10.2 From 8c9edf63e75f036b42afb4502deb20bbfb5004b4 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 13 Jul 2015 08:07:13 -0400 Subject: NTB: Fix zero size or integer overflow in ntb_set_mw A plain 32 bit integer will overflow for values over 4GiB. Change the plain integer size to the appropriate size type in ntb_set_mw. Change the type of the size parameter and two local variables used for size. Even if there is no overflow, a size of zero is invalid here. Reported-by: Juyoung Jung Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index b82171e..bc556e2 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -629,13 +629,16 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw) } static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, - unsigned int size) + resource_size_t size) { struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; struct pci_dev *pdev = nt->ndev->pdev; - unsigned int xlat_size, buff_size; + size_t xlat_size, buff_size; int rc; + if (!size) + return -EINVAL; + xlat_size = round_up(size, mw->xlat_align_size); buff_size = round_up(size, mw->xlat_align); @@ -655,7 +658,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, if (!mw->virt_addr) { mw->xlat_size = 0; mw->buff_size = 0; - dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n", + dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n", buff_size); return -ENOMEM; } -- cgit v0.10.2 From 30a4bb1e5a9d7e283af6e29da09362104b67d7aa Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 13 Jul 2015 08:07:14 -0400 Subject: NTB: Fix dereference before check Remove early dereference of a pointer that is checked later in the code. Reported-by: Dan Carpenter Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index bc556e2..1c6386d 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1692,7 +1692,6 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue); */ void ntb_transport_free_queue(struct ntb_transport_qp *qp) { - struct ntb_transport_ctx *nt = qp->transport; struct pci_dev *pdev; struct ntb_queue_entry *entry; u64 qp_bit; @@ -1745,7 +1744,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); - nt->qp_bitmap_free |= qp_bit; + qp->transport->qp_bitmap_free |= qp_bit; dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num); } -- cgit v0.10.2 From e15f940908e474da03349cb55a107fe89310a02c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 24 Jul 2015 16:35:59 -0700 Subject: ntb: avoid format string in dev_set_name Avoid any chance of format string expansion when calling dev_set_name. Signed-off-by: Kees Cook Signed-off-by: Jon Mason diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c index 23435f2..2e25307 100644 --- a/drivers/ntb/ntb.c +++ b/drivers/ntb/ntb.c @@ -114,7 +114,7 @@ int ntb_register_device(struct ntb_dev *ntb) ntb->dev.bus = &ntb_bus; ntb->dev.parent = &ntb->pdev->dev; ntb->dev.release = ntb_dev_release; - dev_set_name(&ntb->dev, pci_name(ntb->pdev)); + dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev)); ntb->ctx = NULL; ntb->ctx_ops = NULL; -- cgit v0.10.2 From 2701fa0864ecb9e49d47a4aa1c02f172ab79639a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 28 Jul 2015 15:31:12 +0200 Subject: fbdev: select versatile helpers for the integrator Commit 11c32d7b6274cb0f554943d65bd4a126c4a86dcd "video: move Versatile CLCD helpers" missed the fact that the Integrator/CP is also using the helper, and as a result the platform got only stubs and no graphics. Add this as a default selection to Kconfig so we have graphics again. Fixes: 11c32d7b6274 (video: move Versatile CLCD helpers) Signed-off-by: Linus Walleij Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 2d98de5..f888561 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -298,7 +298,7 @@ config FB_ARMCLCD # Helper logic selected only by the ARM Versatile platform family. config PLAT_VERSATILE_CLCD - def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS + def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR depends on ARM depends on FB_ARMCLCD && FB=y -- cgit v0.10.2 From 2b55cb3b04684f131a01faf2eb8e4d822d293f24 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 7 Aug 2015 14:04:29 +0300 Subject: OMAPDSS: Fix node refcount leak in omapdss_of_get_next_port() Fix node refcount leak in omapdss_of_get_next_port(). Signed-off-by: Jyri Sarha Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index 928ee63..c8c065d 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -60,6 +60,8 @@ omapdss_of_get_next_port(const struct device_node *parent, } prev = port; } while (of_node_cmp(port->name, "port") != 0); + + of_node_put(ports); } return port; -- cgit v0.10.2 From 6266f4b19d341c531d447d689fb44609daa06c79 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 7 Aug 2015 14:04:30 +0300 Subject: OMAPDSS: Fix omap_dss_find_output_by_port_node() port refcount decrement Fix omap_dss_find_output_by_port_node() port parameter refcount decrementation. The only user of dss_of_port_get_parent_device() function is omap_dss_find_output_by_port_node() and it assumes the refcount of the port parameter is not decremented by the call. Signed-off-by: Jyri Sarha Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index c8c065d..bf407b6 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -96,7 +96,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port) if (!port) return NULL; - np = of_get_next_parent(port); + np = of_get_parent(port); for (i = 0; i < 2 && np; ++i) { struct property *prop; -- cgit v0.10.2 From 9e6e35edb330619fbfa3457eff1d15d3672c833a Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 3 Aug 2015 22:15:34 +0200 Subject: video: fbdev: pxa3xx_gcu: prepare the clocks The clocks need to be prepared before being enabled. Without it a warning appears in the drivers probe path : WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:707 clk_core_enable+0x84/0xa0() Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.2.0-rc3-cm-x300+ #804 Hardware name: CM-X300 module [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x7c/0xb4) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null) from [] (clk_core_enable+0x84/0xa0) [] (clk_core_enable) from [] (clk_enable+0x20/0x34) [] (clk_enable) from [] (pxa3xx_gcu_probe+0x148/0x338) [] (pxa3xx_gcu_probe) from [] (platform_drv_probe+0x30/0x94) Signed-off-by: Robert Jarzmik Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c index 86bd457..50bce45 100644 --- a/drivers/video/fbdev/pxa3xx-gcu.c +++ b/drivers/video/fbdev/pxa3xx-gcu.c @@ -653,7 +653,7 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) goto err_free_dma; } - ret = clk_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); if (ret < 0) { dev_err(dev, "failed to enable clock\n"); goto err_misc_deregister; @@ -685,7 +685,7 @@ err_misc_deregister: misc_deregister(&priv->misc_dev); err_disable_clk: - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } -- cgit v0.10.2 From 2fa3dc4ea7c1cdf4eed288de9a6cc5d3a8befddd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 12 Jul 2015 20:08:34 -0300 Subject: [media] vb2: Fix compilation breakage when !CONFIG_BUG Commit 77a3c6fd90c9 ("[media] vb2: Don't WARN when v4l2_buffer.bytesused is 0 for multiplanar buffers") uses the __WARN() macro which isn't defined when CONFIG_BUG isn't set. This introduces a compilation breakage. Fix it by using WARN_ON() instead. The commit was also broken in that it merged v1 of the patch while a new v2 version had been submitted, reviewed and acked. Fix it by incorporating the changes from v1 to v2. Fixes: 77a3c6fd90c9 ("[media] vb2: Don't WARN when v4l2_buffer.bytesused is 0 for multiplanar buffers") Signed-off-by: Laurent Pinchart Acked-by: Larry Finger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 0c7b6a7..a14c428 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1254,19 +1254,19 @@ EXPORT_SYMBOL_GPL(vb2_discard_done); static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) { - static bool __check_once __read_mostly; + static bool check_once; - if (__check_once) + if (check_once) return; - __check_once = true; - __WARN(); + check_once = true; + WARN_ON(1); - pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n"); + pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n"); if (vb->vb2_queue->allow_zero_bytesused) - pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); + pr_warn("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); else - pr_warn_once("use the actual size instead.\n"); + pr_warn("use the actual size instead.\n"); } /** -- cgit v0.10.2 From 96fffb4f23f124f297d51dedc9cf51d19eb88ee1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 9 Aug 2015 13:14:15 +0200 Subject: netfilter: ip6t_SYNPROXY: fix NULL pointer dereference This happens when networking namespaces are enabled. Suggested-by: Patrick McHardy Signed-off-by: Phil Sutter Acked-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index 6edb7b1..bcebc24 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c @@ -37,12 +37,13 @@ synproxy_build_ip(struct sk_buff *skb, const struct in6_addr *saddr, } static void -synproxy_send_tcp(const struct sk_buff *skb, struct sk_buff *nskb, +synproxy_send_tcp(const struct synproxy_net *snet, + const struct sk_buff *skb, struct sk_buff *nskb, struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo, struct ipv6hdr *niph, struct tcphdr *nth, unsigned int tcp_hdr_size) { - struct net *net = nf_ct_net((struct nf_conn *)nfct); + struct net *net = nf_ct_net(snet->tmpl); struct dst_entry *dst; struct flowi6 fl6; @@ -83,7 +84,8 @@ free_nskb: } static void -synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th, +synproxy_send_client_synack(const struct synproxy_net *snet, + const struct sk_buff *skb, const struct tcphdr *th, const struct synproxy_options *opts) { struct sk_buff *nskb; @@ -119,7 +121,7 @@ synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th, synproxy_build_options(nth, opts); - synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, + synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size); } @@ -163,7 +165,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet, synproxy_build_options(nth, opts); - synproxy_send_tcp(skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW, + synproxy_send_tcp(snet, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW, niph, nth, tcp_hdr_size); } @@ -203,7 +205,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet, synproxy_build_options(nth, opts); - synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); + synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); } static void @@ -241,7 +243,7 @@ synproxy_send_client_ack(const struct synproxy_net *snet, synproxy_build_options(nth, opts); - synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); + synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); } static bool @@ -301,7 +303,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par) XT_SYNPROXY_OPT_SACK_PERM | XT_SYNPROXY_OPT_ECN); - synproxy_send_client_synack(skb, th, &opts); + synproxy_send_client_synack(snet, skb, th, &opts); return NF_DROP; } else if (th->ack && !(th->fin || th->rst || th->syn)) { -- cgit v0.10.2 From 3c16241c445303a90529565e7437e1f240acfef2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jul 2015 00:53:26 +0200 Subject: netfilter: SYNPROXY: fix sending window update to client Upon receipt of SYNACK from the server, ipt_SYNPROXY first sends back an ACK to finish the server handshake, then calls nf_ct_seqadj_init() to initiate sequence number adjustment of forwarded packets to the client and finally sends a window update to the client to unblock it's TX queue. Since synproxy_send_client_ack() does not set synproxy_send_tcp()'s nfct parameter, no sequence number adjustment happens and the client receives the window update with incorrect sequence number. Depending on client TCP implementation, this leads to a significant delay (until a window probe is being sent). Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c index fe8cc18..95ea633e 100644 --- a/net/ipv4/netfilter/ipt_SYNPROXY.c +++ b/net/ipv4/netfilter/ipt_SYNPROXY.c @@ -226,7 +226,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet, synproxy_build_options(nth, opts); - synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); + synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, + niph, nth, tcp_hdr_size); } static bool diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index bcebc24..ebbb754 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c @@ -243,7 +243,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet, synproxy_build_options(nth, opts); - synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); + synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, + niph, nth, tcp_hdr_size); } static bool -- cgit v0.10.2 From e5b94083d0996b4c69674c8a5563c2eb272557ba Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Fri, 7 Aug 2015 14:08:15 -0700 Subject: ASoC: max98090: Fix sequencing when starting additional routes Enforce correct device sequencing when configuring a new audio route when there is an existing active audio route(s). This patch fixed recording noise issue while playback is active. We have some registers which require the device to be in full shutdown or to enter full shutdown before the register settings will take effect. Currently the driver is not shutting down the device when a new audio route is created. If a new audio route is made active while there is already an active audio route, then the required register sequencing is violated. A hardware shutdown toggle when creating a new audio route corrects the sequencing error. The device must remain in hardware shutdown for 40ms to allow the internal hardware core to fully shutdown. Signed-off-by: Fang, Yang A Signed-off-by: Sathyanarayana Nujella Acked-by: Anish Kumar Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f05..2a4c2e1 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -850,6 +850,19 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, return 0; } +static int max98090_shdn_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + if (event & SND_SOC_DAPM_POST_PMU) + max98090->shdn_pending = true; + + return 0; + +} + static const char *mic1_mux_text[] = { "IN12", "IN56" }; static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, @@ -1158,9 +1171,11 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION, M98090_SDOEN_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICL_SHIFT, 0, NULL, 0), + M98090_DIGMICL_SHIFT, 0, max98090_shdn_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICR_SHIFT, 0, NULL, 0), + M98090_DIGMICR_SHIFT, 0, max98090_shdn_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG, M98090_AHPF_SHIFT, 0, NULL, 0), @@ -1205,10 +1220,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { &max98090_right_adc_mixer_controls[0], ARRAY_SIZE(max98090_right_adc_mixer_controls)), - SND_SOC_DAPM_ADC("ADCL", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADLEN_SHIFT, 0), - SND_SOC_DAPM_ADC("ADCR", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADREN_SHIFT, 0), + SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE, + M98090_ADLEN_SHIFT, 0, max98090_shdn_event, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE, + M98090_ADREN_SHIFT, 0, max98090_shdn_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), @@ -2536,9 +2553,26 @@ static int max98090_remove(struct snd_soc_codec *codec) return 0; } +static void max98090_seq_notifier(struct snd_soc_dapm_context *dapm, + enum snd_soc_dapm_type event, int subseq) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + if (max98090->shdn_pending) { + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, 0); + msleep(40); + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, M98090_SHDNN_MASK); + max98090->shdn_pending = false; + } +} + static struct snd_soc_codec_driver soc_codec_dev_max98090 = { .probe = max98090_probe, .remove = max98090_remove, + .seq_notifier = max98090_seq_notifier, .set_bias_level = max98090_set_bias_level, }; diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 21ff743..bc610d9 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1543,6 +1543,7 @@ struct max98090_priv { unsigned int pa2en; unsigned int sidetone; bool master; + bool shdn_pending; }; int max98090_mic_detect(struct snd_soc_codec *codec, -- cgit v0.10.2 From 37b617f9be527b1f1181e3ff23df4cdbe3e6441f Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Sat, 11 Jul 2015 19:46:11 +0200 Subject: video: Fix possible leak in of_get_videomode() In case videomode_from_timings() fails in function of_get_videomode(), the allocated display timing data is not freed in the exit path. Make sure that display_timings_release() is called in any case. Detected by Coverity CID 1309681. Signed-off-by: Christian Engelmayer Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c index 111c2d1..b5102aa 100644 --- a/drivers/video/of_videomode.c +++ b/drivers/video/of_videomode.c @@ -44,11 +44,9 @@ int of_get_videomode(struct device_node *np, struct videomode *vm, index = disp->native_mode; ret = videomode_from_timings(disp, vm, index); - if (ret) - return ret; display_timings_release(disp); - return 0; + return ret; } EXPORT_SYMBOL_GPL(of_get_videomode); -- cgit v0.10.2 From 2a17d7e80f1df44d6b94c3696d5eda44fe6638a8 Mon Sep 17 00:00:00 2001 From: Scot Doyle Date: Tue, 4 Aug 2015 12:33:32 +0000 Subject: fbcon: unconditionally initialize cursor blink interval A sun7i-a20-olinuxino-micro fails to boot when kernel parameter vt.global_cursor_default=0. The value is copied to vc->vc_deccm causing the initialization of ops->cur_blink_jiffies to be skipped. Unconditionally initialize it. Reported-and-tested-by: Jonathan Liu Signed-off-by: Scot Doyle Acked-by: Pavel Machek Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 658c34b..1aaf893 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1306,10 +1306,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode) int y; int c = scr_readw((u16 *) vc->vc_pos); + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) return; - ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); if (vc->vc_cursor_type & 0x10) fbcon_del_cursor_timer(info); else -- cgit v0.10.2 From fc5fee86bdd3d720e2d1d324e4fae0c35845fa63 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 10 Aug 2015 15:40:27 +0200 Subject: x86/xen: build "Xen PV" APIC driver for domU as well It turns out that a PV domU also requires the "Xen PV" APIC driver. Otherwise, the flat driver is used and we get stuck in busy loops that never exit, such as in this stack trace: (gdb) target remote localhost:9999 Remote debugging using localhost:9999 __xapic_wait_icr_idle () at ./arch/x86/include/asm/ipi.h:56 56 while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY) (gdb) bt #0 __xapic_wait_icr_idle () at ./arch/x86/include/asm/ipi.h:56 #1 __default_send_IPI_shortcut (shortcut=, dest=, vector=) at ./arch/x86/include/asm/ipi.h:75 #2 apic_send_IPI_self (vector=246) at arch/x86/kernel/apic/probe_64.c:54 #3 0xffffffff81011336 in arch_irq_work_raise () at arch/x86/kernel/irq_work.c:47 #4 0xffffffff8114990c in irq_work_queue (work=0xffff88000fc0e400) at kernel/irq_work.c:100 #5 0xffffffff8110c29d in wake_up_klogd () at kernel/printk/printk.c:2633 #6 0xffffffff8110ca60 in vprintk_emit (facility=0, level=, dict=0x0 , dictlen=, fmt=, args=) at kernel/printk/printk.c:1778 #7 0xffffffff816010c8 in printk (fmt=) at kernel/printk/printk.c:1868 #8 0xffffffffc00013ea in ?? () #9 0x0000000000000000 in ?? () Mailing-list-thread: https://lkml.org/lkml/2015/8/4/755 Signed-off-by: Jason A. Donenfeld Cc: Signed-off-by: David Vrabel diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 7322755..4b6e29a 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -13,13 +13,13 @@ CFLAGS_mmu.o := $(nostackp) obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ time.o xen-asm.o xen-asm_$(BITS).o \ grant-table.o suspend.o platform-pci-unplug.o \ - p2m.o + p2m.o apic.o obj-$(CONFIG_EVENT_TRACING) += trace.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o -obj-$(CONFIG_XEN_DOM0) += apic.o vga.o +obj-$(CONFIG_XEN_DOM0) += vga.o obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o obj-$(CONFIG_XEN_EFI) += efi.o diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 9e195c6..bef30cb 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -101,17 +101,15 @@ struct dom0_vga_console_info; #ifdef CONFIG_XEN_DOM0 void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size); -void __init xen_init_apic(void); #else static inline void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size) { } -static inline void __init xen_init_apic(void) -{ -} #endif +void __init xen_init_apic(void); + #ifdef CONFIG_XEN_EFI extern void xen_efi_init(void); #else -- cgit v0.10.2 From 878854a374620a3f5e8c0a3c418e82a429bc2cff Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 7 Aug 2015 21:03:23 -0500 Subject: arm64: VDSO: fix coarse clock monotonicity regression Since 906c55579a63 ("timekeeping: Copy the shadow-timekeeper over the real timekeeper last") it has become possible on arm64 to: - Obtain a CLOCK_MONOTONIC_COARSE or CLOCK_REALTIME_COARSE timestamp via syscall. - Subsequently obtain a timestamp for the same clock ID via VDSO which predates the first timestamp (by one jiffy). This is because arm64's update_vsyscall is deriving the coarse time using the __current_kernel_time interface, when it should really be using the timekeeper object provided to it by the timekeeping core. It happened to work before only because __current_kernel_time would access the same timekeeper object which had been passed to update_vsyscall. This is no longer the case. Signed-off-by: Nathan Lynch Acked-by: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index ec37ab3..97bc68f 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -199,16 +199,15 @@ up_fail: */ void update_vsyscall(struct timekeeper *tk) { - struct timespec xtime_coarse; u32 use_syscall = strcmp(tk->tkr_mono.clock->name, "arch_sys_counter"); ++vdso_data->tb_seq_count; smp_wmb(); - xtime_coarse = __current_kernel_time(); vdso_data->use_syscall = use_syscall; - vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec; - vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec; + vdso_data->xtime_coarse_sec = tk->xtime_sec; + vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >> + tk->tkr_mono.shift; vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; -- cgit v0.10.2 From 443c0d7ed9d3815b3425ca12d65337d52b9a0c34 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 7 Aug 2015 16:00:04 +0800 Subject: crypto: authencesn - Fix breakage with new ESP code The ESP code has been updated to generate a completely linear AD SG list. This unfortunately broke authencesn which expects the AD to be divided into at least three parts. This patch fixes it to cope with the new format. Later we will fix it properly to accept arbitrary input and not rely on the input being linear as part of the AEAD conversion. Fixes: 7021b2e1cddd ("esp4: Switch to new AEAD interface") Signed-off-by: Herbert Xu diff --git a/crypto/authencesn.c b/crypto/authencesn.c index a3da677..b8efe36 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -393,8 +393,6 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv, struct scatterlist *cipher = areq_ctx->cipher; struct scatterlist *hsg = areq_ctx->hsg; struct scatterlist *tsg = areq_ctx->tsg; - struct scatterlist *assoc1; - struct scatterlist *assoc2; unsigned int ivsize = crypto_aead_ivsize(authenc_esn); unsigned int cryptlen = req->cryptlen; struct page *dstp; @@ -412,27 +410,19 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv, cryptlen += ivsize; } - if (sg_is_last(assoc)) - return -EINVAL; - - assoc1 = assoc + 1; - if (sg_is_last(assoc1)) - return -EINVAL; - - assoc2 = assoc + 2; - if (!sg_is_last(assoc2)) + if (assoc->length < 12) return -EINVAL; sg_init_table(hsg, 2); - sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset); - sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset); + sg_set_page(hsg, sg_page(assoc), 4, assoc->offset); + sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8); sg_init_table(tsg, 1); - sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset); + sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4); areq_ctx->cryptlen = cryptlen; - areq_ctx->headlen = assoc->length + assoc2->length; - areq_ctx->trailen = assoc1->length; + areq_ctx->headlen = 8; + areq_ctx->trailen = 4; areq_ctx->sg = dst; areq_ctx->complete = authenc_esn_geniv_ahash_done; @@ -563,8 +553,6 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, struct scatterlist *cipher = areq_ctx->cipher; struct scatterlist *hsg = areq_ctx->hsg; struct scatterlist *tsg = areq_ctx->tsg; - struct scatterlist *assoc1; - struct scatterlist *assoc2; unsigned int ivsize = crypto_aead_ivsize(authenc_esn); struct page *srcp; u8 *vsrc; @@ -580,27 +568,19 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, cryptlen += ivsize; } - if (sg_is_last(assoc)) - return -EINVAL; - - assoc1 = assoc + 1; - if (sg_is_last(assoc1)) - return -EINVAL; - - assoc2 = assoc + 2; - if (!sg_is_last(assoc2)) + if (assoc->length < 12) return -EINVAL; sg_init_table(hsg, 2); - sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset); - sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset); + sg_set_page(hsg, sg_page(assoc), 4, assoc->offset); + sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8); sg_init_table(tsg, 1); - sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset); + sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4); areq_ctx->cryptlen = cryptlen; - areq_ctx->headlen = assoc->length + assoc2->length; - areq_ctx->trailen = assoc1->length; + areq_ctx->headlen = 8; + areq_ctx->trailen = 4; areq_ctx->sg = src; areq_ctx->complete = authenc_esn_verify_ahash_done; -- cgit v0.10.2 From 24ee3cf89bef04e8bc23788aca4e029a3f0f06d9 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Thu, 6 Aug 2015 16:21:05 +0200 Subject: cpuset: use trialcs->mems_allowed as a temp variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment says it's using trialcs->mems_allowed as a temp variable but it didn't match the code. Change the code to match the comment. This fixes an issue when writing in cpuset.mems when a sub-directory exists: we need to write several times for the information to persist: | root@alban:/sys/fs/cgroup/cpuset# mkdir footest9 | root@alban:/sys/fs/cgroup/cpuset# cd footest9 | root@alban:/sys/fs/cgroup/cpuset/footest9# mkdir aa | root@alban:/sys/fs/cgroup/cpuset/footest9# cat cpuset.mems | | root@alban:/sys/fs/cgroup/cpuset/footest9# echo 0 > cpuset.mems | root@alban:/sys/fs/cgroup/cpuset/footest9# cat cpuset.mems | | root@alban:/sys/fs/cgroup/cpuset/footest9# echo 0 > cpuset.mems | root@alban:/sys/fs/cgroup/cpuset/footest9# cat cpuset.mems | 0 | root@alban:/sys/fs/cgroup/cpuset/footest9# cat aa/cpuset.mems | | root@alban:/sys/fs/cgroup/cpuset/footest9# echo 0 > aa/cpuset.mems | root@alban:/sys/fs/cgroup/cpuset/footest9# cat aa/cpuset.mems | 0 | root@alban:/sys/fs/cgroup/cpuset/footest9# This should help to fix the following issue in Docker: https://github.com/opencontainers/runc/issues/133 In some conditions, a Docker container needs to be started twice in order to work. Signed-off-by: Alban Crequy Tested-by: Iago López Galeiras Cc: # 3.17+ Acked-by: Li Zefan Signed-off-by: Tejun Heo diff --git a/kernel/cpuset.c b/kernel/cpuset.c index ee14e3a..f0acff0 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1223,7 +1223,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, spin_unlock_irq(&callback_lock); /* use trialcs->mems_allowed as a temp variable */ - update_nodemasks_hier(cs, &cs->mems_allowed); + update_nodemasks_hier(cs, &trialcs->mems_allowed); done: return retval; } -- cgit v0.10.2 From d53793c5d6eb0cfe4175d9c315a30d65adf3478b Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 6 Aug 2015 19:00:28 +0200 Subject: net: mvpp2: remove excessive spinlocks from driver initialization Using spinlocks protection during one-time driver initialization is not necessary. Moreover it resulted in invalid GFP_KERNEL allocation under the lock. This commit removes redundant spinlocks from buffer manager part of mvpp2 initialization. Signed-off-by: Marcin Wojtas Reported-by: Alexandre Fournier Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 3e8b1bf..f94bd12 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -913,8 +913,6 @@ struct mvpp2_bm_pool { /* Occupied buffers indicator */ atomic_t in_use; int in_use_thresh; - - spinlock_t lock; }; struct mvpp2_buff_hdr { @@ -3376,7 +3374,6 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev, bm_pool->pkt_size = 0; bm_pool->buf_num = 0; atomic_set(&bm_pool->in_use, 0); - spin_lock_init(&bm_pool->lock); return 0; } @@ -3647,7 +3644,6 @@ static struct mvpp2_bm_pool * mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, int pkt_size) { - unsigned long flags = 0; struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool]; int num; @@ -3656,8 +3652,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, return NULL; } - spin_lock_irqsave(&new_pool->lock, flags); - if (new_pool->type == MVPP2_BM_FREE) new_pool->type = type; @@ -3686,8 +3680,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, if (num != pkts_num) { WARN(1, "pool %d: %d of %d allocated\n", new_pool->id, num, pkts_num); - /* We need to undo the bufs_add() allocations */ - spin_unlock_irqrestore(&new_pool->lock, flags); return NULL; } } @@ -3695,15 +3687,12 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, mvpp2_bm_pool_bufsize_set(port->priv, new_pool, MVPP2_RX_BUF_SIZE(new_pool->pkt_size)); - spin_unlock_irqrestore(&new_pool->lock, flags); - return new_pool; } /* Initialize pools for swf */ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) { - unsigned long flags = 0; int rxq; if (!port->pool_long) { @@ -3714,9 +3703,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) if (!port->pool_long) return -ENOMEM; - spin_lock_irqsave(&port->pool_long->lock, flags); port->pool_long->port_map |= (1 << port->id); - spin_unlock_irqrestore(&port->pool_long->lock, flags); for (rxq = 0; rxq < rxq_number; rxq++) mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id); @@ -3730,9 +3717,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) if (!port->pool_short) return -ENOMEM; - spin_lock_irqsave(&port->pool_short->lock, flags); port->pool_short->port_map |= (1 << port->id); - spin_unlock_irqrestore(&port->pool_short->lock, flags); for (rxq = 0; rxq < rxq_number; rxq++) mvpp2_rxq_short_pool_set(port, rxq, -- cgit v0.10.2 From 71ce391dfb7843f4d31abcd7287967a00cb1b8a1 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 6 Aug 2015 19:00:29 +0200 Subject: net: mvpp2: enable proper per-CPU TX buffers unmapping mvpp2 driver allows usage of per-CPU TX processing. Once the packets are prepared independetly on each CPU, the hardware enqueues the descriptors in common TX queue. After they are sent, the buffers and associated sk_buffs should be released on the corresponding CPU. This is why a special index is maintained in order to point to the right data to be released after transmission takes place. Each per-CPU TX queue comprise an array of sent sk_buffs, freed in mvpp2_txq_bufs_free function. However, the index was used there also for obtaining a descriptor (and therefore a buffer to be DMA-unmapped) from common TX queue, which was wrong, because it was not referring to the current CPU. This commit enables proper unmapping of sent data buffers by indexing them in per-CPU queues using a dedicated array for keeping their physical addresses. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index f94bd12..3e25d314 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -776,6 +776,9 @@ struct mvpp2_txq_pcpu { /* Array of transmitted skb */ struct sk_buff **tx_skb; + /* Array of transmitted buffers' physical addresses */ + dma_addr_t *tx_buffs; + /* Index of last TX DMA descriptor that was inserted */ int txq_put_index; @@ -961,9 +964,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu) } static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, - struct sk_buff *skb) + struct sk_buff *skb, + struct mvpp2_tx_desc *tx_desc) { txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb; + if (skb) + txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] = + tx_desc->buf_phys_addr; txq_pcpu->txq_put_index++; if (txq_pcpu->txq_put_index == txq_pcpu->size) txq_pcpu->txq_put_index = 0; @@ -4392,8 +4399,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, int i; for (i = 0; i < num; i++) { - struct mvpp2_tx_desc *tx_desc = txq->descs + - txq_pcpu->txq_get_index; + dma_addr_t buf_phys_addr = + txq_pcpu->tx_buffs[txq_pcpu->txq_get_index]; struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index]; mvpp2_txq_inc_get(txq_pcpu); @@ -4401,8 +4408,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, if (!skb) continue; - dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr, - tx_desc->data_size, DMA_TO_DEVICE); + dma_unmap_single(port->dev->dev.parent, buf_phys_addr, + skb_headlen(skb), DMA_TO_DEVICE); dev_kfree_skb_any(skb); } } @@ -4634,12 +4641,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port, txq_pcpu->tx_skb = kmalloc(txq_pcpu->size * sizeof(*txq_pcpu->tx_skb), GFP_KERNEL); - if (!txq_pcpu->tx_skb) { - dma_free_coherent(port->dev->dev.parent, - txq->size * MVPP2_DESC_ALIGNED_SIZE, - txq->descs, txq->descs_phys); - return -ENOMEM; - } + if (!txq_pcpu->tx_skb) + goto error; + + txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size * + sizeof(dma_addr_t), GFP_KERNEL); + if (!txq_pcpu->tx_buffs) + goto error; txq_pcpu->count = 0; txq_pcpu->reserved_num = 0; @@ -4648,6 +4656,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port, } return 0; + +error: + for_each_present_cpu(cpu) { + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + kfree(txq_pcpu->tx_skb); + kfree(txq_pcpu->tx_buffs); + } + + dma_free_coherent(port->dev->dev.parent, + txq->size * MVPP2_DESC_ALIGNED_SIZE, + txq->descs, txq->descs_phys); + + return -ENOMEM; } /* Free allocated TXQ resources */ @@ -4660,6 +4681,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); kfree(txq_pcpu->tx_skb); + kfree(txq_pcpu->tx_buffs); } if (txq->descs) @@ -5129,11 +5151,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb, if (i == (skb_shinfo(skb)->nr_frags - 1)) { /* Last descriptor */ tx_desc->command = MVPP2_TXD_L_DESC; - mvpp2_txq_inc_put(txq_pcpu, skb); + mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc); } else { /* Descriptor in the middle: Not First, Not Last */ tx_desc->command = 0; - mvpp2_txq_inc_put(txq_pcpu, NULL); + mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc); } } @@ -5199,12 +5221,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) /* First and Last descriptor */ tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC; tx_desc->command = tx_cmd; - mvpp2_txq_inc_put(txq_pcpu, skb); + mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc); } else { /* First but not Last */ tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE; tx_desc->command = tx_cmd; - mvpp2_txq_inc_put(txq_pcpu, NULL); + mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc); /* Continue with other skb fragments */ if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) { -- cgit v0.10.2 From edc660fa09e2295b6ee2d2bf742c2a72dfeb18d2 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 6 Aug 2015 19:00:30 +0200 Subject: net: mvpp2: replace TX coalescing interrupts with hrtimer The PP2 controller is capable of per-CPU TX processing, which means there are per-CPU banked register sets and queues. Current version of the driver supports TX packet coalescing - once on given CPU sent packets amount reaches a threshold value, an IRQ occurs. However, there is a single interrupt line responsible for CPU0/1 TX and RX events (the latter is not per-CPU, the hardware does not support RSS). When the top-half executes the interrupt cause is not known. This is why in NAPI poll function, along with RX processing, IRQ cause register on both CPU's is accessed in order to determine on which of them the TX coalescing threshold might have been reached. Thus the egress processing and releasing the buffers is able to take place on the corresponding CPU. Hitherto approach lead to an illegal usage of on_each_cpu function in softirq context. The problem is solved by resigning from TX coalescing interrupts and separating egress finalization from NAPI processing. For that purpose a method of using hrtimer is introduced. In main transmit function (mvpp2_tx) buffers are released once a software coalescing threshold is reached. In case not all the data is processed a timer is set on this CPU - in its interrupt context a tasklet is scheduled in which all queues are processed. At once only one timer per-CPU can be running, which is controlled by a dedicated flag. This commit removes TX processing from NAPI polling function, disables hardware coalescing and enables hrtimer with tasklet, using new per-CPU port structure (mvpp2_port_pcpu). Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 3e25d314..d9884fd 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -299,6 +301,7 @@ /* Coalescing */ #define MVPP2_TXDONE_COAL_PKTS_THRESH 15 +#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL #define MVPP2_RX_COAL_PKTS 32 #define MVPP2_RX_COAL_USEC 100 @@ -660,6 +663,14 @@ struct mvpp2_pcpu_stats { u64 tx_bytes; }; +/* Per-CPU port control */ +struct mvpp2_port_pcpu { + struct hrtimer tx_done_timer; + bool timer_scheduled; + /* Tasklet for egress finalization */ + struct tasklet_struct tx_done_tasklet; +}; + struct mvpp2_port { u8 id; @@ -679,6 +690,9 @@ struct mvpp2_port { u32 pending_cause_rx; struct napi_struct napi; + /* Per-CPU port control */ + struct mvpp2_port_pcpu __percpu *pcpu; + /* Flags */ unsigned long flags; @@ -3798,7 +3812,6 @@ static void mvpp2_interrupts_unmask(void *arg) mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id), (MVPP2_CAUSE_MISC_SUM_MASK | - MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK | MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)); } @@ -4374,23 +4387,6 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port, rxq->time_coal = usec; } -/* Set threshold for TX_DONE pkts coalescing */ -static void mvpp2_tx_done_pkts_coal_set(void *arg) -{ - struct mvpp2_port *port = arg; - int queue; - u32 val; - - for (queue = 0; queue < txq_number; queue++) { - struct mvpp2_tx_queue *txq = port->txqs[queue]; - - val = (txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET) & - MVPP2_TRANSMITTED_THRESH_MASK; - mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); - mvpp2_write(port->priv, MVPP2_TXQ_THRESH_REG, val); - } -} - /* Free Tx queue skbuffs */ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, @@ -4425,7 +4421,7 @@ static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port, static inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port, u32 cause) { - int queue = fls(cause >> 16) - 1; + int queue = fls(cause) - 1; return port->txqs[queue]; } @@ -4452,6 +4448,29 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, netif_tx_wake_queue(nq); } +static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause) +{ + struct mvpp2_tx_queue *txq; + struct mvpp2_txq_pcpu *txq_pcpu; + unsigned int tx_todo = 0; + + while (cause) { + txq = mvpp2_get_tx_queue(port, cause); + if (!txq) + break; + + txq_pcpu = this_cpu_ptr(txq->pcpu); + + if (txq_pcpu->count) { + mvpp2_txq_done(port, txq, txq_pcpu); + tx_todo += txq_pcpu->count; + } + + cause &= ~(1 << txq->log_id); + } + return tx_todo; +} + /* Rx/Tx queue initialization/cleanup methods */ /* Allocate and initialize descriptors for aggr TXQ */ @@ -4812,7 +4831,6 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port) goto err_cleanup; } - on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1); on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1); return 0; @@ -4894,6 +4912,49 @@ static void mvpp2_link_event(struct net_device *dev) } } +static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu) +{ + ktime_t interval; + + if (!port_pcpu->timer_scheduled) { + port_pcpu->timer_scheduled = true; + interval = ktime_set(0, MVPP2_TXDONE_HRTIMER_PERIOD_NS); + hrtimer_start(&port_pcpu->tx_done_timer, interval, + HRTIMER_MODE_REL_PINNED); + } +} + +static void mvpp2_tx_proc_cb(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct mvpp2_port *port = netdev_priv(dev); + struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu); + unsigned int tx_todo, cause; + + if (!netif_running(dev)) + return; + port_pcpu->timer_scheduled = false; + + /* Process all the Tx queues */ + cause = (1 << txq_number) - 1; + tx_todo = mvpp2_tx_done(port, cause); + + /* Set the timer in case not all the packets were processed */ + if (tx_todo) + mvpp2_timer_set(port_pcpu); +} + +static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer) +{ + struct mvpp2_port_pcpu *port_pcpu = container_of(timer, + struct mvpp2_port_pcpu, + tx_done_timer); + + tasklet_schedule(&port_pcpu->tx_done_tasklet); + + return HRTIMER_NORESTART; +} + /* Main RX/TX processing routines */ /* Display more error info */ @@ -5262,6 +5323,17 @@ out: dev_kfree_skb_any(skb); } + /* Finalize TX processing */ + if (txq_pcpu->count >= txq->done_pkts_coal) + mvpp2_txq_done(port, txq, txq_pcpu); + + /* Set the timer in case not all frags were processed */ + if (txq_pcpu->count <= frags && txq_pcpu->count > 0) { + struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu); + + mvpp2_timer_set(port_pcpu); + } + return NETDEV_TX_OK; } @@ -5275,10 +5347,11 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause) netdev_err(dev, "tx fifo underrun error\n"); } -static void mvpp2_txq_done_percpu(void *arg) +static int mvpp2_poll(struct napi_struct *napi, int budget) { - struct mvpp2_port *port = arg; - u32 cause_rx_tx, cause_tx, cause_misc; + u32 cause_rx_tx, cause_rx, cause_misc; + int rx_done = 0; + struct mvpp2_port *port = netdev_priv(napi->dev); /* Rx/Tx cause register * @@ -5292,7 +5365,7 @@ static void mvpp2_txq_done_percpu(void *arg) */ cause_rx_tx = mvpp2_read(port->priv, MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); - cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; + cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK; if (cause_misc) { @@ -5304,26 +5377,6 @@ static void mvpp2_txq_done_percpu(void *arg) cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK); } - /* Release TX descriptors */ - if (cause_tx) { - struct mvpp2_tx_queue *txq = mvpp2_get_tx_queue(port, cause_tx); - struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); - - if (txq_pcpu->count) - mvpp2_txq_done(port, txq, txq_pcpu); - } -} - -static int mvpp2_poll(struct napi_struct *napi, int budget) -{ - u32 cause_rx_tx, cause_rx; - int rx_done = 0; - struct mvpp2_port *port = netdev_priv(napi->dev); - - on_each_cpu(mvpp2_txq_done_percpu, port, 1); - - cause_rx_tx = mvpp2_read(port->priv, - MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; /* Process RX packets */ @@ -5568,6 +5621,8 @@ err_cleanup_rxqs: static int mvpp2_stop(struct net_device *dev) { struct mvpp2_port *port = netdev_priv(dev); + struct mvpp2_port_pcpu *port_pcpu; + int cpu; mvpp2_stop_dev(port); mvpp2_phy_disconnect(port); @@ -5576,6 +5631,13 @@ static int mvpp2_stop(struct net_device *dev) on_each_cpu(mvpp2_interrupts_mask, port, 1); free_irq(port->irq, port); + for_each_present_cpu(cpu) { + port_pcpu = per_cpu_ptr(port->pcpu, cpu); + + hrtimer_cancel(&port_pcpu->tx_done_timer); + port_pcpu->timer_scheduled = false; + tasklet_kill(&port_pcpu->tx_done_tasklet); + } mvpp2_cleanup_rxqs(port); mvpp2_cleanup_txqs(port); @@ -5791,7 +5853,6 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev, txq->done_pkts_coal = c->tx_max_coalesced_frames; } - on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1); return 0; } @@ -6042,6 +6103,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, { struct device_node *phy_node; struct mvpp2_port *port; + struct mvpp2_port_pcpu *port_pcpu; struct net_device *dev; struct resource *res; const char *dt_mac_addr; @@ -6051,7 +6113,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, int features; int phy_mode; int priv_common_regs_num = 2; - int err, i; + int err, i, cpu; dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number, rxq_number); @@ -6142,6 +6204,24 @@ static int mvpp2_port_probe(struct platform_device *pdev, } mvpp2_port_power_up(port); + port->pcpu = alloc_percpu(struct mvpp2_port_pcpu); + if (!port->pcpu) { + err = -ENOMEM; + goto err_free_txq_pcpu; + } + + for_each_present_cpu(cpu) { + port_pcpu = per_cpu_ptr(port->pcpu, cpu); + + hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb; + port_pcpu->timer_scheduled = false; + + tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb, + (unsigned long)dev); + } + netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT); features = NETIF_F_SG | NETIF_F_IP_CSUM; dev->features = features | NETIF_F_RXCSUM; @@ -6151,7 +6231,7 @@ static int mvpp2_port_probe(struct platform_device *pdev, err = register_netdev(dev); if (err < 0) { dev_err(&pdev->dev, "failed to register netdev\n"); - goto err_free_txq_pcpu; + goto err_free_port_pcpu; } netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr); @@ -6160,6 +6240,8 @@ static int mvpp2_port_probe(struct platform_device *pdev, priv->port_list[id] = port; return 0; +err_free_port_pcpu: + free_percpu(port->pcpu); err_free_txq_pcpu: for (i = 0; i < txq_number; i++) free_percpu(port->txqs[i]->pcpu); @@ -6178,6 +6260,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port) int i; unregister_netdev(port->dev); + free_percpu(port->pcpu); free_percpu(port->stats); for (i = 0; i < txq_number; i++) free_percpu(port->txqs[i]->pcpu); -- cgit v0.10.2 From ade4dc3e616e33c80d7e62855fe1b6f9895bc7c3 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 6 Aug 2015 22:48:23 +0200 Subject: bna: fix interrupts storm caused by erroneous packets The commit "e29aa33 bna: Enable Multi Buffer RX" moved packets counter increment from the beginning of the NAPI processing loop after the check for erroneous packets so they are never accounted. This counter is used to inform firmware about number of processed completions (packets). As these packets are never acked the firmware fires IRQs for them again and again. Fixes: e29aa33 ("bna: Enable Multi Buffer RX") Signed-off-by: Ivan Vecera Acked-by: Rasesh Mody Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 0612b19..506047c 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -676,6 +676,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) if (!next_cmpl->valid) break; } + packets++; /* TODO: BNA_CQ_EF_LOCAL ? */ if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR | @@ -692,7 +693,6 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) else bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len); - packets++; rcb->rxq->rx_packets++; rcb->rxq->rx_bytes += totlen; ccb->bytes_per_intr += totlen; -- cgit v0.10.2 From 4e7c1330689e27556de407d3fdadc65ffff5eb12 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 7 Aug 2015 00:26:41 +0200 Subject: netlink: make sure -EBUSY won't escape from netlink_insert Linus reports the following deadlock on rtnl_mutex; triggered only once so far (extract): [12236.694209] NetworkManager D 0000000000013b80 0 1047 1 0x00000000 [12236.694218] ffff88003f902640 0000000000000000 ffffffff815d15a9 0000000000000018 [12236.694224] ffff880119538000 ffff88003f902640 ffffffff81a8ff84 00000000ffffffff [12236.694230] ffffffff81a8ff88 ffff880119c47f00 ffffffff815d133a ffffffff81a8ff80 [12236.694235] Call Trace: [12236.694250] [] ? schedule_preempt_disabled+0x9/0x10 [12236.694257] [] ? schedule+0x2a/0x70 [12236.694263] [] ? schedule_preempt_disabled+0x9/0x10 [12236.694271] [] ? __mutex_lock_slowpath+0x7f/0xf0 [12236.694280] [] ? mutex_lock+0x16/0x30 [12236.694291] [] ? rtnetlink_rcv+0x10/0x30 [12236.694299] [] ? netlink_unicast+0xfb/0x180 [12236.694309] [] ? rtnl_getlink+0x113/0x190 [12236.694319] [] ? rtnetlink_rcv_msg+0x7a/0x210 [12236.694331] [] ? sock_has_perm+0x5c/0x70 [12236.694339] [] ? rtnetlink_rcv+0x30/0x30 [12236.694346] [] ? netlink_rcv_skb+0x9c/0xc0 [12236.694354] [] ? rtnetlink_rcv+0x1f/0x30 [12236.694360] [] ? netlink_unicast+0xfb/0x180 [12236.694367] [] ? netlink_sendmsg+0x484/0x5d0 [12236.694376] [] ? __wake_up+0x2f/0x50 [12236.694387] [] ? sock_sendmsg+0x33/0x40 [12236.694396] [] ? ___sys_sendmsg+0x22e/0x240 [12236.694405] [] ? ___sys_recvmsg+0x135/0x1a0 [12236.694415] [] ? eventfd_write+0x82/0x210 [12236.694423] [] ? fsnotify+0x32e/0x4c0 [12236.694429] [] ? wake_up_q+0x60/0x60 [12236.694434] [] ? __sys_sendmsg+0x39/0x70 [12236.694440] [] ? entry_SYSCALL_64_fastpath+0x12/0x6a It seems so far plausible that the recursive call into rtnetlink_rcv() looks suspicious. One way, where this could trigger is that the senders NETLINK_CB(skb).portid was wrongly 0 (which is rtnetlink socket), so the rtnl_getlink() request's answer would be sent to the kernel instead to the actual user process, thus grabbing rtnl_mutex() twice. One theory would be that netlink_autobind() triggered via netlink_sendmsg() internally overwrites the -EBUSY error to 0, but where it is wrongly originating from __netlink_insert() instead. That would reset the socket's portid to 0, which is then filled into NETLINK_CB(skb).portid later on. As commit d470e3b483dc ("[NETLINK]: Fix two socket hashing bugs.") also puts it, -EBUSY should not be propagated from netlink_insert(). It looks like it's very unlikely to reproduce. We need to trigger the rhashtable_insert_rehash() handler under a situation where rehashing currently occurs (one /rare/ way would be to hit ht->elasticity limits while not filled enough to expand the hashtable, but that would rather require a specifically crafted bind() sequence with knowledge about destination slots, seems unlikely). It probably makes sense to guard __netlink_insert() in any case and remap that error. It was suggested that EOVERFLOW might be better than an already overloaded ENOMEM. Reference: http://thread.gmane.org/gmane.linux.network/372676 Reported-by: Linus Torvalds Signed-off-by: Daniel Borkmann Acked-by: Herbert Xu Acked-by: Thomas Graf Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d8e2e39..67d2104 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1096,6 +1096,11 @@ static int netlink_insert(struct sock *sk, u32 portid) err = __netlink_insert(table, sk); if (err) { + /* In case the hashtable backend returns with -EBUSY + * from here, it must not escape to the caller. + */ + if (unlikely(err == -EBUSY)) + err = -EOVERFLOW; if (err == -EEXIST) err = -EADDRINUSE; nlk_sk(sk)->portid = 0; -- cgit v0.10.2 From 330567b71d8716704b189454553c2696e1eceb6c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Aug 2015 10:54:28 +0200 Subject: ipv6: don't reject link-local nexthop on other interface 48ed7b26faa7 ("ipv6: reject locally assigned nexthop addresses") is too strict; it rejects following corner-case: ip -6 route add default via fe80::1:2:3 dev eth1 [ where fe80::1:2:3 is assigned to a local interface, but not eth1 ] Fix this by restricting search to given device if nh is linklocal. Joint work with Hannes Frederic Sowa. Fixes: 48ed7b26faa7 ("ipv6: reject locally assigned nexthop addresses") Signed-off-by: Hannes Frederic Sowa Signed-off-by: Florian Westphal Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6090969..9de4d2b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1831,6 +1831,7 @@ int ip6_route_add(struct fib6_config *cfg) int gwa_type; gw_addr = &cfg->fc_gateway; + gwa_type = ipv6_addr_type(gw_addr); /* if gw_addr is local we will fail to detect this in case * address is still TENTATIVE (DAD in progress). rt6_lookup() @@ -1838,11 +1839,12 @@ int ip6_route_add(struct fib6_config *cfg) * prefix route was assigned to, which might be non-loopback. */ err = -EINVAL; - if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0)) + if (ipv6_chk_addr_and_flags(net, gw_addr, + gwa_type & IPV6_ADDR_LINKLOCAL ? + dev : NULL, 0, 0)) goto out; rt->rt6i_gateway = *gw_addr; - gwa_type = ipv6_addr_type(gw_addr); if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { struct rt6_info *grt; -- cgit v0.10.2 From 7a76a021cd5a292be875fbc616daf03eab1e6996 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 7 Aug 2015 09:32:21 -0700 Subject: net-timestamp: Update skb_complete_tx_timestamp comment After "62bccb8 net-timestamp: Make the clone operation stand-alone from phy timestamping" the hwtstamps parameter of skb_complete_tx_timestamp() may no longer be NULL. Signed-off-by: Benjamin Poirier Cc: Alexander Duyck Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d6cdd6e..22b6d9c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2884,11 +2884,11 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb) * * PHY drivers may accept clones of transmitted packets for * timestamping via their phy_driver.txtstamp method. These drivers - * must call this function to return the skb back to the stack, with - * or without a timestamp. + * must call this function to return the skb back to the stack with a + * timestamp. * * @skb: clone of the the original outgoing packet - * @hwtstamps: hardware time stamps, may be NULL if not available + * @hwtstamps: hardware time stamps * */ void skb_complete_tx_timestamp(struct sk_buff *skb, -- cgit v0.10.2 From 21a447637d28eb824a1163c1fc5f41ffa4b28e33 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Aug 2015 22:15:25 +0300 Subject: cxgb4: missing curly braces in t4_setup_debugfs() There were missing curly braces so it means we call add_debugfs_mem() unintentionally. Fixes: 3ccc6cf74d8c ('cxgb4: Adds support for T6 adapter') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a11485f..c3c7db4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2332,10 +2332,11 @@ int t4_setup_debugfs(struct adapter *adap) EXT_MEM1_SIZE_G(size)); } } else { - if (i & EXT_MEM_ENABLE_F) + if (i & EXT_MEM_ENABLE_F) { size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A); add_debugfs_mem(adap, "mc", MEM_MC, EXT_MEM_SIZE_G(size)); + } } de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap, -- cgit v0.10.2 From e1615903eb6b5e599396d4b3d8e3e96f6d432a6e Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 10 Aug 2015 12:49:35 +0300 Subject: bnx2x: Prevent null pointer dereference on SKB release On error flows its possible to free an SKB even if it was not allocated. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index a90d736..f7fbdc9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -262,9 +262,9 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, if (likely(skb)) { (*pkts_compl)++; (*bytes_compl) += skb->len; + dev_kfree_skb_any(skb); } - dev_kfree_skb_any(skb); tx_buf->first_bd = 0; tx_buf->skb = NULL; -- cgit v0.10.2 From 0ea853dfa93371e651d8b7b27fd2344e973a86ed Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 10 Aug 2015 12:49:36 +0300 Subject: bnx2x: Free NVRAM lock at end of each page Writing each 4Kb page into flash might take up-to ~100 miliseconds, during which time management firmware cannot acces the nvram for its own uses. Firmware upgrade utility use the ethtool API to burn new flash images for the device via the ethtool API, doing so by writing several page-worth of data on each command. Such action might create problems for the management firmware, as the nvram might not be accessible for a long time. This patch changes the write implementation, releasing the nvram lock on the completion of each page, allowing the management firmware time to claim it and perform its own required actions. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 76b9052..5907c82 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1718,6 +1718,22 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, offset += sizeof(u32); data_buf += sizeof(u32); written_so_far += sizeof(u32); + + /* At end of each 4Kb page, release nvram lock to allow MFW + * chance to take it for its own use. + */ + if ((cmd_flags & MCPR_NVM_COMMAND_LAST) && + (written_so_far < buf_size)) { + DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, + "Releasing NVM lock after offset 0x%x\n", + (u32)(offset - sizeof(u32))); + bnx2x_release_nvram_lock(bp); + usleep_range(1000, 2000); + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + } + cmd_flags = 0; } -- cgit v0.10.2 From 0be017120b80f0fe3da9a8239f989a27e54828f2 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 5 Aug 2015 15:44:53 -0700 Subject: HID: wacom: Report correct device resolution when using the wireless adapater The 'wacom_wireless_work' function does not recalculate the tablet's resolution, causing the value contained in the 'features' struct to always be reported to userspace. This value is valid only for the pen interface, meaning that the value will be incorrect for the touchpad (if present). This in particular causes problems for libinput which relies on the reported resolution being correct. This patch adds the necessary calls to recalculate the resolution for each interface. This requires a little bit of code shuffling since both the 'wacom_set_default_phy' and 'wacom_calculate_res' are declared below their new first point of use in 'wacom_wireless_work'. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 44958d7..01b937e 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1284,6 +1284,39 @@ fail_register_pen_input: return error; } +/* + * Not all devices report physical dimensions from HID. + * Compute the default from hardcoded logical dimension + * and resolution before driver overwrites them. + */ +static void wacom_set_default_phy(struct wacom_features *features) +{ + if (features->x_resolution) { + features->x_phy = (features->x_max * 100) / + features->x_resolution; + features->y_phy = (features->y_max * 100) / + features->y_resolution; + } +} + +static void wacom_calculate_res(struct wacom_features *features) +{ + /* set unit to "100th of a mm" for devices not reported by HID */ + if (!features->unit) { + features->unit = 0x11; + features->unitExpo = -3; + } + + features->x_resolution = wacom_calc_hid_res(features->x_max, + features->x_phy, + features->unit, + features->unitExpo); + features->y_resolution = wacom_calc_hid_res(features->y_max, + features->y_phy, + features->unit, + features->unitExpo); +} + static void wacom_wireless_work(struct work_struct *work) { struct wacom *wacom = container_of(work, struct wacom, work); @@ -1341,6 +1374,8 @@ static void wacom_wireless_work(struct work_struct *work) if (wacom_wac1->features.type != INTUOSHT && wacom_wac1->features.type != BAMBOO_PT) wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD; + wacom_set_default_phy(&wacom_wac1->features); + wacom_calculate_res(&wacom_wac1->features); snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", @@ -1359,7 +1394,9 @@ static void wacom_wireless_work(struct work_struct *work) wacom_wac2->features = *((struct wacom_features *)id->driver_data); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; + wacom_set_default_phy(&wacom_wac2->features); wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; + wacom_calculate_res(&wacom_wac2->features); snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX, "%s (WL) Finger",wacom_wac2->features.name); snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX, @@ -1407,39 +1444,6 @@ void wacom_battery_work(struct work_struct *work) } } -/* - * Not all devices report physical dimensions from HID. - * Compute the default from hardcoded logical dimension - * and resolution before driver overwrites them. - */ -static void wacom_set_default_phy(struct wacom_features *features) -{ - if (features->x_resolution) { - features->x_phy = (features->x_max * 100) / - features->x_resolution; - features->y_phy = (features->y_max * 100) / - features->y_resolution; - } -} - -static void wacom_calculate_res(struct wacom_features *features) -{ - /* set unit to "100th of a mm" for devices not reported by HID */ - if (!features->unit) { - features->unit = 0x11; - features->unitExpo = -3; - } - - features->x_resolution = wacom_calc_hid_res(features->x_max, - features->x_phy, - features->unit, - features->unitExpo); - features->y_resolution = wacom_calc_hid_res(features->y_max, - features->y_phy, - features->unit, - features->unitExpo); -} - static size_t wacom_compute_pktlen(struct hid_device *hdev) { struct hid_report_enum *report_enum; -- cgit v0.10.2 From 9d332d92a95c9c67abe08b5f7cba64d8fc1e3c76 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Aug 2015 14:22:43 -0300 Subject: mkiss: Fix error handling in mkiss_open() If register_netdev() fails we are not propagating the error and we return success because ax_open() succeeded previously. Fix this by checking the return value of ax_open() and register_netdev() and propagate the error in case of failure. Reported-by: RUC_Soft_Sec Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 2ffbf13..216bfd3 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -728,11 +728,12 @@ static int mkiss_open(struct tty_struct *tty) dev->type = ARPHRD_AX25; /* Perform the low-level AX25 initialization. */ - if ((err = ax_open(ax->dev))) { + err = ax_open(ax->dev); + if (err) goto out_free_netdev; - } - if (register_netdev(dev)) + err = register_netdev(dev); + if (err) goto out_free_buffers; /* after register_netdev() - because else printk smashes the kernel */ -- cgit v0.10.2 From 2235f2ac75fd2501c251b0b699a9632e80239a6d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Aug 2015 09:09:13 -0700 Subject: inet: fix races with reqsk timers reqsk_queue_destroy() and reqsk_queue_unlink() should use del_timer_sync() instead of del_timer() before calling reqsk_put(), otherwise we could free a req still used by another cpu. But before doing so, reqsk_queue_destroy() must release syn_wait_lock spinlock or risk a dead lock, as reqsk_timer_handler() might need to take this same spinlock from reqsk_queue_unlink() (called from inet_csk_reqsk_queue_drop()) Fixes: fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 87b22c0..b42f0e2 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -103,10 +103,16 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) spin_lock_bh(&queue->syn_wait_lock); while ((req = lopt->syn_table[i]) != NULL) { lopt->syn_table[i] = req->dl_next; + /* Because of following del_timer_sync(), + * we must release the spinlock here + * or risk a dead lock. + */ + spin_unlock_bh(&queue->syn_wait_lock); atomic_inc(&lopt->qlen_dec); - if (del_timer(&req->rsk_timer)) + if (del_timer_sync(&req->rsk_timer)) reqsk_put(req); reqsk_put(req); + spin_lock_bh(&queue->syn_wait_lock); } spin_unlock_bh(&queue->syn_wait_lock); } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 60021d0..05e3145 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue, } spin_unlock(&queue->syn_wait_lock); - if (del_timer(&req->rsk_timer)) + if (del_timer_sync(&req->rsk_timer)) reqsk_put(req); return found; } -- cgit v0.10.2 From 3257d8b12f954c462d29de6201664a846328a522 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 10 Aug 2015 15:07:34 -0700 Subject: inet: fix possible request socket leak In commit b357a364c57c9 ("inet: fix possible panic in reqsk_queue_unlink()"), I missed fact that tcp_check_req() can return the listener socket in one case, and that we must release the request socket refcount or we leak it. Tested: Following packetdrill test template shows the issue 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 +0 < S 0:0(0) win 2920 +0 > S. 0:0(0) ack 1 +.002 < . 1:1(0) ack 21 win 2920 +0 > R 21:21(0) Fixes: b357a364c57c9 ("inet: fix possible panic in reqsk_queue_unlink()") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d7d4c2b..0ea2e1c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1348,7 +1348,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr); if (req) { nsk = tcp_check_req(sk, skb, req, false); - if (!nsk) + if (!nsk || nsk == sk) reqsk_put(req); return nsk; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6748c42..7a6cea5 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -943,7 +943,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb)); if (req) { nsk = tcp_check_req(sk, skb, req, false); - if (!nsk) + if (!nsk || nsk == sk) reqsk_put(req); return nsk; } -- cgit v0.10.2 From f2d016011c04fc36580a3efeeee9217fd80298f8 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Wed, 1 Jul 2015 19:09:24 +0900 Subject: drm/exynos: gsc: fix wrong bitwise operation for swap detection The bits for rotation are not used as exclusively. So GSC_IN_ROT_270 can not be used for swap detection. The definition of it is same with GSC_IN_ROT_MASK. It is enough to check GSC_IN_ROT_90 bit is set or not to check whether width / height size swapping is needed. Signed-off-by: Hyungwon Hwang Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 8040ed2..f1c6b76 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -593,8 +593,7 @@ static int gsc_src_set_transf(struct device *dev, gsc_write(cfg, GSC_IN_CON); - ctx->rotation = cfg & - (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0; + ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0; *swap = ctx->rotation; return 0; @@ -857,8 +856,7 @@ static int gsc_dst_set_transf(struct device *dev, gsc_write(cfg, GSC_IN_CON); - ctx->rotation = cfg & - (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0; + ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0; *swap = ctx->rotation; return 0; -- cgit v0.10.2 From e6e771dc05b07be1e2b6ced3fa764b30bdda517d Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:38 +0200 Subject: drm/exynos/hdmi: fix edid memory leak edid returned by drm_get_edid should be freed. The patch fixes it. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 99e2864..4a00990 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1064,6 +1064,7 @@ static int hdmi_get_modes(struct drm_connector *connector) { struct hdmi_context *hdata = ctx_from_connector(connector); struct edid *edid; + int ret; if (!hdata->ddc_adpt) return -ENODEV; @@ -1079,7 +1080,11 @@ static int hdmi_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); - return drm_add_edid_modes(connector, edid); + ret = drm_add_edid_modes(connector, edid); + + kfree(edid); + + return ret; } static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) -- cgit v0.10.2 From 9859e203713a190f79959681836da34606d0d5bd Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 10:07:53 +0200 Subject: drm/exynos/mixer: fix interrupt clearing The driver used incorrect flags to clear interrupt status. The patch fixes it. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index cae98db..25f0aac 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -718,6 +718,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) /* handling VSYNC */ if (val & MXR_INT_STATUS_VSYNC) { + /* vsync interrupt use different bit for read and clear */ + val |= MXR_INT_CLEAR_VSYNC; + val &= ~MXR_INT_STATUS_VSYNC; + /* interlace scan need to check shadow register */ if (ctx->interlace) { base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0)); @@ -743,11 +747,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) out: /* clear interrupts */ - if (~val & MXR_INT_EN_VSYNC) { - /* vsync interrupt use different bit for read and clear */ - val &= ~MXR_INT_EN_VSYNC; - val |= MXR_INT_CLEAR_VSYNC; - } mixer_reg_write(res, MXR_INT_STATUS, val); spin_unlock(&res->reg_slock); -- cgit v0.10.2 From 4f98f9446f0ec9bc7d1e9274a74e58b04ae48ead Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:40 +0200 Subject: drm/exynos/mixer: correct vsync configuration sequence Specification advises to clear vsync indicator before configuring vsync. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 25f0aac..923aa75 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -906,8 +906,8 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) } /* enable vsync interrupt */ - mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC, - MXR_INT_EN_VSYNC); + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); + mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC); return 0; } @@ -918,6 +918,7 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_resources *res = &mixer_ctx->mixer_res; /* disable vsync interrupt */ + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } @@ -1046,6 +1047,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); + if (ctx->int_en & MXR_INT_EN_VSYNC) + mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); } -- cgit v0.10.2 From 2c5f70ef58171943c0d9a89590b2bf9ee437ec48 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 9 Jul 2015 08:25:41 +0200 Subject: drm/exynos/mixer: always update INT_EN cache INT_EN cache field was updated only by mixer_enable_vblank. The patch adds update also by mixer_disable_vblank function. Signed-off-by: Andrzej Hajda Reviewed-by: Joonyoung Shim Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 923aa75..4706b56 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -917,6 +917,11 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; + if (!mixer_ctx->powered) { + mixer_ctx->int_en &= MXR_INT_EN_VSYNC; + return; + } + /* disable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC); mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); -- cgit v0.10.2 From 9992349a54823c511acc438364dceda7abe4ac98 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 9 Apr 2015 10:46:00 +0200 Subject: drm/exynos/fimc: fix runtime pm support Once pm_runtime_set_active() gets called, the kernel assumes that given device has already enabled runtime pm and will call pm_runtime_suspend() without matching pm_runtime_resume(). In case of DRM FIMC IPP driver, this will result in calling clk_disable() without respective call to clk_enable(). This patch removes call to pm_runtime_set_active() to ensure that pm_runtime_suspend/resume calls will match. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 842d6b8..2a65235 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1745,7 +1745,6 @@ static int fimc_probe(struct platform_device *pdev) spin_lock_init(&ctx->lock); platform_set_drvdata(pdev, ctx); - pm_runtime_set_active(dev); pm_runtime_enable(dev); ret = exynos_drm_ippdrv_register(ippdrv); -- cgit v0.10.2 From 4772ff03df8094fd99d28de5fcf5df3a3e9c68bb Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 11 Aug 2015 09:54:29 +0200 Subject: drm/dp/mst: Remove port after removing connector. The port is removed synchronously, but the connector delayed. This causes a use after free which can cause a kernel BUG with slug_debug=FPZU. This is fixed by freeing the port after the connector. This fixes a regression introduced with 6b8eeca65b18ae77e175cc2b6571731f0ee413bf "drm/dp/mst: close deadlock in connector destruction." Cc: stable@vger.kernel.org Cc: Dave Airlie Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 778bbb6..1325eec 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref) from an EDID retrieval */ if (port->connector) { mutex_lock(&mgr->destroy_connector_lock); - list_add(&port->connector->destroy_list, &mgr->destroy_connector_list); + list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); + return; } drm_dp_port_teardown_pdt(port, port->pdt); @@ -2660,7 +2661,7 @@ static void drm_dp_tx_work(struct work_struct *work) static void drm_dp_destroy_connector_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); - struct drm_connector *connector; + struct drm_dp_mst_port *port; /* * Not a regular list traverse as we have to drop the destroy @@ -2669,15 +2670,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) */ for (;;) { mutex_lock(&mgr->destroy_connector_lock); - connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list); - if (!connector) { + port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next); + if (!port) { mutex_unlock(&mgr->destroy_connector_lock); break; } - list_del(&connector->destroy_list); + list_del(&port->next); mutex_unlock(&mgr->destroy_connector_lock); - mgr->cbs->destroy_connector(mgr, connector); + mgr->cbs->destroy_connector(mgr, port->connector); + + drm_dp_port_teardown_pdt(port, port->pdt); + + if (!port->input && port->vcpi.vcpi > 0) + drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); + kfree(port); } } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 57ca8cc..3b4d8a4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -743,8 +743,6 @@ struct drm_connector { uint8_t num_h_tile, num_v_tile; uint8_t tile_h_loc, tile_v_loc; uint16_t tile_h_size, tile_v_size; - - struct list_head destroy_list; }; /** -- cgit v0.10.2 From ad6cd7bafcd2c812ba4200d5938e07304f1e2fcd Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 10 Aug 2015 18:11:06 +0100 Subject: Revert "xen/events/fifo: Handle linked events when closing a port" This reverts commit fcdf31a7c162de0c93a2bee51df4688ab0a348f8. This was causing a WARNING whenever a PIRQ was closed since shutdown_pirq() is called with irqs disabled. Signed-off-by: David Vrabel Cc: diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 1495ecc..96093ae 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -452,12 +452,10 @@ static void xen_free_irq(unsigned irq) irq_free_desc(irq); } -static void xen_evtchn_close(unsigned int port, unsigned int cpu) +static void xen_evtchn_close(unsigned int port) { struct evtchn_close close; - xen_evtchn_op_close(port, cpu); - close.port = port; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) BUG(); @@ -546,7 +544,7 @@ out: err: pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc); - xen_evtchn_close(evtchn, NR_CPUS); + xen_evtchn_close(evtchn); return 0; } @@ -567,7 +565,7 @@ static void shutdown_pirq(struct irq_data *data) return; mask_evtchn(evtchn); - xen_evtchn_close(evtchn, cpu_from_evtchn(evtchn)); + xen_evtchn_close(evtchn); xen_irq_info_cleanup(info); } @@ -611,7 +609,7 @@ static void __unbind_from_irq(unsigned int irq) if (VALID_EVTCHN(evtchn)) { unsigned int cpu = cpu_from_irq(irq); - xen_evtchn_close(evtchn, cpu); + xen_evtchn_close(evtchn); switch (type_from_irq(irq)) { case IRQT_VIRQ: diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index 6df8aac..ed673e1 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -255,12 +255,6 @@ static void evtchn_fifo_unmask(unsigned port) } } -static bool evtchn_fifo_is_linked(unsigned port) -{ - event_word_t *word = event_word_from_port(port); - return sync_test_bit(EVTCHN_FIFO_BIT(LINKED, word), BM(word)); -} - static uint32_t clear_linked(volatile event_word_t *word) { event_word_t new, old, w; @@ -287,8 +281,7 @@ static void handle_irq_for_port(unsigned port) static void consume_one_event(unsigned cpu, struct evtchn_fifo_control_block *control_block, - unsigned priority, unsigned long *ready, - bool drop) + unsigned priority, unsigned long *ready) { struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); uint32_t head; @@ -320,15 +313,13 @@ static void consume_one_event(unsigned cpu, if (head == 0) clear_bit(priority, ready); - if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) { - if (likely(!drop)) - handle_irq_for_port(port); - } + if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) + handle_irq_for_port(port); q->head[priority] = head; } -static void __evtchn_fifo_handle_events(unsigned cpu, bool drop) +static void evtchn_fifo_handle_events(unsigned cpu) { struct evtchn_fifo_control_block *control_block; unsigned long ready; @@ -340,16 +331,11 @@ static void __evtchn_fifo_handle_events(unsigned cpu, bool drop) while (ready) { q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES); - consume_one_event(cpu, control_block, q, &ready, drop); + consume_one_event(cpu, control_block, q, &ready); ready |= xchg(&control_block->ready, 0); } } -static void evtchn_fifo_handle_events(unsigned cpu) -{ - __evtchn_fifo_handle_events(cpu, false); -} - static void evtchn_fifo_resume(void) { unsigned cpu; @@ -385,26 +371,6 @@ static void evtchn_fifo_resume(void) event_array_pages = 0; } -static void evtchn_fifo_close(unsigned port, unsigned int cpu) -{ - if (cpu == NR_CPUS) - return; - - get_online_cpus(); - if (cpu_online(cpu)) { - if (WARN_ON(irqs_disabled())) - goto out; - - while (evtchn_fifo_is_linked(port)) - cpu_relax(); - } else { - __evtchn_fifo_handle_events(cpu, true); - } - -out: - put_online_cpus(); -} - static const struct evtchn_ops evtchn_ops_fifo = { .max_channels = evtchn_fifo_max_channels, .nr_channels = evtchn_fifo_nr_channels, @@ -418,7 +384,6 @@ static const struct evtchn_ops evtchn_ops_fifo = { .unmask = evtchn_fifo_unmask, .handle_events = evtchn_fifo_handle_events, .resume = evtchn_fifo_resume, - .close = evtchn_fifo_close, }; static int evtchn_fifo_alloc_control_block(unsigned cpu) diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h index d18e123..50c2050a 100644 --- a/drivers/xen/events/events_internal.h +++ b/drivers/xen/events/events_internal.h @@ -68,7 +68,6 @@ struct evtchn_ops { bool (*test_and_set_mask)(unsigned port); void (*mask)(unsigned port); void (*unmask)(unsigned port); - void (*close)(unsigned port, unsigned cpu); void (*handle_events)(unsigned cpu); void (*resume)(void); @@ -146,12 +145,6 @@ static inline void xen_evtchn_resume(void) evtchn_ops->resume(); } -static inline void xen_evtchn_op_close(unsigned port, unsigned cpu) -{ - if (evtchn_ops->close) - return evtchn_ops->close(port, cpu); -} - void xen_evtchn_2l_init(void); int xen_evtchn_fifo_init(void); -- cgit v0.10.2 From c22fe519e7e2b94ad173e0ea3b89c1a7d8be8d00 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Mon, 10 Aug 2015 19:10:38 +0100 Subject: xen/xenbus: Don't leak memory when unmapping the ring on HVM backend The commit ccc9d90a9a8b5c4ad7e9708ec41f75ff9e98d61d "xenbus_client: Extend interface to support multi-page ring" removes the call to free_xenballooned_pages() in xenbus_unmap_ring_vfree_hvm(), leaking a page for every shared ring. Only with backends running in HVM domains were affected. Signed-off-by: Julien Grall Cc: Reviewed-by: Boris Ostrovsky Reviewed-by: Wei Liu Signed-off-by: David Vrabel diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 9ad3272..e303535 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -814,8 +814,10 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles, addrs); - if (!rv) + if (!rv) { vunmap(vaddr); + free_xenballooned_pages(node->nr_handles, node->hvm.pages); + } else WARN(1, "Leaking %p, size %u page(s)\n", vaddr, node->nr_handles); -- cgit v0.10.2 From 09edea4f8fdeb4e292b80d493296070f5ec64e6e Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Mon, 10 Aug 2015 17:36:06 +0100 Subject: ARM: 8410/1: VDSO: fix coarse clock monotonicity regression Since 906c55579a63 ("timekeeping: Copy the shadow-timekeeper over the real timekeeper last") it has become possible on ARM to: - Obtain a CLOCK_MONOTONIC_COARSE or CLOCK_REALTIME_COARSE timestamp via syscall. - Subsequently obtain a timestamp for the same clock ID via VDSO which predates the first timestamp (by one jiffy). This is because ARM's update_vsyscall is deriving the coarse time using the __current_kernel_time interface, when it should really be using the timekeeper object provided to it by the timekeeping core. It happened to work before only because __current_kernel_time would access the same timekeeper object which had been passed to update_vsyscall. This is no longer the case. Cc: stable@vger.kernel.org Fixes: 906c55579a63 ("timekeeping: Copy the shadow-timekeeper over the real timekeeper last") Signed-off-by: Nathan Lynch Acked-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index efe17dd..54a5aea 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -296,7 +296,6 @@ static bool tk_is_cntvct(const struct timekeeper *tk) */ void update_vsyscall(struct timekeeper *tk) { - struct timespec xtime_coarse; struct timespec64 *wtm = &tk->wall_to_monotonic; if (!cntvct_ok) { @@ -308,10 +307,10 @@ void update_vsyscall(struct timekeeper *tk) vdso_write_begin(vdso_data); - xtime_coarse = __current_kernel_time(); vdso_data->tk_is_cntvct = tk_is_cntvct(tk); - vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec; - vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec; + vdso_data->xtime_coarse_sec = tk->xtime_sec; + vdso_data->xtime_coarse_nsec = (u32)(tk->tkr_mono.xtime_nsec >> + tk->tkr_mono.shift); vdso_data->wtm_clock_sec = wtm->tv_sec; vdso_data->wtm_clock_nsec = wtm->tv_nsec; -- cgit v0.10.2 From d3392f41f6d3cd0a034bd0aca47fabea2b47218e Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Sat, 8 Aug 2015 08:47:28 +0200 Subject: crypto: nx - respect sg limit bounds when building sg lists for SHA Commit 000851119e80 changed sha256/512 update functions to pass more data to nx_build_sg_list(), which ends with sg list overflows and usually with update functions failing for data larger than max_sg_len * NX_PAGE_SIZE. This happens because: - both "total" and "to_process" are updated, which leads to "to_process" getting overflowed for some data lengths For example: In first iteration "total" is 50, and let's assume "to_process" is 30 due to sg limits. At the end of first iteration "total" is set to 20. At start of 2nd iteration "to_process" overflows on: to_process = total - to_process; - "in_sg" is not reset to nx_ctx->in_sg after each iteration - nx_build_sg_list() is hitting overflow because the amount of data passed to it would require more than sgmax elements - as consequence of previous item, data stored in overflowed sg list may no longer be aligned to SHA*_BLOCK_SIZE This patch changes sha256/512 update functions so that "to_process" respects sg limits and never tries to pass more data to nx_build_sg_list() to avoid overflows. "to_process" is calculated as minimum of "total" and sg limits at start of every iteration. Fixes: 000851119e80 ("crypto: nx - Fix SHA concurrence issue and sg limit bounds") Signed-off-by: Jan Stancek Cc: stable@vger.kernel.org Cc: Leonidas Da Silva Barbosa Cc: Marcelo Henrique Cerri Cc: Fionnuala Gunter Cc: "David S. Miller" Signed-off-by: Herbert Xu diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c index 08f8d5c..becb738 100644 --- a/drivers/crypto/nx/nx-sha256.c +++ b/drivers/crypto/nx/nx-sha256.c @@ -71,7 +71,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, struct sha256_state *sctx = shash_desc_ctx(desc); struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; - struct nx_sg *in_sg; struct nx_sg *out_sg; u64 to_process = 0, leftover, total; unsigned long irq_flags; @@ -97,7 +96,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; - in_sg = nx_ctx->in_sg; max_sg_len = min_t(u64, nx_ctx->ap->sglen, nx_driver.of.max_sg_len/sizeof(struct nx_sg)); max_sg_len = min_t(u64, max_sg_len, @@ -114,17 +112,12 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, } do { - /* - * to_process: the SHA256_BLOCK_SIZE data chunk to process in - * this update. This value is also restricted by the sg list - * limits. - */ - to_process = total - to_process; - to_process = to_process & ~(SHA256_BLOCK_SIZE - 1); + int used_sgs = 0; + struct nx_sg *in_sg = nx_ctx->in_sg; if (buf_len) { data_len = buf_len; - in_sg = nx_build_sg_list(nx_ctx->in_sg, + in_sg = nx_build_sg_list(in_sg, (u8 *) sctx->buf, &data_len, max_sg_len); @@ -133,15 +126,27 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, rc = -EINVAL; goto out; } + used_sgs = in_sg - nx_ctx->in_sg; } + /* to_process: SHA256_BLOCK_SIZE aligned chunk to be + * processed in this iteration. This value is restricted + * by sg list limits and number of sgs we already used + * for leftover data. (see above) + * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len, + * but because data may not be aligned, we need to account + * for that too. */ + to_process = min_t(u64, total, + (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE); + to_process = to_process & ~(SHA256_BLOCK_SIZE - 1); + data_len = to_process - buf_len; in_sg = nx_build_sg_list(in_sg, (u8 *) data, &data_len, max_sg_len); nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg); - to_process = (data_len + buf_len); + to_process = data_len + buf_len; leftover = total - to_process; /* diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c index aff0fe5..b6e183d 100644 --- a/drivers/crypto/nx/nx-sha512.c +++ b/drivers/crypto/nx/nx-sha512.c @@ -71,7 +71,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, struct sha512_state *sctx = shash_desc_ctx(desc); struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; - struct nx_sg *in_sg; struct nx_sg *out_sg; u64 to_process, leftover = 0, total; unsigned long irq_flags; @@ -97,7 +96,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; - in_sg = nx_ctx->in_sg; max_sg_len = min_t(u64, nx_ctx->ap->sglen, nx_driver.of.max_sg_len/sizeof(struct nx_sg)); max_sg_len = min_t(u64, max_sg_len, @@ -114,18 +112,12 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, } do { - /* - * to_process: the SHA512_BLOCK_SIZE data chunk to process in - * this update. This value is also restricted by the sg list - * limits. - */ - to_process = total - leftover; - to_process = to_process & ~(SHA512_BLOCK_SIZE - 1); - leftover = total - to_process; + int used_sgs = 0; + struct nx_sg *in_sg = nx_ctx->in_sg; if (buf_len) { data_len = buf_len; - in_sg = nx_build_sg_list(nx_ctx->in_sg, + in_sg = nx_build_sg_list(in_sg, (u8 *) sctx->buf, &data_len, max_sg_len); @@ -133,8 +125,20 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, rc = -EINVAL; goto out; } + used_sgs = in_sg - nx_ctx->in_sg; } + /* to_process: SHA512_BLOCK_SIZE aligned chunk to be + * processed in this iteration. This value is restricted + * by sg list limits and number of sgs we already used + * for leftover data. (see above) + * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len, + * but because data may not be aligned, we need to account + * for that too. */ + to_process = min_t(u64, total, + (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE); + to_process = to_process & ~(SHA512_BLOCK_SIZE - 1); + data_len = to_process - buf_len; in_sg = nx_build_sg_list(in_sg, (u8 *) data, &data_len, max_sg_len); @@ -146,7 +150,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, goto out; } - to_process = (data_len + buf_len); + to_process = data_len + buf_len; leftover = total - to_process; /* -- cgit v0.10.2 From 3176bf2d7ccd64da9be7b07036e0ba8293179906 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Tue, 11 Aug 2015 19:25:15 +0800 Subject: ASoC: wm8960: update pll and clock setting function Add sysclk auto mode. When it's sysclk auto mode, if the MCLK is available for clock configure, using MCLK to provide sysclk directly, otherwise, search a available pll out frequcncy and set pll. Configure clock in hw_params may cause problems when using bypass style paths without hw_params in machine driver getting called. So add configure clock to set_bias_level. Signed-off-by: Zidan Wang Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 94c5c46..0fc8364 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -48,6 +48,9 @@ #define WM8960_DISOP 0x40 #define WM8960_DRES_MASK 0x30 +static bool is_pll_freq_available(unsigned int source, unsigned int target); +static int wm8960_set_pll(struct snd_soc_codec *codec, + unsigned int freq_in, unsigned int freq_out); /* * wm8960 register cache * We can't read the WM8960 register space when we are @@ -126,9 +129,12 @@ struct wm8960_priv { struct snd_soc_dapm_widget *rout1; struct snd_soc_dapm_widget *out3; bool deemph; - int playback_fs; + int lrclk; int bclk; int sysclk; + int clk_id; + int freq_in; + bool is_stream_in_use[2]; struct wm8960_data pdata; }; @@ -164,8 +170,8 @@ static int wm8960_set_deemph(struct snd_soc_codec *codec) if (wm8960->deemph) { best = 1; for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { - if (abs(deemph_settings[i] - wm8960->playback_fs) < - abs(deemph_settings[best] - wm8960->playback_fs)) + if (abs(deemph_settings[i] - wm8960->lrclk) < + abs(deemph_settings[best] - wm8960->lrclk)) best = i; } @@ -565,6 +571,9 @@ static struct { { 8000, 5 }, }; +/* -1 for reserved value */ +static const int sysclk_divs[] = { 1, -1, 2, -1 }; + /* Multiply 256 for internal 256 div */ static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; @@ -574,61 +583,110 @@ static const int bclk_divs[] = { 120, 160, 220, 240, 320, 320, 320 }; -static void wm8960_configure_clocking(struct snd_soc_codec *codec, - bool tx, int lrclk) +static int wm8960_configure_clocking(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + int sysclk, bclk, lrclk, freq_out, freq_in; u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); - u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); - u32 sysclk; - int i, j; + int i, j, k; if (!(iface1 & (1<<6))) { dev_dbg(codec->dev, "Codec is slave mode, no need to configure clock\n"); - return; + return 0; + } + + if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) { + dev_err(codec->dev, "No MCLK configured\n"); + return -EINVAL; } - if (!wm8960->sysclk) { - dev_dbg(codec->dev, "No SYSCLK configured\n"); - return; + freq_in = wm8960->freq_in; + bclk = wm8960->bclk; + lrclk = wm8960->lrclk; + /* + * If it's sysclk auto mode, check if the MCLK can provide sysclk or + * not. If MCLK can provide sysclk, using MCLK to provide sysclk + * directly. Otherwise, auto select a available pll out frequency + * and set PLL. + */ + if (wm8960->clk_id == WM8960_SYSCLK_AUTO) { + /* disable the PLL and using MCLK to provide sysclk */ + wm8960_set_pll(codec, 0, 0); + freq_out = freq_in; + } else if (wm8960->sysclk) { + freq_out = wm8960->sysclk; + } else { + dev_err(codec->dev, "No SYSCLK configured\n"); + return -EINVAL; } - if (!wm8960->bclk || !lrclk) { - dev_dbg(codec->dev, "No audio clocks configured\n"); - return; + /* check if the sysclk frequency is available. */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + sysclk = freq_out / sysclk_divs[i]; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + if (sysclk == dac_divs[j] * lrclk) { + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) + if (sysclk == bclk * bclk_divs[k] / 10) + break; + if (k != ARRAY_SIZE(bclk_divs)) + break; + } + } + if (j != ARRAY_SIZE(dac_divs)) + break; } - for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { - if (wm8960->sysclk == lrclk * dac_divs[i]) { - for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { - sysclk = wm8960->bclk * bclk_divs[j] / 10; - if (wm8960->sysclk == sysclk) + if (i != ARRAY_SIZE(sysclk_divs)) { + goto configure_clock; + } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { + dev_err(codec->dev, "failed to configure clock\n"); + return -EINVAL; + } + /* get a available pll out frequency and set pll */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + sysclk = lrclk * dac_divs[j]; + freq_out = sysclk * sysclk_divs[i]; + + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { + if (sysclk == bclk * bclk_divs[k] / 10 && + is_pll_freq_available(freq_in, freq_out)) { + wm8960_set_pll(codec, + freq_in, freq_out); break; + } else { + continue; + } } - if(j != ARRAY_SIZE(bclk_divs)) + if (k != ARRAY_SIZE(bclk_divs)) break; } + if (j != ARRAY_SIZE(dac_divs)) + break; } - if (i == ARRAY_SIZE(dac_divs)) { - dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); - return; + if (i == ARRAY_SIZE(sysclk_divs)) { + dev_err(codec->dev, "failed to configure clock\n"); + return -EINVAL; } - /* - * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC - * pin is used as a frame clock for ADCs and DACs. - */ - if (iface2 & (1<<6)) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); - else if (tx) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); - else if (!tx) - snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); +configure_clock: + /* configure sysclk clock */ + snd_soc_update_bits(codec, WM8960_CLOCK1, 3 << 1, i << 1); + + /* configure frame clock */ + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, j << 3); + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, j << 6); /* configure bit clock */ - snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); + snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, k); + + return 0; } static int wm8960_hw_params(struct snd_pcm_substream *substream, @@ -667,9 +725,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + wm8960->lrclk = params_rate(params); /* Update filters for the new rate */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - wm8960->playback_fs = params_rate(params); + if (tx) { wm8960_set_deemph(codec); } else { for (i = 0; i < ARRAY_SIZE(alc_rates); i++) @@ -682,7 +740,23 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, /* set iface */ snd_soc_write(codec, WM8960_IFACE1, iface); - wm8960_configure_clocking(codec, tx, params_rate(params)); + wm8960->is_stream_in_use[tx] = true; + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON && + !wm8960->is_stream_in_use[!tx]) + return wm8960_configure_clocking(codec); + + return 0; +} + +static int wm8960_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + + wm8960->is_stream_in_use[tx] = false; return 0; } @@ -702,6 +776,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + u16 pm2 = snd_soc_read(codec, WM8960_POWER2); int ret; switch (level) { @@ -721,11 +796,22 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, } } + ret = wm8960_configure_clocking(codec); + if (ret) + return ret; + /* Set VMID to 2x50k */ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); break; case SND_SOC_BIAS_ON: + /* + * If it's sysclk auto mode, and the pll is enabled, + * disable the pll + */ + if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) + wm8960_set_pll(codec, 0, 0); + if (!IS_ERR(wm8960->mclk)) clk_disable_unprepare(wm8960->mclk); break; @@ -780,6 +866,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + u16 pm2 = snd_soc_read(codec, WM8960_POWER2); int reg, ret; switch (level) { @@ -831,9 +918,21 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, return ret; } } + + ret = wm8960_configure_clocking(codec); + if (ret) + return ret; + break; case SND_SOC_BIAS_ON: + /* + * If it's sysclk auto mode, and the pll is enabled, + * disable the pll + */ + if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) + wm8960_set_pll(codec, 0, 0); + if (!IS_ERR(wm8960->mclk)) clk_disable_unprepare(wm8960->mclk); @@ -892,6 +991,28 @@ struct _pll_div { u32 k:24; }; +static bool is_pll_freq_available(unsigned int source, unsigned int target) +{ + unsigned int Ndiv; + + if (source == 0 || target == 0) + return false; + + /* Scale up target to PLL operating frequency */ + target *= 4; + Ndiv = target / source; + + if (Ndiv < 6) { + source >>= 1; + Ndiv = target / source; + } + + if ((Ndiv < 6) || (Ndiv > 12)) + return false; + + return true; +} + /* The size in bits of the pll divide multiplied by 10 * to allow rounding later */ #define FIXED_PLL_SIZE ((1 << 24) * 10) @@ -943,10 +1064,9 @@ static int pll_factors(unsigned int source, unsigned int target, return 0; } -static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out) +static int wm8960_set_pll(struct snd_soc_codec *codec, + unsigned int freq_in, unsigned int freq_out) { - struct snd_soc_codec *codec = codec_dai->codec; u16 reg; static struct _pll_div pll_div; int ret; @@ -986,6 +1106,20 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, return 0; } +static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + + wm8960->freq_in = freq_in; + + if (pll_id == WM8960_SYSCLK_AUTO) + return 0; + + return wm8960_set_pll(codec, freq_in, freq_out); +} + static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { @@ -1043,11 +1177,14 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, WM8960_SYSCLK_PLL); break; + case WM8960_SYSCLK_AUTO: + break; default: return -EINVAL; } wm8960->sysclk = freq; + wm8960->clk_id = clk_id; return 0; } @@ -1060,6 +1197,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, static const struct snd_soc_dai_ops wm8960_dai_ops = { .hw_params = wm8960_hw_params, + .hw_free = wm8960_hw_free, .digital_mute = wm8960_mute, .set_fmt = wm8960_set_dai_fmt, .set_clkdiv = wm8960_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h index 2d8163d..ab3220d 100644 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -82,6 +82,7 @@ #define WM8960_SYSCLK_MCLK (0 << 0) #define WM8960_SYSCLK_PLL (1 << 0) +#define WM8960_SYSCLK_AUTO (2 << 0) #define WM8960_DAC_DIV_1 (0 << 3) #define WM8960_DAC_DIV_1_5 (1 << 3) -- cgit v0.10.2 From 1af2cc64b18c29f1d774caa7e592c781bee6a7eb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Aug 2015 14:47:18 +0200 Subject: ASoC: rsnd: Silence DMA slave ID compile warning on 64-bit On arm64: sound/soc/sh/rcar/dma.c: In function 'rsnd_dmaen_init': sound/soc/sh/rcar/dma.c:180:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] (void *)id); ^ include/linux/dmaengine.h:1185:75: note: in definition of macro 'dma_request_channel' #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) ^ Add an intermediate cast to "uintptr_t" to kill the compile warning. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 305b129..bfbb8a5 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -177,7 +177,7 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, dma_cap_set(DMA_SLAVE, mask); dmaen->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)id); + (void *)(uintptr_t)id); } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; -- cgit v0.10.2 From 9b850ca4f1c5acd7fcbbd4b38a2d27132801a8d5 Mon Sep 17 00:00:00 2001 From: John Lin Date: Tue, 11 Aug 2015 14:27:25 +0800 Subject: ASoC: rt5640: fix line out no sound issue The power for line out was not turned on when line out is enabled. So we add "LOUT amp" widget to turn on the power for line out. Signed-off-by: John Lin Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e5..ff72cd8 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -984,6 +984,35 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5640_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + hp_amp_power_on(codec); + snd_soc_update_bits(codec, RT5640_PWR_ANLG1, + RT5640_PWR_LM, RT5640_PWR_LM); + snd_soc_update_bits(codec, RT5640_OUTPUT, + RT5640_L_MUTE | RT5640_R_MUTE, 0); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5640_OUTPUT, + RT5640_L_MUTE | RT5640_R_MUTE, + RT5640_L_MUTE | RT5640_R_MUTE); + snd_soc_update_bits(codec, RT5640_PWR_ANLG1, + RT5640_PWR_LM, 0); + break; + + default: + return 0; + } + + return 0; +} + static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1179,13 +1208,16 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { 0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)), SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)), - SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0, + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)), SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM, 0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5640_hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, + rt5640_lout_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1, RT5640_PWR_HP_L_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1, @@ -1500,8 +1532,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"HP R Playback", "Switch", "HP Amp"}, {"HPOL", NULL, "HP L Playback"}, {"HPOR", NULL, "HP R Playback"}, - {"LOUTL", NULL, "LOUT MIX"}, - {"LOUTR", NULL, "LOUT MIX"}, + + {"LOUT amp", NULL, "LOUT MIX"}, + {"LOUTL", NULL, "LOUT amp"}, + {"LOUTR", NULL, "LOUT amp"}, }; static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { -- cgit v0.10.2 From 9b7493d00c06013fb9192ea23cc83a1a2d003d61 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Tue, 11 Aug 2015 11:14:26 +0800 Subject: ASoC: fsl-sai: add 32 bit word length support Add 32 bit word length support. There are no code changes required in the SAI driver since it has already wirten the word width to the corresponding register. Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0662809..d137290 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -13,7 +13,8 @@ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) /* SAI Register Map Register */ #define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ -- cgit v0.10.2 From 8961822c46cc363c239503f998a6d24bbeb346d5 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Tue, 11 Aug 2015 12:11:00 +0200 Subject: net: fs_enet: explicitly remove I flag on TX partial frames We are not interested in interrupts for partially transmitted frames, we have to clear BD_ENET_TX_INTR explicitly otherwise it may remain from a previously used descriptor. Signed-off-by: Christophe Leroy Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 56316db..cf8e546 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -586,7 +586,8 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) frag = skb_shinfo(skb)->frags; while (nr_frags) { CBDC_SC(bdp, - BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC); + BD_ENET_TX_STATS | BD_ENET_TX_INTR | BD_ENET_TX_LAST | + BD_ENET_TX_TC); CBDS_SC(bdp, BD_ENET_TX_READY); if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) -- cgit v0.10.2 From c68875fa82a8ab2f45a32aa8adab059f3cb1ed01 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Tue, 11 Aug 2015 12:11:03 +0200 Subject: net: fs_enet: mask interrupts for TX partial frames. We are not interested in interrupts for partially transmitted frames. Unlike SCC and FCC, the FEC doesn't handle the I bit in buffer descriptors, instead it defines two interrupt bits, TXB and TXF. We have to mask TXB in order to only get interrupts once the frame is fully transmitted. Signed-off-by: Christophe Leroy Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c index b34214e..016743e 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c @@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep) } #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) -#define FEC_NAPI_TX_EVENT_MSK (FEC_ENET_TXF | FEC_ENET_TXB) +#define FEC_NAPI_TX_EVENT_MSK (FEC_ENET_TXF) #define FEC_RX_EVENT (FEC_ENET_RXF) #define FEC_TX_EVENT (FEC_ENET_TXF) #define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ -- cgit v0.10.2 From c0ddc8c745b7f89c50385fd7aa03c78dc543fa7a Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 27 Jul 2015 00:06:55 +0200 Subject: localmodconfig: Use Kbuild files too In kbuild it is allowed to define objects in files named "Makefile" and "Kbuild". Currently localmodconfig reads objects only from "Makefile"s and misses modules like nouveau. Link: http://lkml.kernel.org/r/1437948415-16290-1-git-send-email-richard@nod.at Cc: stable@vger.kernel.org Reported-and-tested-by: Leonidas Spyropoulos Signed-off-by: Richard Weinberger Signed-off-by: Steven Rostedt diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 9cb8522..f3d3fb4 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -137,7 +137,7 @@ my $ksource = ($ARGV[0] ? $ARGV[0] : '.'); my $kconfig = $ARGV[1]; my $lsmod_file = $ENV{'LSMOD'}; -my @makefiles = `find $ksource -name Makefile 2>/dev/null`; +my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`; chomp @makefiles; my %depends; -- cgit v0.10.2 From e984a1791ac6a7c944911207e8a9c344763f0003 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 5 Aug 2015 14:24:15 +0200 Subject: memory: omap-gpmc: Don't try to save uninitialized GPMC context If for some reason the GPMC device hasn't been probed yet, gpmc_base is going to be NULL. Because there's no context yet to be saved, just turn these functions into no-ops until that device gets probed. Unable to handle kernel NULL pointer dereference at virtual address 00000010 pgd = c0204000 [00000010] *pgd=00000000 Internal error: Oops: 5 [#1] SMP ARM Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.2.0-rc5-next-20150804-05947-g23f38fe8eda9 #1 Hardware name: Generic OMAP3-GP (Flattened Device Tree) task: c0e623e8 ti: c0e5c000 task.ti: c0e5c000 PC is at omap3_gpmc_save_context+0x8/0xc4 LR is at omap_sram_idle+0x154/0x23c pc : [] lr : [] psr: 60000193 sp : c0e5df40 ip : c0f92a80 fp : c0999eb0 r10: c0e57364 r9 : c0e66f14 r8 : 00000003 r7 : 00000000 r6 : 00000003 r5 : 00000000 r4 : c0f5f174 r3 : c0fa4fe8 r2 : 00000000 r1 : 00000000 r0 : fa200280 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 80204019 DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0xc0e5c220) Stack: (0xc0e5df40 to 0xc0e5e000) df40: 00000000 c0e66ef8 c0f5f1a4 00000000 00000003 c02333a4 c3813822 00000000 df60: 00000000 c0e5a5c8 cfb8a5d0 c07f0c44 0e4f1d7e 00000000 00000000 00000000 df80: c3813822 00000000 cfb8a5d0 c0e5e4e4 cfb8a5d0 c0e66f14 c0e5a5c8 c0e5e54c dfa0: c0e5e544 c0e57364 c0999eb0 c0277758 000000fa c0f5d000 00000000 c0d61c18 dfc0: ffffffff ffffffff 00000000 c0d61674 00000000 c0df7a48 00000000 c0f5d5d4 dfe0: c0e5e4c0 c0df7a44 c0e634f8 80204059 00000000 8020807c 00000000 00000000 [] (omap3_gpmc_save_context) from [] (omap_sram_idle+0x154/0x23c) [] (omap_sram_idle) from [] (omap3_enter_idle_bm+0xec/0x1a8) [] (omap3_enter_idle_bm) from [] (cpuidle_enter_state+0xbc/0x284) [] (cpuidle_enter_state) from [] (cpu_startup_entry+0x174/0x24c) [] (cpu_startup_entry) from [] (start_kernel+0x358/0x3c0) [] (start_kernel) from [<8020807c>] (0x8020807c) Code: c0ccace8 c0ccacc0 e59f30b4 e5932000 (e5921010) Signed-off-by: Tomeu Vizoso Suggested-by: Javier Martinez Canillas Reviewed-by: Javier Martinez Canillas Acked-by: Roger Quadros [tony@atomide.com: updated description as suggested by Javier] Signed-off-by: Tony Lindgren diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 3a27a84..9426276 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -2245,6 +2245,9 @@ void omap3_gpmc_save_context(void) { int i; + if (!gpmc_base) + return; + gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG); gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE); gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL); @@ -2277,6 +2280,9 @@ void omap3_gpmc_restore_context(void) { int i; + if (!gpmc_base) + return; + gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig); gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable); gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl); -- cgit v0.10.2 From ee9397a6fb9bc4e52677f5e33eed4abee0f515e6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 27 Jul 2015 00:31:08 +0100 Subject: perf: Fix double-free of the AUX buffer If rb->aux_refcount is decremented to zero before rb->refcount, __rb_free_aux() may be called twice resulting in a double free of rb->aux_pages. Fix this by adding a check to __rb_free_aux(). Signed-off-by: Ben Hutchings Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Fixes: 57ffc5ca679f ("perf: Fix AUX buffer refcounting") Link: http://lkml.kernel.org/r/1437953468.12842.17.camel@decadent.org.uk Signed-off-by: Ingo Molnar diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index b2be01b..c8aa3f7 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -559,11 +559,13 @@ static void __rb_free_aux(struct ring_buffer *rb) rb->aux_priv = NULL; } - for (pg = 0; pg < rb->aux_nr_pages; pg++) - rb_free_aux_page(rb, pg); + if (rb->aux_nr_pages) { + for (pg = 0; pg < rb->aux_nr_pages; pg++) + rb_free_aux_page(rb, pg); - kfree(rb->aux_pages); - rb->aux_nr_pages = 0; + kfree(rb->aux_pages); + rb->aux_nr_pages = 0; + } } void rb_free_aux(struct ring_buffer *rb) -- cgit v0.10.2 From c7999c6f3fed9e383d3131474588f282ae6d56b9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 4 Aug 2015 19:22:49 +0200 Subject: perf: Fix PERF_EVENT_IOC_PERIOD migration race I ran the perf fuzzer, which triggered some WARN()s which are due to trying to stop/restart an event on the wrong CPU. Use the normal IPI pattern to ensure we run the code on the correct CPU. Signed-off-by: Peter Zijlstra (Intel) Cc: Vince Weaver Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: bad7192b842c ("perf: Fix PERF_EVENT_IOC_PERIOD to force-reset the period") Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 072b8a6..e6feb51 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3958,28 +3958,21 @@ static void perf_event_for_each(struct perf_event *event, perf_event_for_each_child(sibling, func); } -static int perf_event_period(struct perf_event *event, u64 __user *arg) -{ - struct perf_event_context *ctx = event->ctx; - int ret = 0, active; +struct period_event { + struct perf_event *event; u64 value; +}; - if (!is_sampling_event(event)) - return -EINVAL; - - if (copy_from_user(&value, arg, sizeof(value))) - return -EFAULT; - - if (!value) - return -EINVAL; +static int __perf_event_period(void *info) +{ + struct period_event *pe = info; + struct perf_event *event = pe->event; + struct perf_event_context *ctx = event->ctx; + u64 value = pe->value; + bool active; - raw_spin_lock_irq(&ctx->lock); + raw_spin_lock(&ctx->lock); if (event->attr.freq) { - if (value > sysctl_perf_event_sample_rate) { - ret = -EINVAL; - goto unlock; - } - event->attr.sample_freq = value; } else { event->attr.sample_period = value; @@ -3998,11 +3991,53 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) event->pmu->start(event, PERF_EF_RELOAD); perf_pmu_enable(ctx->pmu); } + raw_spin_unlock(&ctx->lock); -unlock: + return 0; +} + +static int perf_event_period(struct perf_event *event, u64 __user *arg) +{ + struct period_event pe = { .event = event, }; + struct perf_event_context *ctx = event->ctx; + struct task_struct *task; + u64 value; + + if (!is_sampling_event(event)) + return -EINVAL; + + if (copy_from_user(&value, arg, sizeof(value))) + return -EFAULT; + + if (!value) + return -EINVAL; + + if (event->attr.freq && value > sysctl_perf_event_sample_rate) + return -EINVAL; + + task = ctx->task; + pe.value = value; + + if (!task) { + cpu_function_call(event->cpu, __perf_event_period, &pe); + return 0; + } + +retry: + if (!task_function_call(task, __perf_event_period, &pe)) + return 0; + + raw_spin_lock_irq(&ctx->lock); + if (ctx->is_active) { + raw_spin_unlock_irq(&ctx->lock); + task = ctx->task; + goto retry; + } + + __perf_event_period(&pe); raw_spin_unlock_irq(&ctx->lock); - return ret; + return 0; } static const struct file_operations perf_fops; -- cgit v0.10.2 From dbc72b7a0c673ff00fdeb21d3a26064e2185baf4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 10 Aug 2015 14:17:34 +0200 Subject: perf/x86/intel: Fix memory leak on hot-plug allocation fail We fail to free the shared_regs allocation if the constraint_list allocation fails. Cure this and be more consistent in NULL-ing the pointers after free. Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index b9826a9..6326ae2 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2534,7 +2534,7 @@ static int intel_pmu_cpu_prepare(int cpu) if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) { cpuc->shared_regs = allocate_shared_regs(cpu); if (!cpuc->shared_regs) - return NOTIFY_BAD; + goto err; } if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) { @@ -2542,18 +2542,27 @@ static int intel_pmu_cpu_prepare(int cpu) cpuc->constraint_list = kzalloc(sz, GFP_KERNEL); if (!cpuc->constraint_list) - return NOTIFY_BAD; + goto err_shared_regs; cpuc->excl_cntrs = allocate_excl_cntrs(cpu); - if (!cpuc->excl_cntrs) { - kfree(cpuc->constraint_list); - kfree(cpuc->shared_regs); - return NOTIFY_BAD; - } + if (!cpuc->excl_cntrs) + goto err_constraint_list; + cpuc->excl_thread_id = 0; } return NOTIFY_OK; + +err_constraint_list: + kfree(cpuc->constraint_list); + cpuc->constraint_list = NULL; + +err_shared_regs: + kfree(cpuc->shared_regs); + cpuc->shared_regs = NULL; + +err: + return NOTIFY_BAD; } static void intel_pmu_cpu_starting(int cpu) -- cgit v0.10.2 From d7a702f0b1033cf402fef65bd6395072738f0844 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 6 Aug 2015 13:12:43 +0100 Subject: perf/x86/intel/cqm: Do not access cpu_data() from CPU_UP_PREPARE handler Tony reports that booting his 144-cpu machine with maxcpus=10 triggers the following WARN_ON(): [ 21.045727] WARNING: CPU: 8 PID: 647 at arch/x86/kernel/cpu/perf_event_intel_cqm.c:1267 intel_cqm_cpu_prepare+0x75/0x90() [ 21.045744] CPU: 8 PID: 647 Comm: systemd-udevd Not tainted 4.2.0-rc4 #1 [ 21.045745] Hardware name: Intel Corporation BRICKLAND/BRICKLAND, BIOS BRHSXSD1.86B.0066.R00.1506021730 06/02/2015 [ 21.045747] 0000000000000000 0000000082771b09 ffff880856333ba8 ffffffff81669b67 [ 21.045748] 0000000000000000 0000000000000000 ffff880856333be8 ffffffff8107b02a [ 21.045750] ffff88085b789800 ffff88085f68a020 ffffffff819e2470 000000000000000a [ 21.045750] Call Trace: [ 21.045757] [] dump_stack+0x45/0x57 [ 21.045759] [] warn_slowpath_common+0x8a/0xc0 [ 21.045761] [] warn_slowpath_null+0x1a/0x20 [ 21.045762] [] intel_cqm_cpu_prepare+0x75/0x90 [ 21.045764] [] intel_cqm_cpu_notifier+0x42/0x160 [ 21.045767] [] notifier_call_chain+0x4d/0x80 [ 21.045769] [] __raw_notifier_call_chain+0xe/0x10 [ 21.045770] [] _cpu_up+0xe8/0x190 [ 21.045771] [] cpu_up+0x7a/0xa0 [ 21.045774] [] cpu_subsys_online+0x40/0x90 [ 21.045777] [] device_online+0x67/0x90 [ 21.045778] [] online_store+0x8a/0xa0 [ 21.045782] [] dev_attr_store+0x18/0x30 [ 21.045785] [] sysfs_kf_write+0x3a/0x50 [ 21.045786] [] kernfs_fop_write+0x120/0x170 [ 21.045789] [] __vfs_write+0x37/0x100 [ 21.045791] [] ? __sb_start_write+0x58/0x110 [ 21.045795] [] ? security_file_permission+0x3d/0xc0 [ 21.045796] [] vfs_write+0xa9/0x190 [ 21.045797] [] SyS_write+0x55/0xc0 [ 21.045800] [] ? do_page_fault+0x30/0x80 [ 21.045804] [] entry_SYSCALL_64_fastpath+0x12/0x71 [ 21.045805] ---[ end trace fe228b836d8af405 ]--- The root cause is that CPU_UP_PREPARE is completely the wrong notifier action from which to access cpu_data(), because smp_store_cpu_info() won't have been executed by the target CPU at that point, which in turn means that ->x86_cache_max_rmid and ->x86_cache_occ_scale haven't been filled out. Instead let's invoke our handler from CPU_STARTING and rename it appropriately. Reported-by: Tony Luck Signed-off-by: Matt Fleming Signed-off-by: Peter Zijlstra (Intel) Cc: Ashok Raj Cc: Kanaka Juvva Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vikas Shivappa Link: http://lkml.kernel.org/r/1438863163-14083-1-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c index 63eb68b..377e8f8 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c +++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c @@ -1255,7 +1255,7 @@ static inline void cqm_pick_event_reader(int cpu) cpumask_set_cpu(cpu, &cqm_cpumask); } -static void intel_cqm_cpu_prepare(unsigned int cpu) +static void intel_cqm_cpu_starting(unsigned int cpu) { struct intel_pqr_state *state = &per_cpu(pqr_state, cpu); struct cpuinfo_x86 *c = &cpu_data(cpu); @@ -1296,13 +1296,11 @@ static int intel_cqm_cpu_notifier(struct notifier_block *nb, unsigned int cpu = (unsigned long)hcpu; switch (action & ~CPU_TASKS_FROZEN) { - case CPU_UP_PREPARE: - intel_cqm_cpu_prepare(cpu); - break; case CPU_DOWN_PREPARE: intel_cqm_cpu_exit(cpu); break; case CPU_STARTING: + intel_cqm_cpu_starting(cpu); cqm_pick_event_reader(cpu); break; } @@ -1373,7 +1371,7 @@ static int __init intel_cqm_init(void) goto out; for_each_online_cpu(i) { - intel_cqm_cpu_prepare(i); + intel_cqm_cpu_starting(i); cqm_pick_event_reader(i); } -- cgit v0.10.2 From dcfcf2c2cd71906073beef32aadb1989e8996951 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Wed, 12 Aug 2015 14:38:18 +0800 Subject: ASoC: fsl: fix typos for sound/soc/fsl/* There are too much noise about the typos for fsl's drivers. So I fix all the typos here in this patch in almost every file I touched. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index e1aa3834..883087f 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -182,7 +182,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) ); } else { if (np) { - /* The eukrea,asoc-tlv320 driver was explicitely + /* The eukrea,asoc-tlv320 driver was explicitly * requested (through the device tree). */ dev_err(&pdev->dev, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0662809..b4666fd 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -45,7 +45,7 @@ #define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR) #define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) -/* SAI Transmit/Recieve Control Register */ +/* SAI Transmit/Receive Control Register */ #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FR BIT(25) #define FSL_SAI_CSR_SR BIT(24) @@ -67,10 +67,10 @@ #define FSL_SAI_CSR_FRIE BIT(8) #define FSL_SAI_CSR_FRDE BIT(0) -/* SAI Transmit and Recieve Configuration 1 Register */ +/* SAI Transmit and Receive Configuration 1 Register */ #define FSL_SAI_CR1_RFW_MASK 0x1f -/* SAI Transmit and Recieve Configuration 2 Register */ +/* SAI Transmit and Receive Configuration 2 Register */ #define FSL_SAI_CR2_SYNC BIT(30) #define FSL_SAI_CR2_MSEL_MASK (0x3 << 26) #define FSL_SAI_CR2_MSEL_BUS 0 @@ -82,12 +82,12 @@ #define FSL_SAI_CR2_BCD_MSTR BIT(24) #define FSL_SAI_CR2_DIV_MASK 0xff -/* SAI Transmit and Recieve Configuration 3 Register */ +/* SAI Transmit and Receive Configuration 3 Register */ #define FSL_SAI_CR3_TRCE BIT(16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f -/* SAI Transmit and Recieve Configuration 4 Register */ +/* SAI Transmit and Receive Configuration 4 Register */ #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) @@ -97,7 +97,7 @@ #define FSL_SAI_CR4_FSP BIT(1) #define FSL_SAI_CR4_FSD_MSTR BIT(0) -/* SAI Transmit and Recieve Configuration 5 Register */ +/* SAI Transmit and Receive Configuration 5 Register */ #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index d1e9be7..92efbc5 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -707,7 +707,7 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, return ret; } -/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */ +/* Q-subcode information. The byte size is SPDIF_UBITS_SIZE/8 */ static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -739,7 +739,7 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, return ret; } -/* Valid bit infomation */ +/* Valid bit information */ static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -767,7 +767,7 @@ static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, return 0; } -/* DPLL lock infomation */ +/* DPLL lock information */ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e122dab..6a338b8 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -156,7 +156,7 @@ struct fsl_ssi_soc_data { * * @dbg_stats: Debugging statistics * - * @soc: SoC specifc data + * @soc: SoC specific data */ struct fsl_ssi_private { struct regmap *regs; @@ -1210,7 +1210,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, } } - /* For those SLAVE implementations, we ingore non-baudclk cases + /* For those SLAVE implementations, we ignore non-baudclk cases * and, instead, abandon MASTER mode that needs baud clock. */ ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud"); -- cgit v0.10.2 From 7f518ad0a212e2a6fd68630e176af1de395070a7 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 12 Aug 2015 15:10:21 +0100 Subject: dm thin metadata: delete btrees when releasing metadata snapshot The device details and mapping trees were just being decremented before. Now btree_del() is called to do a deep delete. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 48dfe3c..6ba47cf 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1293,8 +1293,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd) return r; disk_super = dm_block_data(copy); - dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root)); - dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root)); + dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root)); + dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root)); dm_sm_dec_block(pmd->metadata_sm, held_root); return dm_tm_unlock(pmd->tm, copy); -- cgit v0.10.2 From b0dc3c8bc157c60b1d470163882be8c13e1950af Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 12 Aug 2015 15:12:09 +0100 Subject: dm btree: add ref counting ops for the leaves of top level btrees When using nested btrees, the top leaves of the top levels contain block addresses for the root of the next tree down. If we shadow a shared leaf node the leaf values (sub tree roots) should be incremented accordingly. This is only an issue if there is metadata sharing in the top levels. Which only occurs if metadata snapshots are being used (as is possible with dm-thinp). And could result in a block from the thinp metadata snap being reused early, thus corrupting the thinp metadata snap. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h index bf2b80d..8731b6e 100644 --- a/drivers/md/persistent-data/dm-btree-internal.h +++ b/drivers/md/persistent-data/dm-btree-internal.h @@ -138,4 +138,10 @@ int lower_bound(struct btree_node *n, uint64_t key); extern struct dm_block_validator btree_node_validator; +/* + * Value type for upper levels of multi-level btrees. + */ +extern void init_le64_type(struct dm_transaction_manager *tm, + struct dm_btree_value_type *vt); + #endif /* DM_BTREE_INTERNAL_H */ diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 9ca9ecc..4222f77 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -544,14 +544,6 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info, return r; } -static struct dm_btree_value_type le64_type = { - .context = NULL, - .size = sizeof(__le64), - .inc = NULL, - .dec = NULL, - .equal = NULL -}; - int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, uint64_t *keys, dm_block_t *new_root) { @@ -559,12 +551,14 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, int index = 0, r = 0; struct shadow_spine spine; struct btree_node *n; + struct dm_btree_value_type le64_vt; + init_le64_type(info->tm, &le64_vt); init_shadow_spine(&spine, info); for (level = 0; level < info->levels; level++) { r = remove_raw(&spine, info, (level == last_level ? - &info->value_type : &le64_type), + &info->value_type : &le64_vt), root, keys[level], (unsigned *)&index); if (r < 0) break; @@ -654,11 +648,13 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root, int index = 0, r = 0; struct shadow_spine spine; struct btree_node *n; + struct dm_btree_value_type le64_vt; uint64_t k; + init_le64_type(info->tm, &le64_vt); init_shadow_spine(&spine, info); for (level = 0; level < last_level; level++) { - r = remove_raw(&spine, info, &le64_type, + r = remove_raw(&spine, info, &le64_vt, root, keys[level], (unsigned *) &index); if (r < 0) goto out; diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c index 1b5e13e..0dee514 100644 --- a/drivers/md/persistent-data/dm-btree-spine.c +++ b/drivers/md/persistent-data/dm-btree-spine.c @@ -249,3 +249,40 @@ int shadow_root(struct shadow_spine *s) { return s->root; } + +static void le64_inc(void *context, const void *value_le) +{ + struct dm_transaction_manager *tm = context; + __le64 v_le; + + memcpy(&v_le, value_le, sizeof(v_le)); + dm_tm_inc(tm, le64_to_cpu(v_le)); +} + +static void le64_dec(void *context, const void *value_le) +{ + struct dm_transaction_manager *tm = context; + __le64 v_le; + + memcpy(&v_le, value_le, sizeof(v_le)); + dm_tm_dec(tm, le64_to_cpu(v_le)); +} + +static int le64_equal(void *context, const void *value1_le, const void *value2_le) +{ + __le64 v1_le, v2_le; + + memcpy(&v1_le, value1_le, sizeof(v1_le)); + memcpy(&v2_le, value2_le, sizeof(v2_le)); + return v1_le == v2_le; +} + +void init_le64_type(struct dm_transaction_manager *tm, + struct dm_btree_value_type *vt) +{ + vt->context = tm; + vt->size = sizeof(__le64); + vt->inc = le64_inc; + vt->dec = le64_dec; + vt->equal = le64_equal; +} diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index fdd3793..c7726ce 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -667,12 +667,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root, struct btree_node *n; struct dm_btree_value_type le64_type; - le64_type.context = NULL; - le64_type.size = sizeof(__le64); - le64_type.inc = NULL; - le64_type.dec = NULL; - le64_type.equal = NULL; - + init_le64_type(info->tm, &le64_type); init_shadow_spine(&spine, info); for (level = 0; level < (info->levels - 1); level++) { -- cgit v0.10.2 From 34dd051741572859bc1fef525c5ddbc127158b52 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Wed, 12 Aug 2015 19:22:43 +0800 Subject: dm cache policy smq: move 'dm-cache-default' module alias to SMQ When creating dm-cache with the default policy, it will call request_module("dm-cache-default") to register the default policy. But the "dm-cache-default" alias was left referring to the MQ policy. Fix this by moving the module alias to SMQ. Fixes: bccab6a0 (dm cache: switch the "default" cache replacement policy from mq to smq) Signed-off-by: Yi Zhang Signed-off-by: Mike Snitzer diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index 3281437..aa1b41c 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -1471,5 +1471,3 @@ module_exit(mq_exit); MODULE_AUTHOR("Joe Thornber "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("mq cache policy"); - -MODULE_ALIAS("dm-cache-default"); diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c index 48a4a82..200366c 100644 --- a/drivers/md/dm-cache-policy-smq.c +++ b/drivers/md/dm-cache-policy-smq.c @@ -1789,3 +1789,5 @@ module_exit(smq_exit); MODULE_AUTHOR("Joe Thornber "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("smq cache policy"); + +MODULE_ALIAS("dm-cache-default"); -- cgit v0.10.2 From 8c8bac59dda0c41c7dd289d443ac42b7b72d31b0 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang Date: Wed, 5 Aug 2015 14:03:48 -0400 Subject: drm/amdgpu: add context buffer size check for HEVC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Boyuan Zhang Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 2f7a5ef..f5c2255 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -374,7 +374,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) unsigned height_in_mb = ALIGN(height / 16, 2); unsigned fs_in_mb = width_in_mb * height_in_mb; - unsigned image_size, tmp, min_dpb_size, num_dpb_buffer; + unsigned image_size, tmp, min_dpb_size, num_dpb_buffer, min_ctx_size; image_size = width * height; image_size += image_size / 2; @@ -466,6 +466,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2; min_dpb_size = image_size * num_dpb_buffer; + min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16) + * 16 * num_dpb_buffer + 52 * 1024; break; default: @@ -486,6 +488,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) buf_sizes[0x1] = dpb_size; buf_sizes[0x2] = image_size; + buf_sizes[0x4] = min_ctx_size; return 0; } @@ -628,6 +631,13 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx) return -EINVAL; } + } else if (cmd == 0x206) { + if ((end - start) < ctx->buf_sizes[4]) { + DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, + (unsigned)(end - start), + ctx->buf_sizes[4]); + return -EINVAL; + } } else if ((cmd != 0x100) && (cmd != 0x204)) { DRM_ERROR("invalid UVD command %X!\n", cmd); return -EINVAL; @@ -755,9 +765,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx) struct amdgpu_uvd_cs_ctx ctx = {}; unsigned buf_sizes[] = { [0x00000000] = 2048, - [0x00000001] = 32 * 1024 * 1024, - [0x00000002] = 2048 * 1152 * 3, + [0x00000001] = 0xFFFFFFFF, + [0x00000002] = 0xFFFFFFFF, [0x00000003] = 2048, + [0x00000004] = 0xFFFFFFFF, }; struct amdgpu_ib *ib = &parser->ibs[ib_idx]; int r; -- cgit v0.10.2 From b8826b0cbf47ecfc9fdefdbf8c7bbb308e117005 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 10 Aug 2015 11:08:31 -0400 Subject: Revert "drm/amdgpu: Configure doorbell to maximum slots" This reverts commit 78ad5cdd21f0d614983fc397338944e797ec70b9. This commit breaks dpm and suspend/resume on CZ. diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index f5a42ab..20e2cfd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3135,7 +3135,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2); WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, - 0x7FFFF << 2); + AMDGPU_DOORBELL_MEC_RING7 << 2); } tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL, -- cgit v0.10.2 From e037239e5e7b61007763984aa35a8329596d8c88 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 10 Aug 2015 15:28:49 -0400 Subject: drm/radeon: add new OLAND pci id Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 45c39a3..8bc073d 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -172,6 +172,7 @@ {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -- cgit v0.10.2 From 660d0831d1494a6837b2f810d08b5be092c1f31d Mon Sep 17 00:00:00 2001 From: John Soni Jose Date: Wed, 24 Jun 2015 06:41:58 +0530 Subject: libiscsi: Fix host busy blocking during connection teardown In case of hw iscsi offload, an host can have N-number of active connections. There can be IO's running on some connections which make host->host_busy always TRUE. Now if logout from a connection is tried then the code gets into an infinite loop as host->host_busy is always TRUE. iscsi_conn_teardown(....) { ......... /* * Block until all in-progress commands for this connection * time out or fail. */ for (;;) { spin_lock_irqsave(session->host->host_lock, flags); if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */ spin_unlock_irqrestore(session->host->host_lock, flags); break; } spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " "host_busy %d host_failed %d\n", atomic_read(&session->host->host_busy), session->host->host_failed); ................ ............... } } This is not an issue with software-iscsi/iser as each cxn is a separate host. Fix: Acquiring eh_mutex in iscsi_conn_teardown() before setting session->state = ISCSI_STATE_TERMINATE. Signed-off-by: John Soni Jose Reviewed-by: Mike Christie Reviewed-by: Chris Leech Cc: stable@vger.kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8053f24..98d9bb6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2941,10 +2941,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; - unsigned long flags; del_timer_sync(&conn->transport_timer); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->frwd_lock); conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; if (session->leadconn == conn) { @@ -2956,28 +2956,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->frwd_lock); - /* - * Block until all in-progress commands for this connection - * time out or fail. - */ - for (;;) { - spin_lock_irqsave(session->host->host_lock, flags); - if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */ - spin_unlock_irqrestore(session->host->host_lock, flags); - break; - } - spin_unlock_irqrestore(session->host->host_lock, flags); - msleep_interruptible(500); - iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " - "host_busy %d host_failed %d\n", - atomic_read(&session->host->host_busy), - session->host->host_failed); - /* - * force eh_abort() to unblock - */ - wake_up(&conn->ehwait); - } - /* flush queued up work because we free the connection below */ iscsi_suspend_tx(conn); @@ -2994,6 +2972,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) if (session->leadconn == conn) session->leadconn = NULL; spin_unlock_bh(&session->frwd_lock); + mutex_unlock(&session->eh_mutex); iscsi_destroy_conn(cls_conn); } -- cgit v0.10.2 From f6979adeaab578f8ca14fdd32b06ddee0d9d3314 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jun 2015 14:20:46 -0700 Subject: libfc: Fix fc_exch_recv_req() error path Due to patch "libfc: Do not invoke the response handler after fc_exch_done()" (commit ID 7030fd62) the lport_recv() call in fc_exch_recv_req() is passed a dangling pointer. Avoid this by moving the fc_frame_free() call from fc_invoke_resp() to its callers. This patch fixes the following crash: general protection fault: 0000 [#3] PREEMPT SMP RIP: fc_lport_recv_req+0x72/0x280 [libfc] Call Trace: fc_exch_recv+0x642/0xde0 [libfc] fcoe_percpu_receive_thread+0x46a/0x5ed [fcoe] kthread+0x10a/0x120 ret_from_fork+0x42/0x70 Signed-off-by: Bart Van Assche Cc: stable Signed-off-by: Vasu Dev Signed-off-by: James Bottomley diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 1b3a094..30f9ef0 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -733,8 +733,6 @@ static bool fc_invoke_resp(struct fc_exch *ep, struct fc_seq *sp, if (resp) { resp(sp, fp, arg); res = true; - } else if (!IS_ERR(fp)) { - fc_frame_free(fp); } spin_lock_bh(&ep->ex_lock); @@ -1596,7 +1594,8 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) * If new exch resp handler is valid then call that * first. */ - fc_invoke_resp(ep, sp, fp); + if (!fc_invoke_resp(ep, sp, fp)) + fc_frame_free(fp); fc_exch_release(ep); return; @@ -1695,7 +1694,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) fc_exch_hold(ep); if (!rc) fc_exch_delete(ep); - fc_invoke_resp(ep, sp, fp); + if (!fc_invoke_resp(ep, sp, fp)) + fc_frame_free(fp); if (has_rec) fc_exch_timer_set(ep, ep->r_a_tov); fc_exch_release(ep); -- cgit v0.10.2 From 8f2777f53e3d5ad8ef2a176a4463a5c8e1a16431 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jun 2015 14:20:51 -0700 Subject: libfc: Fix fc_fcp_cleanup_each_cmd() Since fc_fcp_cleanup_cmd() can sleep this function must not be called while holding a spinlock. This patch avoids that fc_fcp_cleanup_each_cmd() triggers the following bug: BUG: scheduling while atomic: sg_reset/1512/0x00000202 1 lock held by sg_reset/1512: #0: (&(&fsp->scsi_pkt_lock)->rlock){+.-...}, at: [] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Preemption disabled at:[] fc_fcp_cleanup_each_cmd.isra.21+0xa5/0x150 [libfc] Call Trace: [] dump_stack+0x4f/0x7b [] __schedule_bug+0x6c/0xd0 [] __schedule+0x71a/0xa10 [] schedule+0x32/0x80 [] fc_seq_set_resp+0xac/0x100 [libfc] [] fc_exch_done+0x41/0x60 [libfc] [] fc_fcp_cleanup_each_cmd.isra.21+0xcf/0x150 [libfc] [] fc_eh_device_reset+0x1c3/0x270 [libfc] [] scsi_try_bus_device_reset+0x29/0x60 [] scsi_ioctl_reset+0x258/0x2d0 [] scsi_ioctl+0x150/0x440 [] sd_ioctl+0xad/0x120 [] blkdev_ioctl+0x1b6/0x810 [] block_ioctl+0x38/0x40 [] do_vfs_ioctl+0x2f8/0x530 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x16/0x7a Signed-off-by: Bart Van Assche Cc: stable Signed-off-by: Vasu Dev Signed-off-by: James Bottomley diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index c679594..2d5909c 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1039,11 +1039,26 @@ restart: fc_fcp_pkt_hold(fsp); spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - if (!fc_fcp_lock_pkt(fsp)) { + spin_lock_bh(&fsp->scsi_pkt_lock); + if (!(fsp->state & FC_SRB_COMPL)) { + fsp->state |= FC_SRB_COMPL; + /* + * TODO: dropping scsi_pkt_lock and then reacquiring + * again around fc_fcp_cleanup_cmd() is required, + * since fc_fcp_cleanup_cmd() calls into + * fc_seq_set_resp() and that func preempts cpu using + * schedule. May be schedule and related code should be + * removed instead of unlocking here to avoid scheduling + * while atomic bug. + */ + spin_unlock_bh(&fsp->scsi_pkt_lock); + fc_fcp_cleanup_cmd(fsp, error); + + spin_lock_bh(&fsp->scsi_pkt_lock); fc_io_compl(fsp); - fc_fcp_unlock_pkt(fsp); } + spin_unlock_bh(&fsp->scsi_pkt_lock); fc_fcp_pkt_release(fsp); spin_lock_irqsave(&si->scsi_queue_lock, flags); -- cgit v0.10.2 From 4f258a46346c03fa0bbb6199ffaf4e1f9f599660 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 23 Jun 2015 12:13:59 -0400 Subject: sd: Fix maximum I/O size for BLOCK_PC requests Commit bcdb247c6b6a ("sd: Limit transfer length") clamped the maximum size of an I/O request to the MAXIMUM TRANSFER LENGTH field in the BLOCK LIMITS VPD. This had the unfortunate effect of also limiting the maximum size of non-filesystem requests sent to the device through sg/bsg. Avoid using blk_queue_max_hw_sectors() and set the max_sectors queue limit directly. Also update the comment in blk_limits_max_hw_sectors() to clarify that max_hw_sectors defines the limit for the I/O controller only. Signed-off-by: Martin K. Petersen Reported-by: Brian King Tested-by: Brian King Cc: stable@vger.kernel.org # 3.17+ Signed-off-by: James Bottomley diff --git a/block/blk-settings.c b/block/blk-settings.c index 12600bf..e0057d0 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -241,8 +241,8 @@ EXPORT_SYMBOL(blk_queue_bounce_limit); * Description: * Enables a low level driver to set a hard upper limit, * max_hw_sectors, on the size of requests. max_hw_sectors is set by - * the device driver based upon the combined capabilities of I/O - * controller and storage device. + * the device driver based upon the capabilities of the I/O + * controller. * * max_sectors is a soft limit imposed by the block layer for * filesystem type requests. This value can be overridden on a diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3b2fcb4..a20da8c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2770,9 +2770,9 @@ static int sd_revalidate_disk(struct gendisk *disk) max_xfer = sdkp->max_xfer_blocks; max_xfer <<= ilog2(sdp->sector_size) - 9; - max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), - max_xfer); - blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer); + sdkp->disk->queue->limits.max_sectors = + min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer); + set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); kfree(buffer); -- cgit v0.10.2 From 211c504a444710b1d8ce3431ac19f2578602ca27 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 8 Aug 2015 12:58:57 -0700 Subject: net: dsa: Do not override PHY interface if already configured In case we need to divert reads/writes using the slave MII bus, we may have already fetched a valid PHY interface property from Device Tree, and that mode is used by the PHY driver to make configuration decisions. If we could not fetch the "phy-mode" property, we will assign p->phy_interface to PHY_INTERFACE_MODE_NA, such that we can actually check for that condition as to whether or not we should override the interface value. Fixes: 19334920eaf7 ("net: dsa: Set valid phy interface type") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0917123..35c47dd 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -756,7 +756,8 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p, return -ENODEV; /* Use already configured phy mode */ - p->phy_interface = p->phy->interface; + if (p->phy_interface == PHY_INTERFACE_MODE_NA) + p->phy_interface = p->phy->interface; phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link, p->phy_interface); -- cgit v0.10.2 From b02e3e948de6c11fded1821d89012e24d953da12 Mon Sep 17 00:00:00 2001 From: Venkat Venkatsubra Date: Tue, 11 Aug 2015 07:57:23 -0700 Subject: bonding: Gratuitous ARP gets dropped when first slave added When the first slave is added (such as during bootup) the first gratuitous ARP gets dropped. We don't see this drop during a failover. The packet gets dropped in qdisc (noop_enqueue). The fix is to delay the sending of gratuitous ARPs till the bond dev's carrier is present. It can also be worked around by setting num_grat_arp to more than 1. Signed-off-by: Venkat Venkatsubra Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e1ccefc..a98dd4f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -786,6 +786,7 @@ static bool bond_should_notify_peers(struct bonding *bond) slave ? slave->dev->name : "NULL"); if (!slave || !bond->send_peer_notif || + !netif_carrier_ok(bond->dev) || test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) return false; -- cgit v0.10.2 From a898fe040f62a32b90e26dc1f1b5973608054b29 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 12 Aug 2015 02:41:55 +0200 Subject: gianfar: correct filer table writing MAX_FILER_IDX is the last usable index. Using less-than will already guarantee that one entry for catch-all rule will be left, no need to subtract 1 here. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 3c0a8f8..4a710f3 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -1583,11 +1583,10 @@ static int gfar_write_filer_table(struct gfar_private *priv, return -EBUSY; /* Fill regular entries */ - for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop); - i++) + for (; i < MAX_FILER_IDX && (tab->fe[i].ctrl | tab->fe[i].prop); i++) gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop); /* Fill the rest with fall-troughs */ - for (; i < MAX_FILER_IDX - 1; i++) + for (; i < MAX_FILER_IDX; i++) gfar_write_filer(priv, i, 0x60, 0xFFFFFFFF); /* Last entry must be default accept * because that's what people expect -- cgit v0.10.2 From b5c8c8906e425f71efb83291c3837e4b78b769ea Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 12 Aug 2015 02:41:56 +0200 Subject: gianfar: correct list membership accounting At a cost of one line let's make sure .count is correct when calling gfar_process_filer_changes(). Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 4a710f3..f477b67 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -1721,13 +1721,14 @@ static int gfar_add_cls(struct gfar_private *priv, } process: + priv->rx_list.count++; ret = gfar_process_filer_changes(priv); if (ret) goto clean_list; - priv->rx_list.count++; return ret; clean_list: + priv->rx_list.count--; list_del(&temp->list); clean_mem: kfree(temp); -- cgit v0.10.2 From 1f2b72933422dfdaa80b59dc3a4c37eef25c4297 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 12 Aug 2015 02:41:57 +0200 Subject: gianfar: remove faulty filer optimizer Current filer rule optimization is broken in several ways: (1) Can perform reads/writes beyond end of allocated tables. (gianfar_ethtool.c:1326). (2) It breaks badly for rules with more than 2 specifiers (e.g. matching ip, port, tos). Example: # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.1 dst-port 1 tos 1 action 1 Added rule with ID 254 # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.2 dst-port 2 tos 2 action 9 Added rule with ID 253 # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.3 dst-port 3 tos 3 action 17 Added rule with ID 252 # ./filer_decode /sys/kernel/debug/gfar1/filer_raw 00: MASK == 00000210 AND Q:00 ctrl:00000080 prop:00000210 01: FPR == 00000210 AND CLE Q:00 ctrl:00000281 prop:00000210 02: MASK == ffffffff AND Q:00 ctrl:00000080 prop:ffffffff 03: DPT == 00000003 AND Q:00 ctrl:0000008e prop:00000003 04: TOS == 00000003 AND Q:00 ctrl:0000008a prop:00000003 05: DIA == 0a000003 AND Q:11 ctrl:0000448c prop:0a000003 06: DPT == 00000002 AND Q:00 ctrl:0000008e prop:00000002 07: TOS == 00000002 AND Q:00 ctrl:0000008a prop:00000002 08: DIA == 0a000002 AND Q:09 ctrl:0000248c prop:0a000002 09: DIA == 0a000001 AND Q:00 ctrl:0000008c prop:0a000001 0a: DPT == 00000001 AND Q:00 ctrl:0000008e prop:00000001 0b: TOS == 00000001 CLE Q:01 ctrl:0000060a prop:00000001 ff: MASK >= 00000000 Q:00 ctrl:00000020 prop:00000000 (Entire cluster gets AND-ed together). (3) We observed that the masking rules it generates do not play well with clustering on P2020. Only first rule of the cluster would ever fire. Given that optimizer relies heavily on masking this is very hard to fix. Example: # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.1 dst-port 1 action 1 Added rule with ID 254 # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.2 dst-port 2 action 9 Added rule with ID 253 # ethtool -N eth2 flow-type udp4 dst-ip 10.0.0.3 dst-port 3 action 17 Added rule with ID 252 # ./filer_decode /sys/kernel/debug/gfar1/filer_raw 00: MASK == 00000210 AND Q:00 ctrl:00000080 prop:00000210 01: FPR == 00000210 AND CLE Q:00 ctrl:00000281 prop:00000210 02: MASK == ffffffff AND Q:00 ctrl:00000080 prop:ffffffff 03: DPT == 00000003 AND Q:00 ctrl:0000008e prop:00000003 04: DIA == 0a000003 Q:11 ctrl:0000440c prop:0a000003 05: DPT == 00000002 AND Q:00 ctrl:0000008e prop:00000002 06: DIA == 0a000002 Q:09 ctrl:0000240c prop:0a000002 07: DIA == 0a000001 AND Q:00 ctrl:0000008c prop:0a000001 08: DPT == 00000001 CLE Q:01 ctrl:0000060e prop:00000001 ff: MASK >= 00000000 Q:00 ctrl:00000020 prop:00000000 Which looks correct according to the spec but only the first (eth id 252)/last added rule for 10.0.0.3 will ever trigger. As if filer did not treat the AND CLE as cluster start but also kept AND-ing the rules. We found no errata covering this. The fact that nobody noticed (2) or (3) makes me think that this feature is not very widely used and we should just remove it. Reported-by: Aleksander Dutkowski Signed-off-by: Jakub Kicinski Acked-by: Claudiu Manoil Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index f477b67..5b90fcf 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -900,27 +900,6 @@ static int gfar_check_filer_hardware(struct gfar_private *priv) return 0; } -static int gfar_comp_asc(const void *a, const void *b) -{ - return memcmp(a, b, 4); -} - -static int gfar_comp_desc(const void *a, const void *b) -{ - return -memcmp(a, b, 4); -} - -static void gfar_swap(void *a, void *b, int size) -{ - u32 *_a = a; - u32 *_b = b; - - swap(_a[0], _b[0]); - swap(_a[1], _b[1]); - swap(_a[2], _b[2]); - swap(_a[3], _b[3]); -} - /* Write a mask to filer cache */ static void gfar_set_mask(u32 mask, struct filer_table *tab) { @@ -1270,310 +1249,6 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule, return 0; } -/* Copy size filer entries */ -static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0], - struct gfar_filer_entry src[0], s32 size) -{ - while (size > 0) { - size--; - dst[size].ctrl = src[size].ctrl; - dst[size].prop = src[size].prop; - } -} - -/* Delete the contents of the filer-table between start and end - * and collapse them - */ -static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab) -{ - int length; - - if (end > MAX_FILER_CACHE_IDX || end < begin) - return -EINVAL; - - end++; - length = end - begin; - - /* Copy */ - while (end < tab->index) { - tab->fe[begin].ctrl = tab->fe[end].ctrl; - tab->fe[begin++].prop = tab->fe[end++].prop; - - } - /* Fill up with don't cares */ - while (begin < tab->index) { - tab->fe[begin].ctrl = 0x60; - tab->fe[begin].prop = 0xFFFFFFFF; - begin++; - } - - tab->index -= length; - return 0; -} - -/* Make space on the wanted location */ -static int gfar_expand_filer_entries(u32 begin, u32 length, - struct filer_table *tab) -{ - if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX || - begin > MAX_FILER_CACHE_IDX) - return -EINVAL; - - gfar_copy_filer_entries(&(tab->fe[begin + length]), &(tab->fe[begin]), - tab->index - length + 1); - - tab->index += length; - return 0; -} - -static int gfar_get_next_cluster_start(int start, struct filer_table *tab) -{ - for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1); - start++) { - if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) == - (RQFCR_AND | RQFCR_CLE)) - return start; - } - return -1; -} - -static int gfar_get_next_cluster_end(int start, struct filer_table *tab) -{ - for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1); - start++) { - if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) == - (RQFCR_CLE)) - return start; - } - return -1; -} - -/* Uses hardwares clustering option to reduce - * the number of filer table entries - */ -static void gfar_cluster_filer(struct filer_table *tab) -{ - s32 i = -1, j, iend, jend; - - while ((i = gfar_get_next_cluster_start(++i, tab)) != -1) { - j = i; - while ((j = gfar_get_next_cluster_start(++j, tab)) != -1) { - /* The cluster entries self and the previous one - * (a mask) must be identical! - */ - if (tab->fe[i].ctrl != tab->fe[j].ctrl) - break; - if (tab->fe[i].prop != tab->fe[j].prop) - break; - if (tab->fe[i - 1].ctrl != tab->fe[j - 1].ctrl) - break; - if (tab->fe[i - 1].prop != tab->fe[j - 1].prop) - break; - iend = gfar_get_next_cluster_end(i, tab); - jend = gfar_get_next_cluster_end(j, tab); - if (jend == -1 || iend == -1) - break; - - /* First we make some free space, where our cluster - * element should be. Then we copy it there and finally - * delete in from its old location. - */ - if (gfar_expand_filer_entries(iend, (jend - j), tab) == - -EINVAL) - break; - - gfar_copy_filer_entries(&(tab->fe[iend + 1]), - &(tab->fe[jend + 1]), jend - j); - - if (gfar_trim_filer_entries(jend - 1, - jend + (jend - j), - tab) == -EINVAL) - return; - - /* Mask out cluster bit */ - tab->fe[iend].ctrl &= ~(RQFCR_CLE); - } - } -} - -/* Swaps the masked bits of a1<>a2 and b1<>b2 */ -static void gfar_swap_bits(struct gfar_filer_entry *a1, - struct gfar_filer_entry *a2, - struct gfar_filer_entry *b1, - struct gfar_filer_entry *b2, u32 mask) -{ - u32 temp[4]; - temp[0] = a1->ctrl & mask; - temp[1] = a2->ctrl & mask; - temp[2] = b1->ctrl & mask; - temp[3] = b2->ctrl & mask; - - a1->ctrl &= ~mask; - a2->ctrl &= ~mask; - b1->ctrl &= ~mask; - b2->ctrl &= ~mask; - - a1->ctrl |= temp[1]; - a2->ctrl |= temp[0]; - b1->ctrl |= temp[3]; - b2->ctrl |= temp[2]; -} - -/* Generate a list consisting of masks values with their start and - * end of validity and block as indicator for parts belonging - * together (glued by ANDs) in mask_table - */ -static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table, - struct filer_table *tab) -{ - u32 i, and_index = 0, block_index = 1; - - for (i = 0; i < tab->index; i++) { - - /* LSByte of control = 0 sets a mask */ - if (!(tab->fe[i].ctrl & 0xF)) { - mask_table[and_index].mask = tab->fe[i].prop; - mask_table[and_index].start = i; - mask_table[and_index].block = block_index; - if (and_index >= 1) - mask_table[and_index - 1].end = i - 1; - and_index++; - } - /* cluster starts and ends will be separated because they should - * hold their position - */ - if (tab->fe[i].ctrl & RQFCR_CLE) - block_index++; - /* A not set AND indicates the end of a depended block */ - if (!(tab->fe[i].ctrl & RQFCR_AND)) - block_index++; - } - - mask_table[and_index - 1].end = i - 1; - - return and_index; -} - -/* Sorts the entries of mask_table by the values of the masks. - * Important: The 0xFF80 flags of the first and last entry of a - * block must hold their position (which queue, CLusterEnable, ReJEct, - * AND) - */ -static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table, - struct filer_table *temp_table, u32 and_index) -{ - /* Pointer to compare function (_asc or _desc) */ - int (*gfar_comp)(const void *, const void *); - - u32 i, size = 0, start = 0, prev = 1; - u32 old_first, old_last, new_first, new_last; - - gfar_comp = &gfar_comp_desc; - - for (i = 0; i < and_index; i++) { - if (prev != mask_table[i].block) { - old_first = mask_table[start].start + 1; - old_last = mask_table[i - 1].end; - sort(mask_table + start, size, - sizeof(struct gfar_mask_entry), - gfar_comp, &gfar_swap); - - /* Toggle order for every block. This makes the - * thing more efficient! - */ - if (gfar_comp == gfar_comp_desc) - gfar_comp = &gfar_comp_asc; - else - gfar_comp = &gfar_comp_desc; - - new_first = mask_table[start].start + 1; - new_last = mask_table[i - 1].end; - - gfar_swap_bits(&temp_table->fe[new_first], - &temp_table->fe[old_first], - &temp_table->fe[new_last], - &temp_table->fe[old_last], - RQFCR_QUEUE | RQFCR_CLE | - RQFCR_RJE | RQFCR_AND); - - start = i; - size = 0; - } - size++; - prev = mask_table[i].block; - } -} - -/* Reduces the number of masks needed in the filer table to save entries - * This is done by sorting the masks of a depended block. A depended block is - * identified by gluing ANDs or CLE. The sorting order toggles after every - * block. Of course entries in scope of a mask must change their location with - * it. - */ -static int gfar_optimize_filer_masks(struct filer_table *tab) -{ - struct filer_table *temp_table; - struct gfar_mask_entry *mask_table; - - u32 and_index = 0, previous_mask = 0, i = 0, j = 0, size = 0; - s32 ret = 0; - - /* We need a copy of the filer table because - * we want to change its order - */ - temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL); - if (temp_table == NULL) - return -ENOMEM; - - mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1, - sizeof(struct gfar_mask_entry), GFP_KERNEL); - - if (mask_table == NULL) { - ret = -ENOMEM; - goto end; - } - - and_index = gfar_generate_mask_table(mask_table, tab); - - gfar_sort_mask_table(mask_table, temp_table, and_index); - - /* Now we can copy the data from our duplicated filer table to - * the real one in the order the mask table says - */ - for (i = 0; i < and_index; i++) { - size = mask_table[i].end - mask_table[i].start + 1; - gfar_copy_filer_entries(&(tab->fe[j]), - &(temp_table->fe[mask_table[i].start]), size); - j += size; - } - - /* And finally we just have to check for duplicated masks and drop the - * second ones - */ - for (i = 0; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) { - if (tab->fe[i].ctrl == 0x80) { - previous_mask = i++; - break; - } - } - for (; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) { - if (tab->fe[i].ctrl == 0x80) { - if (tab->fe[i].prop == tab->fe[previous_mask].prop) { - /* Two identical ones found! - * So drop the second one! - */ - gfar_trim_filer_entries(i, i, tab); - } else - /* Not identical! */ - previous_mask = i; - } - } - - kfree(mask_table); -end: kfree(temp_table); - return ret; -} - /* Write the bit-pattern from software's buffer to hardware registers */ static int gfar_write_filer_table(struct gfar_private *priv, struct filer_table *tab) @@ -1620,7 +1295,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv) { struct ethtool_flow_spec_container *j; struct filer_table *tab; - s32 i = 0; s32 ret = 0; /* So index is set to zero, too! */ @@ -1645,17 +1319,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv) } } - i = tab->index; - - /* Optimizations to save entries */ - gfar_cluster_filer(tab); - gfar_optimize_filer_masks(tab); - - pr_debug("\tSummary:\n" - "\tData on hardware: %d\n" - "\tCompression rate: %d%%\n", - tab->index, 100 - (100 * tab->index) / i); - /* Write everything to hardware */ ret = gfar_write_filer_table(priv, tab); if (ret == -EBUSY) { -- cgit v0.10.2 From e6d006938c9bda7ffd22af9d3e1257fd75941fb7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Aug 2015 00:08:01 +0300 Subject: cosa: missing error code on failure in probe() If register_hdlc_device() fails, the current code returns 0 but we should return an error code instead. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7193b73..848ea6a 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -589,7 +589,8 @@ static int cosa_probe(int base, int irq, int dma) chan->netdev->base_addr = chan->cosa->datareg; chan->netdev->irq = chan->cosa->irq; chan->netdev->dma = chan->cosa->dma; - if (register_hdlc_device(chan->netdev)) { + err = register_hdlc_device(chan->netdev); + if (err) { netdev_warn(chan->netdev, "register_hdlc_device() failed\n"); free_netdev(chan->netdev); -- cgit v0.10.2 From 5c16179b550b9fd8114637a56b153c9768ea06a5 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 21 Jul 2015 11:00:53 +0200 Subject: EDAC, ppc4xx: Access mci->csrows array elements properly The commit de3910eb79ac ("edac: change the mem allocation scheme to make Documentation/kobject.txt happy") changed the memory allocation for the csrows member. But ppc4xx_edac was forgotten in the patch. Fix it. Signed-off-by: Michael Walle Cc: Cc: linux-edac Cc: Mauro Carvalho Chehab Link: http://lkml.kernel.org/r/1437469253-8611-1-git-send-email-michael@walle.cc Signed-off-by: Borislav Petkov diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 3515b38..711d8ad 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -920,7 +920,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) */ for (row = 0; row < mci->nr_csrows; row++) { - struct csrow_info *csi = &mci->csrows[row]; + struct csrow_info *csi = mci->csrows[row]; /* * Get the configuration settings for this -- cgit v0.10.2 From b310c178e6d897f82abb9da3af1cd7c02b09f592 Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Tue, 11 Aug 2015 20:19:20 +0300 Subject: crypto: caam - fix memory corruption in ahash_final_ctx When doing pointer operation for accessing the HW S/G table, a value representing number of entries (and not number of bytes) must be used. Cc: # 3.6+ Fixes: 045e36780f115 ("crypto: caam - ahash hmac support") Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index dae1e80..f9c7875 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -909,13 +909,14 @@ static int ahash_final_ctx(struct ahash_request *req) state->buflen_1; u32 *sh_desc = ctx->sh_desc_fin, *desc; dma_addr_t ptr = ctx->sh_desc_fin_dma; - int sec4_sg_bytes; + int sec4_sg_bytes, sec4_sg_src_index; int digestsize = crypto_ahash_digestsize(ahash); struct ahash_edesc *edesc; int ret = 0; int sh_len; - sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); + sec4_sg_src_index = 1 + (buflen ? 1 : 0); + sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + @@ -942,7 +943,7 @@ static int ahash_final_ctx(struct ahash_request *req) state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, buflen, last_buflen); - (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN; + (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN; edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); -- cgit v0.10.2 From e8fa4270536de2e5e8205fb2b90bb26afc471729 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 12 Aug 2015 11:43:34 +0200 Subject: drm/i915: Only dither on 6bpc panels In commit d328c9d78d64ca11e744fe227096990430a88477 Author: Daniel Vetter Date: Fri Apr 10 16:22:37 2015 +0200 drm/i915: Select starting pipe bpp irrespective or the primary plane we started to select the pipe bpp from sink capabilities and not from the primary framebuffer - that one might change (and we don't want to incur a modeset) and sprites might contain higher bpp content too. We also selected dithering on a 8 bpc screen displaying a 24bpp rgb primary, because pipe_bpp is 24 for such a typical 8 bpc sink, but since the commit mentioned above, base_bpp is always the absolute maximum supported by the hardware, e.g., 36 bpp on my Ironlake chip. Iow. the only way to not get dithering would have been to connect a deep color 12 bpc display, so pipe_bpp == 36 == base_bpp. Hence only enable dithering on 6bpc screens where we difinitely and always want it. Cc: Mario Kleiner Reported-by: Mario Kleiner Signed-off-by: Daniel Vetter Reviewed-and-tested-by: Mario Kleiner Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30e0f54..7a03fdc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11826,7 +11826,9 @@ encoder_retry: goto encoder_retry; } - pipe_config->dither = pipe_config->pipe_bpp != base_bpp; + /* Dithering seems to not pass-through bits correctly when it should, so + * only enable it on 6bpc panels. */ + pipe_config->dither = pipe_config->pipe_bpp == 6*3; DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); -- cgit v0.10.2 From f0fdc55db0c6f761f89c6e0c675af2dbd4e7aab4 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 11 Aug 2015 12:31:10 +0200 Subject: drm/i915: calculate primary visibility changes instead of calling from set_config This should be much cleaner, with the same effects. (cherry picked for v4.2 from commit fb9d6cf8c29bfcb0b3c602f7ded87f128d730382) Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper References: https://bugs.freedesktop.org/show_bug.cgi?id=90398 Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7a03fdc..faf4d18 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12893,20 +12893,11 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } -static bool primary_plane_visible(struct drm_crtc *crtc) -{ - struct intel_plane_state *plane_state = - to_intel_plane_state(crtc->primary->state); - - return plane_state->visible; -} - static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; struct intel_crtc_state *pipe_config; - bool primary_plane_was_visible; int ret; BUG_ON(!set); @@ -12945,38 +12936,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_update_pipe_size(to_intel_crtc(set->crtc)); - primary_plane_was_visible = primary_plane_visible(set->crtc); - ret = intel_set_mode_with_config(set->crtc, pipe_config, true); - if (ret == 0 && - pipe_config->base.enable && - pipe_config->base.planes_changed && - !needs_modeset(&pipe_config->base)) { - struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - - /* - * We need to make sure the primary plane is re-enabled if it - * has previously been turned off. - */ - if (ret == 0 && !primary_plane_was_visible && - primary_plane_visible(set->crtc)) { - WARN_ON(!intel_crtc->active); - intel_post_enable_primary(set->crtc); - } - - /* - * In the fastboot case this may be our only check of the - * state after boot. It would be better to only do it on - * the first update, but we don't have a nice way of doing that - * (and really, set_config isn't used much for high freq page - * flipping, so increasing its cost here shouldn't be a big - * deal). - */ - if (i915.fastboot && ret == 0) - intel_modeset_check_state(set->crtc->dev); - } - if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); @@ -13307,6 +13268,9 @@ intel_check_primary_plane(struct drm_plane *plane, */ if (IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; + + if (crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.post_enable_primary = true; } /* @@ -13319,6 +13283,10 @@ intel_check_primary_plane(struct drm_plane *plane, if (!state->visible || !fb) intel_crtc->atomic.disable_ips = true; + if (!state->visible && old_state->visible && + crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.pre_disable_primary = true; + intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); -- cgit v0.10.2 From d2944cf21305c754fa8b2d6c1eea05ad5dad7944 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 11 Aug 2015 12:31:11 +0200 Subject: drm/i915: Commit planes on each crtc separately. This patch is based on the upstream commit 5ac1c4bcf073ad and amended for v4.2 to make sure it works as intended. Repeated calls to begin_crtc_commit can cause warnings like this: [ 169.127746] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:616 [ 169.127835] in_atomic(): 0, irqs_disabled(): 1, pid: 1947, name: kms_flip [ 169.127840] 3 locks held by kms_flip/1947: [ 169.127843] #0: (&dev->mode_config.mutex){+.+.+.}, at: [] __drm_modeset_lock_all+0x9c/0x130 [ 169.127860] #1: (crtc_ww_class_acquire){+.+.+.}, at: [] __drm_modeset_lock_all+0xad/0x130 [ 169.127870] #2: (crtc_ww_class_mutex){+.+.+.}, at: [] drm_modeset_lock+0x38/0x110 [ 169.127879] irq event stamp: 665690 [ 169.127882] hardirqs last enabled at (665689): [] _raw_spin_unlock_irqrestore+0x55/0x70 [ 169.127889] hardirqs last disabled at (665690): [] intel_pipe_update_start+0x113/0x5c0 [i915] [ 169.127936] softirqs last enabled at (665470): [] __do_softirq+0x236/0x650 [ 169.127942] softirqs last disabled at (665465): [] irq_exit+0xc5/0xd0 [ 169.127951] CPU: 1 PID: 1947 Comm: kms_flip Not tainted 4.1.0-rc4-patser+ #4039 [ 169.127954] Hardware name: LENOVO 2349AV8/2349AV8, BIOS G1ETA5WW (2.65 ) 04/15/2014 [ 169.127957] ffff8800c49036f0 ffff8800cde5fa28 ffffffff817f6907 0000000080000001 [ 169.127964] 0000000000000000 ffff8800cde5fa58 ffffffff810aebed 0000000000000046 [ 169.127970] ffffffff81c5d518 0000000000000268 0000000000000000 ffff8800cde5fa88 [ 169.127981] Call Trace: [ 169.127992] [] dump_stack+0x4f/0x7b [ 169.128001] [] ___might_sleep+0x16d/0x270 [ 169.128008] [] __might_sleep+0x48/0x90 [ 169.128017] [] mutex_lock_nested+0x29/0x410 [ 169.128073] [] ? vgpu_write64+0x220/0x220 [i915] [ 169.128138] [] ? ironlake_update_primary_plane+0x2ff/0x410 [i915] [ 169.128198] [] intel_frontbuffer_flush+0x25/0x70 [i915] [ 169.128253] [] intel_finish_crtc_commit+0x4c/0x180 [i915] [ 169.128279] [] drm_atomic_helper_commit_planes+0x12c/0x240 [drm_kms_helper] [ 169.128338] [] __intel_set_mode+0x684/0x830 [i915] [ 169.128378] [] intel_crtc_set_config+0x49a/0x620 [i915] [ 169.128385] [] ? mutex_unlock+0x9/0x10 [ 169.128391] [] drm_mode_set_config_internal+0x69/0x120 [ 169.128398] [] ? might_fault+0x57/0xb0 [ 169.128403] [] drm_mode_setcrtc+0x253/0x620 [ 169.128409] [] drm_ioctl+0x1a0/0x6a0 [ 169.128415] [] ? get_parent_ip+0x11/0x50 [ 169.128424] [] do_vfs_ioctl+0x2f8/0x530 [ 169.128429] [] ? trace_hardirqs_on+0xd/0x10 [ 169.128435] [] ? selinux_file_ioctl+0x56/0x100 [ 169.128439] [] SyS_ioctl+0x81/0xa0 [ 169.128445] [] system_call_fastpath+0x12/0x6f Solve it by using the newly introduced drm_atomic_helper_commit_planes_on_crtc. The problem here was that the drm_atomic_helper_commit_planes() helper we were using was basically designed to do begin_crtc_commit(crtc #1) begin_crtc_commit(crtc #2) ... commit all planes finish_crtc_commit(crtc #1) finish_crtc_commit(crtc #2) The problem here is that since our hardware relies on vblank evasion, our CRTC 'begin' function waits until we're out of the danger zone in which register writes might wind up straddling the vblank, then disables interrupts; our 'finish' function re-enables interrupts after the registers have been written. The expectation is that the operations between 'begin' and 'end' must be performed without sleeping (since interrupts are disabled) and should happen as quickly as possible. By clumping all of the 'begin' calls together, we introducing a couple problems: * Subsequent 'begin' invocations might sleep (which is illegal) * The first 'begin' ensured that we were far enough from the vblank that we could write our registers safely and ensure they all fell within the same frame. Adding extra delay waiting for subsequent CRTC's wasn't accounted for and could put us back into the 'danger zone' for CRTC #1. This commit solves the problem by using a new helper that allows an order of operations like: for each crtc { begin_crtc_commit(crtc) // sleep (maybe), then disable interrupts commit planes for this specific CRTC end_crtc_commit(crtc) // reenable interrupts } so that sleeps will only be performed while interrupts are enabled and we can be sure that registers for a CRTC will be written immediately once we know we're in the safe zone. The crtc->config->base.crtc update may seem unrelated, but the helper will use it to obtain the crtc for the state. Without the update it will dereference NULL and crash. Changes since v1: - Use Matt Roper's commit message. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper References: https://bugs.freedesktop.org/show_bug.cgi?id=90398 Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 7ed8033..8e35e0d 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -129,8 +129,9 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { - int ret; - int i; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int ret, i; if (async) { DRM_DEBUG_KMS("i915 does not yet support async commit\n"); @@ -142,48 +143,18 @@ int intel_atomic_commit(struct drm_device *dev, return ret; /* Point of no return */ - - /* - * FIXME: The proper sequence here will eventually be: - * - * drm_atomic_helper_swap_state(dev, state) - * drm_atomic_helper_commit_modeset_disables(dev, state); - * drm_atomic_helper_commit_planes(dev, state); - * drm_atomic_helper_commit_modeset_enables(dev, state); - * drm_atomic_helper_wait_for_vblanks(dev, state); - * drm_atomic_helper_cleanup_planes(dev, state); - * drm_atomic_state_free(state); - * - * once we have full atomic modeset. For now, just manually update - * plane states to avoid clobbering good states with dummy states - * while nuclear pageflipping. - */ - for (i = 0; i < dev->mode_config.num_total_plane; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane) - continue; - - plane->state->state = state; - swap(state->plane_states[i], plane->state); - plane->state->state = NULL; - } + drm_atomic_helper_swap_state(dev, state); /* swap crtc_scaler_state */ - for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - if (!crtc) { - continue; - } - - to_intel_crtc(crtc)->config->scaler_state = - to_intel_crtc_state(state->crtc_states[i])->scaler_state; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); if (INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(to_intel_crtc(crtc)); + + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } - drm_atomic_helper_commit_planes(dev, state); drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index faf4d18..87476ff 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12626,17 +12626,17 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, modeset_update_crtc_power_domains(state); - drm_atomic_helper_commit_planes(dev, state); - /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc->state) || !crtc->state->enable) + if (!needs_modeset(crtc->state) || !crtc->state->enable) { + drm_atomic_helper_commit_planes_on_crtc(crtc_state); continue; + } update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } /* FIXME: add subpixel order */ @@ -13269,7 +13269,7 @@ intel_check_primary_plane(struct drm_plane *plane, if (IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; - if (crtc_state && !needs_modeset(&crtc_state->base)) + if (crtc_state) intel_crtc->atomic.post_enable_primary = true; } @@ -15004,6 +15004,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) struct intel_plane_state *plane_state; memset(crtc->config, 0, sizeof(*crtc->config)); + crtc->config->base.crtc = &crtc->base; crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; -- cgit v0.10.2 From 30abbe7727b23c6661daeea5d36be36ed7a41665 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 11 Aug 2015 21:37:59 +0200 Subject: ASoC: dapm: dapm_dai_get_connected_widgets: Fix missing mutex unlock Make sure to unlock the DAPM mutex when dapm_widget_list_create() fails. This means the function will now generate a trace_snd_soc_dapm_connected event, even if the creation of the list fails. But that was the behavior before the patch that introduced the unlock issue, so that should be fine. Fixes: 1ce43acff0c0 ("ASoC: dapm: Simplify list creation in dapm_dai_get_connected_widgets()") Reported-by: Dan Carpenter Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ac506cf..fa09108 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1191,7 +1191,7 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, ret = dapm_widget_list_create(list, &widgets); if (ret) - return ret; + paths = ret; trace_snd_soc_dapm_connected(paths, stream); mutex_unlock(&card->dapm_mutex); -- cgit v0.10.2 From a3423b02cf745c1418f1f199646c450d6fc9ca4e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 11 Aug 2015 21:38:00 +0200 Subject: ASoC: dapm: Consolidate input and output path handling After the recent cleanups and generalizations of the DAPM algorithm the handling of input and output paths is now fully symmetric. This means by making some slight changes to the data structure and using arrays with one entry for each direction, rather than separate fields, it is possible to create a generic implementation that is capable of handling both input and output paths. Unfortunately this generalization significantly increases the code size on the hot path of is_connected_{input,output}_ep() and dapm_widget_invalidate_{input,output}_paths(), which has a negative impact on the overall performance. The inner loops of those functions are quite small and the generic implementation adds extra pointer arithmetic in a few places. Testing on ARM shows that the combined code size of the specialized functions is about 50% larger than the generalized function in relative numbers. But in absolute numbers its less than 200 bytes, which is still quite small. On the other hand the generalized function increases the execution time of dapm_power_one_widget() by 30%. Given that this function is one of the most often called functions of the DAPM framework the trade-off of getting better performance at expense of generating slightly larger code at seems to be worth it. To avoid this still keep two versions of these functions around, one for input and one for output. But have a generic implementation of the algorithm which gets inlined by those two versions. And then let the compiler take care of optimizing it and removing he extra instructions. This still reduces the source code size as well as the makes making changes to the implementation more straight forward since the same change does no longer need to be done in two separate places. Also on the slow paths we can use a generic implementations that handle both input and output paths. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 4973083..5abba03 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -512,9 +512,18 @@ struct snd_soc_dapm_route { struct snd_soc_dapm_path { const char *name; - /* source (input) and sink (output) widgets */ - struct snd_soc_dapm_widget *source; - struct snd_soc_dapm_widget *sink; + /* + * source (input) and sink (output) widgets + * The union is for convience, since it is a lot nicer to type + * p->source, rather than p->node[SND_SOC_DAPM_DIR_IN] + */ + union { + struct { + struct snd_soc_dapm_widget *source; + struct snd_soc_dapm_widget *sink; + }; + struct snd_soc_dapm_widget *node[2]; + }; /* status */ u32 connect:1; /* source and sink widgets are connected */ @@ -525,8 +534,7 @@ struct snd_soc_dapm_path { int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); - struct list_head list_source; - struct list_head list_sink; + struct list_head list_node[2]; struct list_head list_kcontrol; struct list_head list; }; @@ -560,8 +568,7 @@ struct snd_soc_dapm_widget { unsigned char new_power:1; /* power from this run */ unsigned char power_checked:1; /* power checked this run */ unsigned char is_supply:1; /* Widget is a supply type widget */ - unsigned char is_sink:1; /* Widget is a sink type widget */ - unsigned char is_source:1; /* Widget is a source type widget */ + unsigned char is_ep:2; /* Widget is a endpoint type widget */ int subseq; /* sort within widget type */ int (*power_check)(struct snd_soc_dapm_widget *w); @@ -576,16 +583,14 @@ struct snd_soc_dapm_widget { struct snd_kcontrol **kcontrols; struct snd_soc_dobj dobj; - /* widget input and outputs */ - struct list_head sources; - struct list_head sinks; + /* widget input and output edges */ + struct list_head edges[2]; /* used during DAPM updates */ struct list_head work_list; struct list_head power_list; struct list_head dirty; - int inputs; - int outputs; + int endpoints[2]; struct clk *clk; }; @@ -673,6 +678,42 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; } +enum snd_soc_dapm_direction { + SND_SOC_DAPM_DIR_IN, + SND_SOC_DAPM_DIR_OUT +}; + +#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x) + +#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN) +#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT) + +/** + * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the + * specified direction of a widget + * @w: The widget + * @dir: Whether to iterate over the paths where the specified widget is the + * incoming or outgoing widgets + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_path(w, dir, p) \ + list_for_each_entry(p, &w->edges[dir], list_node[dir]) + +/** + * snd_soc_dapm_widget_for_each_sink_path_safe - Iterates over all paths in the + * specified direction of a widget + * @w: The widget + * @dir: Whether to iterate over the paths where the specified widget is the + * incoming or outgoing widgets + * @p: The path iterator variable + * @next_p: Temporary storage for the next path + * + * This function works like snd_soc_dapm_widget_for_each_sink_path, expect that + * it is safe to remove the current path from the list while iterating + */ +#define snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) \ + list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir]) + /** * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a * widget @@ -680,7 +721,7 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( * @p: The path iterator variable */ #define snd_soc_dapm_widget_for_each_sink_path(w, p) \ - list_for_each_entry(p, &w->sinks, list_source) + snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_IN, p) /** * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to @@ -689,6 +730,6 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( * @p: The path iterator variable */ #define snd_soc_dapm_widget_for_each_source_path(w, p) \ - list_for_each_entry(p, &w->sources, list_sink) + snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_OUT, p) #endif diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fa09108..27b7fd9 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -47,6 +47,13 @@ #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; +#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \ + SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN) + +#define snd_soc_dapm_for_each_direction(dir) \ + for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \ + (dir)++) + static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, const char *control, @@ -167,45 +174,59 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) } /* - * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input - * paths - * @w: The widget for which to invalidate the cached number of input paths - * - * The function resets the cached number of inputs for the specified widget and - * all widgets that can be reached via outgoing paths from the widget. - * - * This function must be called if the number of input paths for a widget might - * have changed. E.g. if the source state of a widget changes or a path is added - * or activated with the widget as the sink. + * Common implementation for dapm_widget_invalidate_input_paths() and + * dapm_widget_invalidate_output_paths(). The function is inlined since the + * combined size of the two specialized functions is only marginally larger then + * the size of the generic function and at the same time the fast path of the + * specialized functions is significantly smaller than the generic function. */ -static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) +static __always_inline void dapm_widget_invalidate_paths( + struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir) { - struct snd_soc_dapm_widget *sink; + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + struct snd_soc_dapm_widget *node; struct snd_soc_dapm_path *p; LIST_HEAD(list); dapm_assert_locked(w->dapm); - if (w->inputs == -1) + if (w->endpoints[dir] == -1) return; - w->inputs = -1; list_add_tail(&w->work_list, &list); + w->endpoints[dir] = -1; list_for_each_entry(w, &list, work_list) { - snd_soc_dapm_widget_for_each_sink_path(w, p) { + snd_soc_dapm_widget_for_each_path(w, dir, p) { if (p->is_supply || p->weak || !p->connect) continue; - sink = p->sink; - if (sink->inputs != -1) { - sink->inputs = -1; - list_add_tail(&sink->work_list, &list); + node = p->node[rdir]; + if (node->endpoints[dir] != -1) { + node->endpoints[dir] = -1; + list_add_tail(&node->work_list, &list); } } } } /* + * dapm_widget_invalidate_input_paths() - Invalidate the cached number of + * input paths + * @w: The widget for which to invalidate the cached number of input paths + * + * Resets the cached number of inputs for the specified widget and all widgets + * that can be reached via outcoming paths from the widget. + * + * This function must be called if the number of output paths for a widget might + * have changed. E.g. if the source state of a widget changes or a path is added + * or activated with the widget as the sink. + */ +static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) +{ + dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN); +} + +/* * dapm_widget_invalidate_output_paths() - Invalidate the cached number of * output paths * @w: The widget for which to invalidate the cached number of output paths @@ -219,29 +240,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) */ static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_widget *source; - struct snd_soc_dapm_path *p; - LIST_HEAD(list); - - dapm_assert_locked(w->dapm); - - if (w->outputs == -1) - return; - - w->outputs = -1; - list_add_tail(&w->work_list, &list); - - list_for_each_entry(w, &list, work_list) { - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->is_supply || p->weak || !p->connect) - continue; - source = p->source; - if (source->outputs != -1) { - source->outputs = -1; - list_add_tail(&source->work_list, &list); - } - } - } + dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT); } /* @@ -270,9 +269,9 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p) * endpoints is either connected or disconnected that sum won't change, * so there is no need to re-check the path. */ - if (p->source->inputs != 0) + if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0) dapm_widget_invalidate_input_paths(p->sink); - if (p->sink->outputs != 0) + if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0) dapm_widget_invalidate_output_paths(p->source); } @@ -283,11 +282,11 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card) mutex_lock(&card->dapm_mutex); list_for_each_entry(w, &card->widgets, list) { - if (w->is_sink || w->is_source) { + if (w->is_ep) { dapm_mark_dirty(w, "Rechecking endpoints"); - if (w->is_sink) + if (w->is_ep & SND_SOC_DAPM_EP_SINK) dapm_widget_invalidate_output_paths(w); - if (w->is_source) + if (w->is_ep & SND_SOC_DAPM_EP_SOURCE) dapm_widget_invalidate_input_paths(w); } } @@ -923,18 +922,18 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) static int dapm_new_mux(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *path; - struct list_head *paths; const char *type; int ret; switch (w->id) { case snd_soc_dapm_mux: - paths = &w->sources; + dir = SND_SOC_DAPM_DIR_OUT; type = "mux"; break; case snd_soc_dapm_demux: - paths = &w->sinks; + dir = SND_SOC_DAPM_DIR_IN; type = "demux"; break; default: @@ -948,7 +947,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return -EINVAL; } - if (list_empty(paths)) { + if (list_empty(&w->edges[dir])) { dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name); return -EINVAL; } @@ -957,16 +956,9 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) if (ret < 0) return ret; - if (w->id == snd_soc_dapm_mux) { - snd_soc_dapm_widget_for_each_source_path(w, path) { - if (path->name) - dapm_kcontrol_add_path(w->kcontrols[0], path); - } - } else { - snd_soc_dapm_widget_for_each_sink_path(w, path) { - if (path->name) - dapm_kcontrol_add_path(w->kcontrols[0], path); - } + snd_soc_dapm_widget_for_each_path(w, dir, path) { + if (path->name) + dapm_kcontrol_add_path(w->kcontrols[0], path); } return 0; @@ -1055,18 +1047,32 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; } +static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p) +{ + if (dir == SND_SOC_DAPM_DIR_IN) + trace_snd_soc_dapm_input_path(w, p); + else + trace_snd_soc_dapm_output_path(w, p); +} + /* - * Recursively check for a completed path to an active or physically connected - * output widget. Returns number of complete paths. + * Common implementation for is_connected_output_ep() and + * is_connected_input_ep(). The function is inlined since the combined size of + * the two specialized functions is only marginally larger then the size of the + * generic function and at the same time the fast path of the specialized + * functions is significantly smaller than the generic function. */ -static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, - struct list_head *list) +static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, + struct list_head *list, enum snd_soc_dapm_direction dir, + int (*fn)(struct snd_soc_dapm_widget *, struct list_head *)) { + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); struct snd_soc_dapm_path *path; int con = 0; - if (widget->outputs >= 0) - return widget->outputs; + if (widget->endpoints[dir] >= 0) + return widget->endpoints[dir]; DAPM_UPDATE_STAT(widget, path_checks); @@ -1074,12 +1080,12 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (list) list_add_tail(&widget->work_list, list); - if (widget->is_sink && widget->connected) { - widget->outputs = snd_soc_dapm_suspend_check(widget); - return widget->outputs; + if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { + widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget); + return widget->endpoints[dir]; } - snd_soc_dapm_widget_for_each_sink_path(widget, path) { + snd_soc_dapm_widget_for_each_path(widget, rdir, path) { DAPM_UPDATE_STAT(widget, neighbour_checks); if (path->weak || path->is_supply) @@ -1088,65 +1094,40 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (path->walking) return 1; - trace_snd_soc_dapm_output_path(widget, path); + trace_snd_soc_dapm_path(widget, dir, path); if (path->connect) { path->walking = 1; - con += is_connected_output_ep(path->sink, list); + con += fn(path->node[dir], list); path->walking = 0; } } - widget->outputs = con; + widget->endpoints[dir] = con; return con; } /* * Recursively check for a completed path to an active or physically connected + * output widget. Returns number of complete paths. + */ +static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, + struct list_head *list) +{ + return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT, + is_connected_output_ep); +} + +/* + * Recursively check for a completed path to an active or physically connected * input widget. Returns number of complete paths. */ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, struct list_head *list) { - struct snd_soc_dapm_path *path; - int con = 0; - - if (widget->inputs >= 0) - return widget->inputs; - - DAPM_UPDATE_STAT(widget, path_checks); - - /* do we need to add this widget to the list ? */ - if (list) - list_add_tail(&widget->work_list, list); - - if (widget->is_source && widget->connected) { - widget->inputs = snd_soc_dapm_suspend_check(widget); - return widget->inputs; - } - - snd_soc_dapm_widget_for_each_source_path(widget, path) { - DAPM_UPDATE_STAT(widget, neighbour_checks); - - if (path->weak || path->is_supply) - continue; - - if (path->walking) - return 1; - - trace_snd_soc_dapm_input_path(widget, path); - - if (path->connect) { - path->walking = 1; - con += is_connected_input_ep(path->source, list); - path->walking = 0; - } - } - - widget->inputs = con; - - return con; + return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN, + is_connected_input_ep); } /** @@ -1177,8 +1158,8 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, * to reset the cached number of inputs and outputs. */ list_for_each_entry(w, &card->widgets, list) { - w->inputs = -1; - w->outputs = -1; + w->endpoints[SND_SOC_DAPM_DIR_IN] = -1; + w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1; } if (stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1922,6 +1903,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, { struct snd_soc_dapm_widget *w = file->private_data; struct snd_soc_card *card = w->dapm->card; + enum snd_soc_dapm_direction dir, rdir; char *buf; int in, out; ssize_t ret; @@ -1958,25 +1940,21 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname, w->active ? "active" : "inactive"); - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connected && !p->connected(w, p->source)) - continue; + snd_soc_dapm_for_each_direction(dir) { + rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + snd_soc_dapm_widget_for_each_path(w, dir, p) { + if (p->connected && !p->connected(w, p->node[rdir])) + continue; - if (p->connect) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - " in \"%s\" \"%s\"\n", - p->name ? p->name : "static", - p->source->name); - } - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connected && !p->connected(w, p->sink)) - continue; + if (!p->connect) + continue; - if (p->connect) ret += snprintf(buf + ret, PAGE_SIZE - ret, - " out \"%s\" \"%s\"\n", + " %s \"%s\" \"%s\"\n", + (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out", p->name ? p->name : "static", - p->sink->name); + p->node[rdir]->name); + } } mutex_unlock(&card->dapm_mutex); @@ -2276,8 +2254,8 @@ struct attribute *soc_dapm_dev_attrs[] = { static void dapm_free_path(struct snd_soc_dapm_path *path) { - list_del(&path->list_sink); - list_del(&path->list_source); + list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]); + list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]); list_del(&path->list_kcontrol); list_del(&path->list); kfree(path); @@ -2286,6 +2264,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_path *p, *next_p; + enum snd_soc_dapm_direction dir; list_del(&w->list); /* @@ -2293,11 +2272,10 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) * While removing the path, remove reference to it from both * source and sink widgets so that path is removed only once. */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) - dapm_free_path(p); - - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) - dapm_free_path(p); + snd_soc_dapm_for_each_direction(dir) { + snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p) + dapm_free_path(p); + } kfree(w->kcontrols); kfree_const(w->name); @@ -2418,20 +2396,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); */ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) { + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *p; + unsigned int ep; switch (w->id) { case snd_soc_dapm_input: /* On a fully routed card a input is never a source */ if (w->dapm->card->fully_routed) - break; - w->is_source = 1; + return; + ep = SND_SOC_DAPM_EP_SOURCE; snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->source->id == snd_soc_dapm_micbias || p->source->id == snd_soc_dapm_mic || p->source->id == snd_soc_dapm_line || p->source->id == snd_soc_dapm_output) { - w->is_source = 0; + ep = 0; break; } } @@ -2439,25 +2419,30 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) case snd_soc_dapm_output: /* On a fully routed card a output is never a sink */ if (w->dapm->card->fully_routed) - break; - w->is_sink = 1; + return; + ep = SND_SOC_DAPM_EP_SINK; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->sink->id == snd_soc_dapm_spk || p->sink->id == snd_soc_dapm_hp || p->sink->id == snd_soc_dapm_line || p->sink->id == snd_soc_dapm_input) { - w->is_sink = 0; + ep = 0; break; } } break; case snd_soc_dapm_line: - w->is_sink = !list_empty(&w->sources); - w->is_source = !list_empty(&w->sinks); + ep = 0; + snd_soc_dapm_for_each_direction(dir) { + if (!list_empty(&w->edges[dir])) + ep |= SND_SOC_DAPM_DIR_TO_EP(dir); + } break; default: - break; + return; } + + w->is_ep = ep; } static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm, @@ -2510,6 +2495,8 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)) { + struct snd_soc_dapm_widget *widgets[2]; + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *path; int ret; @@ -2542,13 +2529,14 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, if (!path) return -ENOMEM; - path->source = wsource; - path->sink = wsink; + path->node[SND_SOC_DAPM_DIR_IN] = wsource; + path->node[SND_SOC_DAPM_DIR_OUT] = wsink; + widgets[SND_SOC_DAPM_DIR_IN] = wsource; + widgets[SND_SOC_DAPM_DIR_OUT] = wsink; + path->connected = connected; INIT_LIST_HEAD(&path->list); INIT_LIST_HEAD(&path->list_kcontrol); - INIT_LIST_HEAD(&path->list_source); - INIT_LIST_HEAD(&path->list_sink); if (wsource->is_supply || wsink->is_supply) path->is_supply = 1; @@ -2586,14 +2574,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, } list_add(&path->list, &dapm->card->paths); - list_add(&path->list_sink, &wsink->sources); - list_add(&path->list_source, &wsource->sinks); + snd_soc_dapm_for_each_direction(dir) + list_add(&path->list_node[dir], &widgets[dir]->edges[dir]); - dapm_update_widget_flags(wsource); - dapm_update_widget_flags(wsink); - - dapm_mark_dirty(wsource, "Route added"); - dapm_mark_dirty(wsink, "Route added"); + snd_soc_dapm_for_each_direction(dir) { + dapm_update_widget_flags(widgets[dir]); + dapm_mark_dirty(widgets[dir], "Route added"); + } if (dapm->card->instantiated && path->connect) dapm_path_invalidate(path); @@ -3275,6 +3262,7 @@ struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) { + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_widget *w; const char *prefix; int ret; @@ -3329,27 +3317,27 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, switch (w->id) { case snd_soc_dapm_mic: - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_input: if (!dapm->card->fully_routed) - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_spk: case snd_soc_dapm_hp: - w->is_sink = 1; + w->is_ep = SND_SOC_DAPM_EP_SINK; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_output: if (!dapm->card->fully_routed) - w->is_sink = 1; + w->is_ep = SND_SOC_DAPM_EP_SINK; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_vmid: case snd_soc_dapm_siggen: - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_always_on_check_power; break; case snd_soc_dapm_mux: @@ -3383,14 +3371,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, } w->dapm = dapm; - INIT_LIST_HEAD(&w->sources); - INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); INIT_LIST_HEAD(&w->dirty); list_add_tail(&w->list, &dapm->card->widgets); - w->inputs = -1; - w->outputs = -1; + snd_soc_dapm_for_each_direction(dir) { + INIT_LIST_HEAD(&w->edges[dir]); + w->endpoints[dir] = -1; + } /* machine layer set ups unconnected pins and insertions */ w->connected = 1; @@ -3444,14 +3432,17 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, int ret; if (WARN_ON(!config) || - WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks))) + WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL; /* We only support a single source and sink, pick the first */ - source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path, - list_sink); - sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, - list_source); + source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], + struct snd_soc_dapm_path, + list_node[SND_SOC_DAPM_DIR_OUT]); + sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], + struct snd_soc_dapm_path, + list_node[SND_SOC_DAPM_DIR_IN]); source = source_p->source->priv; sink = sink_p->sink->priv; @@ -3828,6 +3819,7 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, int event) { struct snd_soc_dapm_widget *w; + unsigned int ep; if (stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; @@ -3837,12 +3829,22 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, if (w) { dapm_mark_dirty(w, "stream event"); + if (w->id == snd_soc_dapm_dai_in) { + ep = SND_SOC_DAPM_EP_SOURCE; + dapm_widget_invalidate_input_paths(w); + } else { + ep = SND_SOC_DAPM_EP_SINK; + dapm_widget_invalidate_output_paths(w); + } + switch (event) { case SND_SOC_DAPM_STREAM_START: w->active = 1; + w->is_ep = ep; break; case SND_SOC_DAPM_STREAM_STOP: w->active = 0; + w->is_ep = 0; break; case SND_SOC_DAPM_STREAM_SUSPEND: case SND_SOC_DAPM_STREAM_RESUME: @@ -3850,14 +3852,6 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: break; } - - if (w->id == snd_soc_dapm_dai_in) { - w->is_source = w->active; - dapm_widget_invalidate_input_paths(w); - } else { - w->is_sink = w->active; - dapm_widget_invalidate_output_paths(w); - } } } -- cgit v0.10.2 From 6e588a0d839b51bae49852b68740a25cacc91978 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 11 Aug 2015 21:38:01 +0200 Subject: ASoC: dapm: Consolidate path trace events The snd_soc_dapm_input_path and snd_soc_dapm_output_path trace events are identical except for the direction. Instead of having two events have a single one that has a field that contains the direction. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 88cf39d..317a1ed 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -8,6 +8,7 @@ #include #define DAPM_DIRECT "(direct)" +#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-") struct snd_soc_jack; struct snd_soc_codec; @@ -152,62 +153,38 @@ TRACE_EVENT(snd_soc_dapm_walk_done, (int)__entry->path_checks, (int)__entry->neighbour_checks) ); -TRACE_EVENT(snd_soc_dapm_output_path, +TRACE_EVENT(snd_soc_dapm_path, TP_PROTO(struct snd_soc_dapm_widget *widget, + enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *path), - TP_ARGS(widget, path), + TP_ARGS(widget, dir, path), TP_STRUCT__entry( __string( wname, widget->name ) __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->sink->name ) - __field( int, path_sink ) + __string( pnname, path->node[dir]->name ) + __field( int, path_node ) __field( int, path_connect ) + __field( int, path_dir ) ), TP_fast_assign( __assign_str(wname, widget->name); __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->sink->name); + __assign_str(pnname, path->node[dir]->name); __entry->path_connect = path->connect; - __entry->path_sink = (long)path->sink; + __entry->path_node = (long)path->node[dir]; + __entry->path_dir = dir; ), - TP_printk("%c%s -> %s -> %s", - (int) __entry->path_sink && + TP_printk("%c%s %s %s %s %s", + (int) __entry->path_node && (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) -); - -TRACE_EVENT(snd_soc_dapm_input_path, - - TP_PROTO(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_path *path), - - TP_ARGS(widget, path), - - TP_STRUCT__entry( - __string( wname, widget->name ) - __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->source->name ) - __field( int, path_source ) - __field( int, path_connect ) - ), - - TP_fast_assign( - __assign_str(wname, widget->name); - __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->source->name); - __entry->path_connect = path->connect; - __entry->path_source = (long)path->source; - ), - - TP_printk("%c%s <- %s <- %s", - (int) __entry->path_source && - (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) + __get_str(wname), DAPM_ARROW(__entry->path_dir), + __get_str(pname), DAPM_ARROW(__entry->path_dir), + __get_str(pnname)) ); TRACE_EVENT(snd_soc_dapm_connected, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 27b7fd9..cf2a069 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1047,15 +1047,6 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; } -static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w, - enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p) -{ - if (dir == SND_SOC_DAPM_DIR_IN) - trace_snd_soc_dapm_input_path(w, p); - else - trace_snd_soc_dapm_output_path(w, p); -} - /* * Common implementation for is_connected_output_ep() and * is_connected_input_ep(). The function is inlined since the combined size of -- cgit v0.10.2 From 114bb13968162451f5e1d7fe793f9eb7e0083d9a Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 12 Aug 2015 13:06:12 -0700 Subject: ASoC: fsl-asoc-card: Specify codec_dai_name for DAI links The dev->name of CODEC might not be identical to its codec_dai_name, so using dev->name to probe the CODEC dai is not a correct approach. This patch specifies each supporting codec_dai_name instead of using dev->name any more. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index de43887..040362f 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -407,6 +407,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct fsl_asoc_card_priv *priv; struct i2c_client *codec_dev; struct clk *codec_clk; + const char *codec_dai_name; u32 width; int ret; @@ -459,6 +460,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* Diversify the card configurations */ if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { + codec_dai_name = "cs42888"; priv->card.set_bias_level = NULL; priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; @@ -467,9 +469,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->cpu_priv.slot_width = 32; priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { + codec_dai_name = "sgtl5000"; priv->codec_priv.mclk_id = SGTL5000_SYSCLK; priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { + codec_dai_name = "wm8962"; priv->card.set_bias_level = fsl_asoc_card_set_bias_level; priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; @@ -521,7 +525,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* Normal DAI Link */ priv->dai_link[0].cpu_of_node = cpu_np; priv->dai_link[0].codec_of_node = codec_np; - priv->dai_link[0].codec_dai_name = codec_dev->name; + priv->dai_link[0].codec_dai_name = codec_dai_name; priv->dai_link[0].platform_of_node = cpu_np; priv->dai_link[0].dai_fmt = priv->dai_fmt; priv->card.num_links = 1; @@ -530,7 +534,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) /* DPCM DAI Links only if ASRC exsits */ priv->dai_link[1].cpu_of_node = asrc_np; priv->dai_link[1].platform_of_node = asrc_np; - priv->dai_link[2].codec_dai_name = codec_dev->name; + priv->dai_link[2].codec_dai_name = codec_dai_name; priv->dai_link[2].codec_of_node = codec_np; priv->dai_link[2].cpu_of_node = cpu_np; priv->dai_link[2].dai_fmt = priv->dai_fmt; -- cgit v0.10.2 From f5eeb5fa191fd7b634cbc4883ac58f3b2184dbc5 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Tue, 28 Jul 2015 10:30:16 +0200 Subject: mac80211: fix invalid read in minstrel_sort_best_tp_rates() At the last iteration of the loop, j may equal zero and thus tp_list[j - 1] causes an invalid read. Change the logic of the loop so that j - 1 is always >= 0. Cc: stable@vger.kernel.org Signed-off-by: Adrien Schildknecht Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 247552a..3ece7d1 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -92,14 +92,15 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) static inline void minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) { - int j = MAX_THR_RATES; - struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats; + int j; + struct minstrel_rate_stats *tmp_mrs; struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; - while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) > - minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) { - j--; + for (j = MAX_THR_RATES; j > 0; --j) { tmp_mrs = &mi->r[tp_list[j - 1]].stats; + if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <= + minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma)) + break; } if (j < MAX_THR_RATES - 1) -- cgit v0.10.2 From e61eee7cf8e3f000b6514e18afc74fb8d1525f6d Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Sun, 9 Aug 2015 20:06:27 -0700 Subject: ARM: dts: keystone: fix the clock node for mdio Currently the MDIO clock is pointing to clkpa instead of clkcpgmac. MDIO is part of the ethss and the clock should be clkcpgmac. Signed-off-by: Murali Karicheri Signed-off-by: Santosh Shilimkar diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index c06542b..367b776 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -273,7 +273,7 @@ #size-cells = <0>; reg = <0x02090300 0x100>; status = "disabled"; - clocks = <&clkpa>; + clocks = <&clkcpgmac>; clock-names = "fck"; bus_freq = <2500000>; }; -- cgit v0.10.2 From 85ad3deea4525504355560649be7a41348111a60 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Sun, 9 Aug 2015 20:06:27 -0700 Subject: ARM: dts: keystone: Fix the mdio bindings by moving it to soc specific file Currently mdio bindings are defined in keystone.dtsi and this results in incorrect unit address for the node on K2E and K2L SoCs. Fix this by moving them to SoC specific DTS file. Signed-off-by: Murali Karicheri Signed-off-by: Santosh Shilimkar diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi index 50e555e..d3f2629 100644 --- a/arch/arm/boot/dts/k2e.dtsi +++ b/arch/arm/boot/dts/k2e.dtsi @@ -130,10 +130,17 @@ ; }; }; + + mdio: mdio@24200f00 { + compatible = "ti,keystone_mdio", "ti,davinci_mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x24200f00 0x100>; + status = "disabled"; + clocks = <&clkcpgmac>; + clock-names = "fck"; + bus_freq = <2500000>; + }; /include/ "k2e-netcp.dtsi" }; }; - -&mdio { - reg = <0x24200f00 0x100>; -}; diff --git a/arch/arm/boot/dts/k2hk.dtsi b/arch/arm/boot/dts/k2hk.dtsi index ae64724..d0810a5 100644 --- a/arch/arm/boot/dts/k2hk.dtsi +++ b/arch/arm/boot/dts/k2hk.dtsi @@ -98,6 +98,17 @@ #gpio-cells = <2>; gpio,syscon-dev = <&devctrl 0x25c>; }; + + mdio: mdio@02090300 { + compatible = "ti,keystone_mdio", "ti,davinci_mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x02090300 0x100>; + status = "disabled"; + clocks = <&clkcpgmac>; + clock-names = "fck"; + bus_freq = <2500000>; + }; /include/ "k2hk-netcp.dtsi" }; }; diff --git a/arch/arm/boot/dts/k2l.dtsi b/arch/arm/boot/dts/k2l.dtsi index 0e00748..49fd414 100644 --- a/arch/arm/boot/dts/k2l.dtsi +++ b/arch/arm/boot/dts/k2l.dtsi @@ -29,7 +29,6 @@ }; soc { - /include/ "k2l-clocks.dtsi" uart2: serial@02348400 { @@ -79,6 +78,17 @@ #gpio-cells = <2>; gpio,syscon-dev = <&devctrl 0x24c>; }; + + mdio: mdio@26200f00 { + compatible = "ti,keystone_mdio", "ti,davinci_mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x26200f00 0x100>; + status = "disabled"; + clocks = <&clkcpgmac>; + clock-names = "fck"; + bus_freq = <2500000>; + }; /include/ "k2l-netcp.dtsi" }; }; @@ -96,7 +106,3 @@ /* Pin muxed. Enabled and configured by Bootloader */ status = "disabled"; }; - -&mdio { - reg = <0x26200f00 0x100>; -}; diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index 367b776..d72e8d1 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -267,17 +267,6 @@ 1 0 0x21000A00 0x00000100>; }; - mdio: mdio@02090300 { - compatible = "ti,keystone_mdio", "ti,davinci_mdio"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x02090300 0x100>; - status = "disabled"; - clocks = <&clkcpgmac>; - clock-names = "fck"; - bus_freq = <2500000>; - }; - kirq0: keystone_irq@26202a0 { compatible = "ti,keystone-irq"; interrupts = ; -- cgit v0.10.2 From ed596cde9425509ec6ce88e19f03e9b13b6f518b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 13 Aug 2015 08:25:20 -0700 Subject: Revert x86 sigcontext cleanups This reverts commits 9a036b93a344 ("x86/signal/64: Remove 'fs' and 'gs' from sigcontext") and c6f2062935c8 ("x86/signal/64: Fix SS handling for signals delivered to 64-bit programs"). They were cleanups, but they break dosemu by changing the signal return behavior (and removing 'fs' and 'gs' from the sigcontext struct - while not actually changing any behavior - causes build problems). Reported-and-tested-by: Stas Sergeev Acked-by: Andy Lutomirski Cc: Ingo Molnar Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds diff --git a/arch/x86/include/asm/sigcontext.h b/arch/x86/include/asm/sigcontext.h index 6fe6b18..9dfce4e 100644 --- a/arch/x86/include/asm/sigcontext.h +++ b/arch/x86/include/asm/sigcontext.h @@ -57,9 +57,9 @@ struct sigcontext { unsigned long ip; unsigned long flags; unsigned short cs; - unsigned short __pad2; /* Was called gs, but was always zero. */ - unsigned short __pad1; /* Was called fs, but was always zero. */ - unsigned short ss; + unsigned short gs; + unsigned short fs; + unsigned short __pad0; unsigned long err; unsigned long trapno; unsigned long oldmask; diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h index 0e8a973..40836a9 100644 --- a/arch/x86/include/uapi/asm/sigcontext.h +++ b/arch/x86/include/uapi/asm/sigcontext.h @@ -177,24 +177,9 @@ struct sigcontext { __u64 rip; __u64 eflags; /* RFLAGS */ __u16 cs; - - /* - * Prior to 2.5.64 ("[PATCH] x86-64 updates for 2.5.64-bk3"), - * Linux saved and restored fs and gs in these slots. This - * was counterproductive, as fsbase and gsbase were never - * saved, so arch_prctl was presumably unreliable. - * - * If these slots are ever needed for any other purpose, there - * is some risk that very old 64-bit binaries could get - * confused. I doubt that many such binaries still work, - * though, since the same patch in 2.5.64 also removed the - * 64-bit set_thread_area syscall, so it appears that there is - * no TLS API that works in both pre- and post-2.5.64 kernels. - */ - __u16 __pad2; /* Was gs. */ - __u16 __pad1; /* Was fs. */ - - __u16 ss; + __u16 gs; + __u16 fs; + __u16 __pad0; __u64 err; __u64 trapno; __u64 oldmask; diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 206996c..71820c4 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -93,8 +93,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) COPY(r15); #endif /* CONFIG_X86_64 */ +#ifdef CONFIG_X86_32 COPY_SEG_CPL3(cs); COPY_SEG_CPL3(ss); +#else /* !CONFIG_X86_32 */ + /* Kernel saves and restores only the CS segment register on signals, + * which is the bare minimum needed to allow mixed 32/64-bit code. + * App's signal handler can save/restore other segments if needed. */ + COPY_SEG_CPL3(cs); +#endif /* CONFIG_X86_32 */ get_user_ex(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); @@ -154,9 +161,8 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, #else /* !CONFIG_X86_32 */ put_user_ex(regs->flags, &sc->flags); put_user_ex(regs->cs, &sc->cs); - put_user_ex(0, &sc->__pad2); - put_user_ex(0, &sc->__pad1); - put_user_ex(regs->ss, &sc->ss); + put_user_ex(0, &sc->gs); + put_user_ex(0, &sc->fs); #endif /* CONFIG_X86_32 */ put_user_ex(fpstate, &sc->fpstate); @@ -451,19 +457,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, regs->sp = (unsigned long)frame; - /* - * Set up the CS and SS registers to run signal handlers in - * 64-bit mode, even if the handler happens to be interrupting - * 32-bit or 16-bit code. - * - * SS is subtle. In 64-bit mode, we don't need any particular - * SS descriptor, but we do need SS to be valid. It's possible - * that the old SS is entirely bogus -- this can happen if the - * signal we're trying to deliver is #GP or #SS caused by a bad - * SS value. - */ + /* Set up the CS register to run signal handlers in 64-bit mode, + even if the handler happens to be interrupting 32-bit code. */ regs->cs = __USER_CS; - regs->ss = __USER_DS; return 0; } -- cgit v0.10.2 From cd88ec2317015f9ae94fa55149bc6f61e1a460e9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 13 Aug 2015 16:19:44 -0700 Subject: x86: fix error handling for 32-bit compat out-of-range system call numbers Commit 3f5159a9221f ("x86/asm/entry/32: Update -ENOSYS handling to match the 64-bit logic") broke the ENOSYS handling for the 32-bit compat case. The proper error return value was never loaded into %rax, except if things just happened to go through the audit paths, which ended up reloading the return value. This moves the loading or %rax into the normal system call path, just to make sure the error case triggers it. It's kind of sad, since it adds a useless instruction to reload the register to the fast path, but it's not like that single load from the stack is going to be noticeable. Reported-by: David Drysdale Tested-by: Kees Cook Acked-by: Andy Lutomirski Cc: Denys Vlasenko Cc: Ingo Molnar Signed-off-by: Linus Torvalds diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index 5a18447..a7e257d 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -140,6 +140,7 @@ sysexit_from_sys_call: */ andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) movl RIP(%rsp), %ecx /* User %eip */ + movq RAX(%rsp), %rax RESTORE_RSI_RDI xorl %edx, %edx /* Do not leak kernel information */ xorq %r8, %r8 @@ -219,7 +220,6 @@ sysexit_from_sys_call: 1: setbe %al /* 1 if error, 0 if not */ movzbl %al, %edi /* zero-extend that into %edi */ call __audit_syscall_exit - movq RAX(%rsp), %rax /* reload syscall return value */ movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF @@ -368,6 +368,7 @@ sysretl_from_sys_call: RESTORE_RSI_RDI_RDX movl RIP(%rsp), %ecx movl EFLAGS(%rsp), %r11d + movq RAX(%rsp), %rax xorq %r10, %r10 xorq %r9, %r9 xorq %r8, %r8 -- cgit v0.10.2 From 3e04e2fe6d87807d27521ad6ebb9e7919d628f25 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 11 Aug 2015 22:31:17 -0700 Subject: drm/vmwgfx: Fix execbuf locking issues This addresses two issues that cause problems with viewperf maya-03 in situation with memory pressure. The first issue causes attempts to unreserve buffers if batched reservation fails due to, for example, a signal pending. While previously the ttm_eu api was resistant against this type of error, it is no longer and the lockdep code will complain about attempting to unreserve buffers that are not reserved. The issue is resolved by avoid calling ttm_eu_backoff_reservation in the buffer reserve error path. The second issue is that the binding_mutex may be held when user-space fence objects are created and hence during memory reclaims. This may cause recursive attempts to grab the binding mutex. The issue is resolved by not holding the binding mutex across fence creation and submission. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Cc: Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 654c8da..97ad3bc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2492,7 +2492,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes, true, NULL); if (unlikely(ret != 0)) - goto out_err; + goto out_err_nores; ret = vmw_validate_buffers(dev_priv, sw_context); if (unlikely(ret != 0)) @@ -2536,6 +2536,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, vmw_resource_relocations_free(&sw_context->res_relocations); vmw_fifo_commit(dev_priv, command_size); + mutex_unlock(&dev_priv->binding_mutex); vmw_query_bo_switch_commit(dev_priv, sw_context); ret = vmw_execbuf_fence_commands(file_priv, dev_priv, @@ -2551,7 +2552,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, DRM_ERROR("Fence submission error. Syncing.\n"); vmw_resource_list_unreserve(&sw_context->resource_list, false); - mutex_unlock(&dev_priv->binding_mutex); ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes, (void *) fence); -- cgit v0.10.2 From d211d87e14d0c1b28a60cb6b512d162634ca6a99 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 12 Aug 2015 13:17:38 +0900 Subject: Revert "drm/nouveau/fifo/gk104: kick channels when deactivating them" This reverts commit 1addc1264852 This commit seems to cause crashes in gk104_fifo_intr_runlist() by returning 0xbad0da00 when register 0x2a00 is read. Since this commit was intended for GM20B which is not completely supported yet, let's revert it for the time being. Reported-by: Eric Biggers Signed-off-by: Alexandre Courbot Tested-by: Afzal Mohammed Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 52c22b0..e10f964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -166,30 +166,14 @@ gk104_fifo_context_attach(struct nvkm_object *parent, } static int -gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) -{ - struct nvkm_object *obj = (void *)chan; - struct gk104_fifo_priv *priv = (void *)obj->engine; - - nv_wr32(priv, 0x002634, chan->base.chid); - if (!nv_wait(priv, 0x002634, 0x100000, 0x000000)) { - nv_error(priv, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - return -EBUSY; - } - - return 0; -} - -static int gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { struct nvkm_bar *bar = nvkm_bar(parent); + struct gk104_fifo_priv *priv = (void *)parent->engine; struct gk104_fifo_base *base = (void *)parent->parent; struct gk104_fifo_chan *chan = (void *)parent; u32 addr; - int ret; switch (nv_engidx(object->engine)) { case NVDEV_ENGINE_SW : return 0; @@ -204,9 +188,13 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - ret = gk104_fifo_chan_kick(chan); - if (ret && suspend) - return ret; + nv_wr32(priv, 0x002634, chan->base.chid); + if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { + nv_error(priv, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); + if (suspend) + return -EBUSY; + } if (addr) { nv_wo32(base, addr + 0x00, 0x00000000); @@ -331,7 +319,6 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) gk104_fifo_runlist_update(priv, chan->engine); } - gk104_fifo_chan_kick(chan); nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } -- cgit v0.10.2 From a516993f0ac1694673412eb2d16a091eafa77d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 13 Aug 2015 05:54:07 +0200 Subject: net: fix wrong skb_get() usage / crash in IGMP/MLD parsing code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent refactoring of the IGMP and MLD parsing code into ipv6_mc_check_mld() / ip_mc_check_igmp() introduced a potential crash / BUG() invocation for bridges: I wrongly assumed that skb_get() could be used as a simple reference counter for an skb which is not the case. skb_get() bears additional semantics, a user count. This leads to a BUG() invocation in pskb_expand_head() / kernel panic if pskb_may_pull() is called on an skb with a user count greater than one - unfortunately the refactoring did just that. Fixing this by removing the skb_get() call and changing the API: The caller of ipv6_mc_check_mld() / ip_mc_check_igmp() now needs to additionally check whether the returned skb_trimmed is a clone. Fixes: 9afd85c9e455 ("net: Export IGMP/MLD message validation code") Reported-by: Brenden Blanco Signed-off-by: Linus Lüssing Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 0b39dcc..1285eaf 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1591,7 +1591,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, break; } - if (skb_trimmed) + if (skb_trimmed && skb_trimmed != skb) kfree_skb(skb_trimmed); return err; @@ -1636,7 +1636,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, break; } - if (skb_trimmed) + if (skb_trimmed && skb_trimmed != skb) kfree_skb(skb_trimmed); return err; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b6a19ca..bf9a5d9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4022,8 +4022,8 @@ EXPORT_SYMBOL(skb_checksum_setup); * Otherwise returns the provided skb. Returns NULL in error cases * (e.g. transport_len exceeds skb length or out-of-memory). * - * Caller needs to set the skb transport header and release the returned skb. - * Provided skb is consumed. + * Caller needs to set the skb transport header and free any returned skb if it + * differs from the provided skb. */ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb, unsigned int transport_len) @@ -4032,16 +4032,12 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb, unsigned int len = skb_transport_offset(skb) + transport_len; int ret; - if (skb->len < len) { - kfree_skb(skb); + if (skb->len < len) return NULL; - } else if (skb->len == len) { + else if (skb->len == len) return skb; - } skb_chk = skb_clone(skb, GFP_ATOMIC); - kfree_skb(skb); - if (!skb_chk) return NULL; @@ -4066,8 +4062,8 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb, * If the skb has data beyond the given transport length, then a * trimmed & cloned skb is checked and returned. * - * Caller needs to set the skb transport header and release the returned skb. - * Provided skb is consumed. + * Caller needs to set the skb transport header and free any returned skb if it + * differs from the provided skb. */ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, unsigned int transport_len, @@ -4079,23 +4075,26 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, skb_chk = skb_checksum_maybe_trim(skb, transport_len); if (!skb_chk) - return NULL; + goto err; - if (!pskb_may_pull(skb_chk, offset)) { - kfree_skb(skb_chk); - return NULL; - } + if (!pskb_may_pull(skb_chk, offset)) + goto err; __skb_pull(skb_chk, offset); ret = skb_chkf(skb_chk); __skb_push(skb_chk, offset); - if (ret) { - kfree_skb(skb_chk); - return NULL; - } + if (ret) + goto err; return skb_chk; + +err: + if (skb_chk && skb_chk != skb) + kfree_skb(skb_chk); + + return NULL; + } EXPORT_SYMBOL(skb_checksum_trimmed); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 651cdf6..9fdfd9d 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1435,33 +1435,35 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) struct sk_buff *skb_chk; unsigned int transport_len; unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr); - int ret; + int ret = -EINVAL; transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb); - skb_get(skb); skb_chk = skb_checksum_trimmed(skb, transport_len, ip_mc_validate_checksum); if (!skb_chk) - return -EINVAL; + goto err; - if (!pskb_may_pull(skb_chk, len)) { - kfree_skb(skb_chk); - return -EINVAL; - } + if (!pskb_may_pull(skb_chk, len)) + goto err; ret = ip_mc_check_igmp_msg(skb_chk); - if (ret) { - kfree_skb(skb_chk); - return ret; - } + if (ret) + goto err; if (skb_trimmed) *skb_trimmed = skb_chk; - else + /* free now unneeded clone */ + else if (skb_chk != skb) kfree_skb(skb_chk); - return 0; + ret = 0; + +err: + if (ret && skb_chk && skb_chk != skb) + kfree_skb(skb_chk); + + return ret; } /** @@ -1470,7 +1472,7 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional) * * Checks whether an IPv4 packet is a valid IGMP packet. If so sets - * skb network and transport headers accordingly and returns zero. + * skb transport header accordingly and returns zero. * * -EINVAL: A broken packet was detected, i.e. it violates some internet * standard @@ -1485,7 +1487,8 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) * to leave the original skb and its full frame unchanged (which might be * desirable for layer 2 frame jugglers). * - * The caller needs to release a reference count from any returned skb_trimmed. + * Caller needs to set the skb network header and free any returned skb if it + * differs from the provided skb. */ int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) { diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c index df8afe5..9405b04 100644 --- a/net/ipv6/mcast_snoop.c +++ b/net/ipv6/mcast_snoop.c @@ -143,34 +143,36 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff *skb_chk = NULL; unsigned int transport_len; unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg); - int ret; + int ret = -EINVAL; transport_len = ntohs(ipv6_hdr(skb)->payload_len); transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr); - skb_get(skb); skb_chk = skb_checksum_trimmed(skb, transport_len, ipv6_mc_validate_checksum); if (!skb_chk) - return -EINVAL; + goto err; - if (!pskb_may_pull(skb_chk, len)) { - kfree_skb(skb_chk); - return -EINVAL; - } + if (!pskb_may_pull(skb_chk, len)) + goto err; ret = ipv6_mc_check_mld_msg(skb_chk); - if (ret) { - kfree_skb(skb_chk); - return ret; - } + if (ret) + goto err; if (skb_trimmed) *skb_trimmed = skb_chk; - else + /* free now unneeded clone */ + else if (skb_chk != skb) kfree_skb(skb_chk); - return 0; + ret = 0; + +err: + if (ret && skb_chk && skb_chk != skb) + kfree_skb(skb_chk); + + return ret; } /** @@ -179,7 +181,7 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb, * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional) * * Checks whether an IPv6 packet is a valid MLD packet. If so sets - * skb network and transport headers accordingly and returns zero. + * skb transport header accordingly and returns zero. * * -EINVAL: A broken packet was detected, i.e. it violates some internet * standard @@ -194,7 +196,8 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb, * to leave the original skb and its full frame unchanged (which might be * desirable for layer 2 frame jugglers). * - * The caller needs to release a reference count from any returned skb_trimmed. + * Caller needs to set the skb network header and free any returned skb if it + * differs from the provided skb. */ int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed) { -- cgit v0.10.2 From 25b97c016b26039982daaa2c11d83979f93b71ab Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Thu, 13 Aug 2015 20:49:01 +0100 Subject: ipv4: off-by-one in continuation handling in /proc/net/route When generating /proc/net/route we emit a header followed by a line for each route. When a short read is performed we will restart this process based on the open file descriptor. When calculating the start point we fail to take into account that the 0th entry is the header. This leads us to skip the first entry when doing a continuation read. This can be easily seen with the comparison below: while read l; do echo "$l"; done A cat /proc/net/route >B diff -bu A B | grep '^[+-]' On my example machine I have approximatly 10KB of route output. There we see the very first non-title element is lost in the while read case, and an entry around the 8K mark in the cat case: +wlan0 00000000 02021EAC 0003 0 0 400 00000000 0 0 0 -tun1 00C0AC0A 00000000 0001 0 0 950 00C0FFFF 0 0 0 Fix up the off-by-one when reaquiring position on continuation. Fixes: 8be33e955cb9 ("fib_trie: Fib walk rcu should take a tnode and key instead of a trie and a leaf") BugLink: http://bugs.launchpad.net/bugs/1483440 Acked-by: Alexander Duyck Signed-off-by: Andy Whitcroft Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 37c4bb8..b0c6258 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2465,7 +2465,7 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter, key = l->key + 1; iter->pos++; - if (pos-- <= 0) + if (--pos <= 0) break; l = NULL; -- cgit v0.10.2 From 2a4eebf0c485d8e90bdd2e33e75c4b3b1e1673ac Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 13 Aug 2015 16:50:37 +0300 Subject: gianfar: Restore link state settings after MAC reset There are some MAC registers that need to be kept in sync with the link state parameters, see adjust_link(). However, after a MAC soft reset default values for these registers are assumed. In some cases (excepting if down/ if up for example) adjust_link() does not see that these values were reset to default because the priv->old* link parameters were left unchanged. So, reset the priv->old* link params as well during a MAC reset to let adjust_link() restore the MAC link settings to the actual link state values. Fixes following case, for example: Setting link to 100M, changing MTU (implies MAC reset), link state remains unchanged to 100M but MAC registers were reset to default (1G) breaking the connectivity w/ the PHY. Closing and re-opening the interface would restore the MAC link parameters to the correct values. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 2b7610f..10b3bbbb 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2102,6 +2102,11 @@ int startup_gfar(struct net_device *ndev) /* Start Rx/Tx DMA and enable the interrupts */ gfar_start(priv); + /* force link state update after mac reset */ + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + phy_start(priv->phydev); enable_napi(priv); -- cgit v0.10.2 From cf736ea6f902c26e03895dc7f5ccbc55cdc68e6e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 4 Aug 2015 09:33:40 -0700 Subject: thermal: power_allocator: do not use devm* interfaces The code in question is called outside of standard driver probe()/remove() callbacks and thus will not benefit from use of devm* infrastructure. Signed-off-by: Dmitry Torokhov Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index 63a448f..7006860 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -334,7 +334,7 @@ static int allocate_power(struct thermal_zone_device *tz, max_allocatable_power, current_temp, (s32)control_temp - (s32)current_temp); - devm_kfree(&tz->device, req_power); + kfree(req_power); unlock: mutex_unlock(&tz->lock); @@ -426,7 +426,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz) return -EINVAL; } - params = devm_kzalloc(&tz->device, sizeof(*params), GFP_KERNEL); + params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; @@ -468,14 +468,14 @@ static int power_allocator_bind(struct thermal_zone_device *tz) return 0; free: - devm_kfree(&tz->device, params); + kfree(params); return ret; } static void power_allocator_unbind(struct thermal_zone_device *tz) { dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id); - devm_kfree(&tz->device, tz->governor_data); + kfree(tz->governor_data); tz->governor_data = NULL; } -- cgit v0.10.2 From 83fccfc3940c4a2db90fd7e7079f5b465cd8c6af Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 13 Aug 2015 15:44:51 -0700 Subject: inet: fix potential deadlock in reqsk_queue_unlink() When replacing del_timer() with del_timer_sync(), I introduced a deadlock condition : reqsk_queue_unlink() is called from inet_csk_reqsk_queue_drop() inet_csk_reqsk_queue_drop() can be called from many contexts, one being the timer handler itself (reqsk_timer_handler()). In this case, del_timer_sync() loops forever. Simple fix is to test if timer is pending. Fixes: 2235f2ac75fd ("inet: fix races with reqsk timers") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 05e3145..1349571 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue, } spin_unlock(&queue->syn_wait_lock); - if (del_timer_sync(&req->rsk_timer)) + if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer)) reqsk_put(req); return found; } -- cgit v0.10.2 From 7231ed1a813e0a9d249bbbe58e66ca058aee83e1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 13 Aug 2015 18:53:37 +0200 Subject: ACPI / video: Fix circular lock dependency issue in the video-detect code Before this commit, the following would happen: a) acpi_video_get_backlight_type() gets called b) acpi_video_get_backlight_type() calls acpi_video_init_backlight_type() c) acpi_video_init_backlight_type() locks its function static init_mutex d) acpi_video_init_backlight_type() calls backlight_register_notifier() e) backlight_register_notifier() takes its notifier-chain lock And when the backlight notifier chain gets called we've: 1) blocking_notifier_call_chain() gets called 2) blocking_notifier_call_chain() takes the notifier-chain lock 3) blocking_notifier_call_chain() calls acpi_video_backlight_notify() 4) acpi_video_backlight_notify() calls acpi_video_get_backlight_type() 5) acpi_video_get_backlight_type() calls acpi_video_init_backlight_type() 6) acpi_video_init_backlight_type() locks its function static init_mutex So in the first call sequence we have: a) init_mutex gets locked b) notifier-chain gets locked and in the second call sequence we have: 1) notifier-chain gets locked 2) init_mutex gets locked And we've a circular locking dependency. This specific locking dependency is fixable without using the big hammer otherwise known as a workqueue, but further analysis shows a similar problem with the backlight notifier chain lock vs register_count_mutex from drivers/acpi/acpi_video.c, and fixing that becomes problematic. So this commit simply fixes this with the big hammer, performance wise this is a non issue as we expect the work to get scheduled exactly zero or one times during normal system use. Fixes: 93a291dfaf9c (ACPI / video: Move backlight notifier to video_detect.c) Signed-off-by: Hans de Goede Reported-and-tested-by: Sedat Dilek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 815f75e..2922f1f 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -32,6 +32,7 @@ #include #include #include +#include #include ACPI_MODULE_NAME("video"); @@ -41,6 +42,7 @@ void acpi_video_unregister_backlight(void); static bool backlight_notifier_registered; static struct notifier_block backlight_nb; +static struct work_struct backlight_notify_work; static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef; static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef; @@ -262,6 +264,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = { { }, }; +/* This uses a workqueue to avoid various locking ordering issues */ +static void acpi_video_backlight_notify_work(struct work_struct *work) +{ + if (acpi_video_get_backlight_type() != acpi_backlight_video) + acpi_video_unregister_backlight(); +} + static int acpi_video_backlight_notify(struct notifier_block *nb, unsigned long val, void *bd) { @@ -269,9 +278,8 @@ static int acpi_video_backlight_notify(struct notifier_block *nb, /* A raw bl registering may change video -> native */ if (backlight->props.type == BACKLIGHT_RAW && - val == BACKLIGHT_REGISTERED && - acpi_video_get_backlight_type() != acpi_backlight_video) - acpi_video_unregister_backlight(); + val == BACKLIGHT_REGISTERED) + schedule_work(&backlight_notify_work); return NOTIFY_OK; } @@ -304,6 +312,8 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_video, NULL, &video_caps, NULL); + INIT_WORK(&backlight_notify_work, + acpi_video_backlight_notify_work); backlight_nb.notifier_call = acpi_video_backlight_notify; backlight_nb.priority = 0; if (backlight_register_notifier(&backlight_nb) == 0) -- cgit v0.10.2 From 62c3f2fddd438d6d8d0a3cbb195637b74c3654eb Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 4 Aug 2015 16:45:16 +0900 Subject: cpufreq: exynos: Fix for memory leak in case SoC name does not match During probe free the memory allocated to "exynos_info" in case of unknown SoC type. Signed-off-by: Shailendra Verma Acked-by: Viresh Kumar Acked-by: Lukasz Majewski [k.kozlowski: Rebased the patch around if(of_machine_is_compatible)] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kukjin Kim Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index ae5b2bd..fa3dd84 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -180,7 +180,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) ret = exynos5250_cpufreq_init(exynos_info); } else { pr_err("%s: Unknown SoC type\n", __func__); - return -ENODEV; + ret = -ENODEV; } if (ret) @@ -188,12 +188,14 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) if (exynos_info->set_freq == NULL) { dev_err(&pdev->dev, "No set_freq function (ERR)\n"); + ret = -EINVAL; goto err_vdd_arm; } arm_regulator = regulator_get(NULL, "vdd_arm"); if (IS_ERR(arm_regulator)) { dev_err(&pdev->dev, "failed to get resource vdd_arm\n"); + ret = -EINVAL; goto err_vdd_arm; } @@ -225,7 +227,7 @@ err_cpufreq_reg: regulator_put(arm_regulator); err_vdd_arm: kfree(exynos_info); - return -EINVAL; + return ret; } static struct platform_driver exynos_cpufreq_platdrv = { -- cgit v0.10.2 From 9d8352864907f0ad76124c5b28f65b5a382d7d7c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Aug 2015 17:54:07 +0800 Subject: ASoC: adav80x: Remove .read_flag_mask setting from adav80x_regmap_config Don't set .read_flag_mask for adav803, it's for adav801 only. Fixes: 0c2d69645628 ("ASoC: adav80x: Split SPI and I2C code into different modules") Signed-off-by: Axel Lin Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 36d8425..69c63b9 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -865,7 +865,6 @@ const struct regmap_config adav80x_regmap_config = { .val_bits = 8, .pad_bits = 1, .reg_bits = 7, - .read_flag_mask = 0x01, .max_register = ADAV80X_PLL_OUTE, -- cgit v0.10.2 From dbe71b9d86ee77cf58a92657c43b0e48954dc62b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 12 Aug 2015 13:58:38 +0200 Subject: ASoC: ssm4567: Add sense support The ssm4567 has sensing circuitry that can be used to monitor the current and voltage on the speaker amplifier output has well as the VBAT input. This data can be output over the I2S interface so it can be processed by a DSP or similar. This patch adds the sense capture output stream to the CODEC DAI as well as DAPM widgets that ensure that the sensing circuitry is powered up when the capture stream is active. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index ac242b2..e619d56 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -174,6 +174,12 @@ static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1, &ssm4567_amplifier_boost_control), + SND_SOC_DAPM_SIGGEN("Sense"), + + SND_SOC_DAPM_PGA("Current Sense", SSM4567_REG_POWER_CTRL, 4, 1, NULL, 0), + SND_SOC_DAPM_PGA("Voltage Sense", SSM4567_REG_POWER_CTRL, 5, 1, NULL, 0), + SND_SOC_DAPM_PGA("VBAT Sense", SSM4567_REG_POWER_CTRL, 6, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("OUT"), }; @@ -181,6 +187,13 @@ static const struct snd_soc_dapm_route ssm4567_routes[] = { { "OUT", NULL, "Amplifier Boost" }, { "Amplifier Boost", "Switch", "DAC" }, { "OUT", NULL, "DAC" }, + + { "Current Sense", NULL, "Sense" }, + { "Voltage Sense", NULL, "Sense" }, + { "VBAT Sense", NULL, "Sense" }, + { "Capture Sense", NULL, "Current Sense" }, + { "Capture Sense", NULL, "Voltage Sense" }, + { "Capture Sense", NULL, "VBAT Sense" }, }; static int ssm4567_hw_params(struct snd_pcm_substream *substream, @@ -388,6 +401,14 @@ static struct snd_soc_dai_driver ssm4567_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32, }, + .capture = { + .stream_name = "Capture Sense", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32, + }, .ops = &ssm4567_dai_ops, }; -- cgit v0.10.2 From 470805eb9f31be7b0b94cb8e0cbeb5910c47ce37 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 13 Aug 2015 12:59:21 +0530 Subject: ASoC: tegra: Convert to managed resources Use managed resource functions devm_clk_put and devm_snd_soc_register_component to simplify error handling. To be compatible with the change various gotos are replaced with direct returns, and unneeded labels are dropped. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 9141477..a814da0 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -273,45 +273,40 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) GFP_KERNEL); if (!spdif) { dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } dev_set_drvdata(&pdev->dev, spdif); - spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out"); + spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out"); if (IS_ERR(spdif->clk_spdif_out)) { pr_err("Can't retrieve spdif clock\n"); ret = PTR_ERR(spdif->clk_spdif_out); - goto err; + return ret; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; + return -ENODEV; } dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; + return -ENODEV; } memregion = devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), DRV_NAME); if (!memregion) { dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; + return -EBUSY; } regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!regs) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_clk_put; + return -ENOMEM; } spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, @@ -319,7 +314,7 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) if (IS_ERR(spdif->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); ret = PTR_ERR(spdif->regmap); - goto err_clk_put; + return ret; } spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; @@ -334,8 +329,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, - &tegra20_spdif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &tegra20_spdif_component, + &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -345,21 +341,17 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_component; + return ret; } return 0; -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk_put: - clk_put(spdif->clk_spdif_out); -err: + return ret; } @@ -372,9 +364,6 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev) tegra20_spdif_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - - clk_put(spdif->clk_spdif_out); return 0; } -- cgit v0.10.2 From c17633081a0dc4c9f8c28b7a77ac5b63a1780e49 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Aug 2015 11:07:46 +0800 Subject: ASoC: cs35l32: Use case range at appropriate places Use case range syntax makes the code shorter with better readability when we have a large number of continuous switch cases. Below are the summary of readable/volatile/precious registers. The readable registers: 0x01 ~ 0x0D, 0x0F ~ 0x1C The volatile registers: 0x01 ~ 0x05, 0x15 ~ 0x18 The precious registers: 0x15 ~ 0x18 No functional change with this patch. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index f5f86b2..c84facc 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -74,33 +74,8 @@ static const struct reg_default cs35l32_reg_defaults[] = { static bool cs35l32_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS35L32_DEVID_AB: - case CS35L32_DEVID_CD: - case CS35L32_DEVID_E: - case CS35L32_FAB_ID: - case CS35L32_REV_ID: - case CS35L32_PWRCTL1: - case CS35L32_PWRCTL2: - case CS35L32_CLK_CTL: - case CS35L32_BATT_THRESHOLD: - case CS35L32_VMON: - case CS35L32_BST_CPCP_CTL: - case CS35L32_IMON_SCALING: - case CS35L32_AUDIO_LED_MNGR: - case CS35L32_ADSP_CTL: - case CS35L32_CLASSD_CTL: - case CS35L32_PROTECT_CTL: - case CS35L32_INT_MASK_1: - case CS35L32_INT_MASK_2: - case CS35L32_INT_MASK_3: - case CS35L32_INT_STATUS_1: - case CS35L32_INT_STATUS_2: - case CS35L32_INT_STATUS_3: - case CS35L32_LED_STATUS: - case CS35L32_FLASH_MODE: - case CS35L32_MOVIE_MODE: - case CS35L32_FLASH_TIMER: - case CS35L32_FLASH_INHIBIT: + case CS35L32_DEVID_AB ... CS35L32_AUDIO_LED_MNGR: + case CS35L32_ADSP_CTL ... CS35L32_FLASH_INHIBIT: return true; default: return false; @@ -110,15 +85,8 @@ static bool cs35l32_readable_register(struct device *dev, unsigned int reg) static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS35L32_DEVID_AB: - case CS35L32_DEVID_CD: - case CS35L32_DEVID_E: - case CS35L32_FAB_ID: - case CS35L32_REV_ID: - case CS35L32_INT_STATUS_1: - case CS35L32_INT_STATUS_2: - case CS35L32_INT_STATUS_3: - case CS35L32_LED_STATUS: + case CS35L32_DEVID_AB ... CS35L32_REV_ID: + case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS: return true; default: return false; @@ -128,10 +96,7 @@ static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) static bool cs35l32_precious_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS35L32_INT_STATUS_1: - case CS35L32_INT_STATUS_2: - case CS35L32_INT_STATUS_3: - case CS35L32_LED_STATUS: + case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS: return true; default: return false; -- cgit v0.10.2 From 4caae9546d2cf7dbc7a12d451f847d7b58912bda Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Aug 2015 11:08:37 +0800 Subject: ASoC: cs42l52: Use case range at appropriate place The readable registers are in continuous range: 0x01 ~ 0x34. Use case range syntax makes the code shorter with better readability when we have a large number of continuous switch cases. No functional change with this patch. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9..02d9f3d 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -110,58 +110,7 @@ static const struct reg_default cs42l52_reg_defaults[] = { static bool cs42l52_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS42L52_CHIP: - case CS42L52_PWRCTL1: - case CS42L52_PWRCTL2: - case CS42L52_PWRCTL3: - case CS42L52_CLK_CTL: - case CS42L52_IFACE_CTL1: - case CS42L52_IFACE_CTL2: - case CS42L52_ADC_PGA_A: - case CS42L52_ADC_PGA_B: - case CS42L52_ANALOG_HPF_CTL: - case CS42L52_ADC_HPF_FREQ: - case CS42L52_ADC_MISC_CTL: - case CS42L52_PB_CTL1: - case CS42L52_MISC_CTL: - case CS42L52_PB_CTL2: - case CS42L52_MICA_CTL: - case CS42L52_MICB_CTL: - case CS42L52_PGAA_CTL: - case CS42L52_PGAB_CTL: - case CS42L52_PASSTHRUA_VOL: - case CS42L52_PASSTHRUB_VOL: - case CS42L52_ADCA_VOL: - case CS42L52_ADCB_VOL: - case CS42L52_ADCA_MIXER_VOL: - case CS42L52_ADCB_MIXER_VOL: - case CS42L52_PCMA_MIXER_VOL: - case CS42L52_PCMB_MIXER_VOL: - case CS42L52_BEEP_FREQ: - case CS42L52_BEEP_VOL: - case CS42L52_BEEP_TONE_CTL: - case CS42L52_TONE_CTL: - case CS42L52_MASTERA_VOL: - case CS42L52_MASTERB_VOL: - case CS42L52_HPA_VOL: - case CS42L52_HPB_VOL: - case CS42L52_SPKA_VOL: - case CS42L52_SPKB_VOL: - case CS42L52_ADC_PCM_MIXER: - case CS42L52_LIMITER_CTL1: - case CS42L52_LIMITER_CTL2: - case CS42L52_LIMITER_AT_RATE: - case CS42L52_ALC_CTL: - case CS42L52_ALC_RATE: - case CS42L52_ALC_THRESHOLD: - case CS42L52_NOISE_GATE_CTL: - case CS42L52_CLK_STATUS: - case CS42L52_BATT_COMPEN: - case CS42L52_BATT_LEVEL: - case CS42L52_SPK_STATUS: - case CS42L52_TEM_CTL: - case CS42L52_THE_FOLDBACK: - case CS42L52_CHARGE_PUMP: + case CS42L52_CHIP ... CS42L52_CHARGE_PUMP: return true; default: return false; -- cgit v0.10.2 From 7f325bfc933d140337e55507821d6bb021321059 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Aug 2015 11:09:39 +0800 Subject: ASoC: cs42l56: Use case range at appropriate place The readable registers are in continuous range: 0x01 ~ 0x2e. Use case range syntax makes the code shorter with better readability when we have a large number of continuous switch cases. No functional change with this patch. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba4..98a68c6 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -115,52 +115,7 @@ static const struct reg_default cs42l56_reg_defaults[] = { static bool cs42l56_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS42L56_CHIP_ID_1: - case CS42L56_CHIP_ID_2: - case CS42L56_PWRCTL_1: - case CS42L56_PWRCTL_2: - case CS42L56_CLKCTL_1: - case CS42L56_CLKCTL_2: - case CS42L56_SERIAL_FMT: - case CS42L56_CLASSH_CTL: - case CS42L56_MISC_CTL: - case CS42L56_INT_STATUS: - case CS42L56_PLAYBACK_CTL: - case CS42L56_DSP_MUTE_CTL: - case CS42L56_ADCA_MIX_VOLUME: - case CS42L56_ADCB_MIX_VOLUME: - case CS42L56_PCMA_MIX_VOLUME: - case CS42L56_PCMB_MIX_VOLUME: - case CS42L56_ANAINPUT_ADV_VOLUME: - case CS42L56_DIGINPUT_ADV_VOLUME: - case CS42L56_MASTER_A_VOLUME: - case CS42L56_MASTER_B_VOLUME: - case CS42L56_BEEP_FREQ_ONTIME: - case CS42L56_BEEP_FREQ_OFFTIME: - case CS42L56_BEEP_TONE_CFG: - case CS42L56_TONE_CTL: - case CS42L56_CHAN_MIX_SWAP: - case CS42L56_AIN_REFCFG_ADC_MUX: - case CS42L56_HPF_CTL: - case CS42L56_MISC_ADC_CTL: - case CS42L56_GAIN_BIAS_CTL: - case CS42L56_PGAA_MUX_VOLUME: - case CS42L56_PGAB_MUX_VOLUME: - case CS42L56_ADCA_ATTENUATOR: - case CS42L56_ADCB_ATTENUATOR: - case CS42L56_ALC_EN_ATTACK_RATE: - case CS42L56_ALC_RELEASE_RATE: - case CS42L56_ALC_THRESHOLD: - case CS42L56_NOISE_GATE_CTL: - case CS42L56_ALC_LIM_SFT_ZC: - case CS42L56_AMUTE_HPLO_MUX: - case CS42L56_HPA_VOLUME: - case CS42L56_HPB_VOLUME: - case CS42L56_LOA_VOLUME: - case CS42L56_LOB_VOLUME: - case CS42L56_LIM_THRESHOLD_CTL: - case CS42L56_LIM_CTL_RELEASE_RATE: - case CS42L56_LIM_ATTACK_RATE: + case CS42L56_CHIP_ID_1 ... CS42L56_LIM_ATTACK_RATE: return true; default: return false; -- cgit v0.10.2 From fbf917e14eb65689ad80290170f7d615be711fb7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Aug 2015 11:10:49 +0800 Subject: ASoC: cs42l73: Use case range at appropriate place The readable registers are in continuous ranges: 0x01 ~ 0x03, 0x05 ~ 0x5f. Use case range syntax makes the code shorter with better readability when we have a large number of continuous switch cases. No functional change with this patch. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index efd924a..3de8662 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -153,100 +153,8 @@ static bool cs42l73_volatile_register(struct device *dev, unsigned int reg) static bool cs42l73_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS42L73_DEVID_AB: - case CS42L73_DEVID_CD: - case CS42L73_DEVID_E: - case CS42L73_REVID: - case CS42L73_PWRCTL1: - case CS42L73_PWRCTL2: - case CS42L73_PWRCTL3: - case CS42L73_CPFCHC: - case CS42L73_OLMBMSDC: - case CS42L73_DMMCC: - case CS42L73_XSPC: - case CS42L73_XSPMMCC: - case CS42L73_ASPC: - case CS42L73_ASPMMCC: - case CS42L73_VSPC: - case CS42L73_VSPMMCC: - case CS42L73_VXSPFS: - case CS42L73_MIOPC: - case CS42L73_ADCIPC: - case CS42L73_MICAPREPGAAVOL: - case CS42L73_MICBPREPGABVOL: - case CS42L73_IPADVOL: - case CS42L73_IPBDVOL: - case CS42L73_PBDC: - case CS42L73_HLADVOL: - case CS42L73_HLBDVOL: - case CS42L73_SPKDVOL: - case CS42L73_ESLDVOL: - case CS42L73_HPAAVOL: - case CS42L73_HPBAVOL: - case CS42L73_LOAAVOL: - case CS42L73_LOBAVOL: - case CS42L73_STRINV: - case CS42L73_XSPINV: - case CS42L73_ASPINV: - case CS42L73_VSPINV: - case CS42L73_LIMARATEHL: - case CS42L73_LIMRRATEHL: - case CS42L73_LMAXHL: - case CS42L73_LIMARATESPK: - case CS42L73_LIMRRATESPK: - case CS42L73_LMAXSPK: - case CS42L73_LIMARATEESL: - case CS42L73_LIMRRATEESL: - case CS42L73_LMAXESL: - case CS42L73_ALCARATE: - case CS42L73_ALCRRATE: - case CS42L73_ALCMINMAX: - case CS42L73_NGCAB: - case CS42L73_ALCNGMC: - case CS42L73_MIXERCTL: - case CS42L73_HLAIPAA: - case CS42L73_HLBIPBA: - case CS42L73_HLAXSPAA: - case CS42L73_HLBXSPBA: - case CS42L73_HLAASPAA: - case CS42L73_HLBASPBA: - case CS42L73_HLAVSPMA: - case CS42L73_HLBVSPMA: - case CS42L73_XSPAIPAA: - case CS42L73_XSPBIPBA: - case CS42L73_XSPAXSPAA: - case CS42L73_XSPBXSPBA: - case CS42L73_XSPAASPAA: - case CS42L73_XSPAASPBA: - case CS42L73_XSPAVSPMA: - case CS42L73_XSPBVSPMA: - case CS42L73_ASPAIPAA: - case CS42L73_ASPBIPBA: - case CS42L73_ASPAXSPAA: - case CS42L73_ASPBXSPBA: - case CS42L73_ASPAASPAA: - case CS42L73_ASPBASPBA: - case CS42L73_ASPAVSPMA: - case CS42L73_ASPBVSPMA: - case CS42L73_VSPAIPAA: - case CS42L73_VSPBIPBA: - case CS42L73_VSPAXSPAA: - case CS42L73_VSPBXSPBA: - case CS42L73_VSPAASPAA: - case CS42L73_VSPBASPBA: - case CS42L73_VSPAVSPMA: - case CS42L73_VSPBVSPMA: - case CS42L73_MMIXCTL: - case CS42L73_SPKMIPMA: - case CS42L73_SPKMXSPA: - case CS42L73_SPKMASPA: - case CS42L73_SPKMVSPMA: - case CS42L73_ESLMIPMA: - case CS42L73_ESLMXSPA: - case CS42L73_ESLMASPA: - case CS42L73_ESLMVSPMA: - case CS42L73_IM1: - case CS42L73_IM2: + case CS42L73_DEVID_AB ... CS42L73_DEVID_E: + case CS42L73_REVID ... CS42L73_IM2: return true; default: return false; -- cgit v0.10.2 From e1d46d30d133e7909e7dde06a4e867225c7e079b Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Fri, 17 Jul 2015 10:29:00 +0800 Subject: ASoC: Intel: fix runtime pm imbalance on error pm_runtime_get_sync() increments the runtime PM usage counter even the call returns an error code. Thus a pairing decrement is needed on the error handling path to keep the counter balanced. Signed-off-by: Junjie Mao Signed-off-by: Mark Brown diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 620da1d..27a9653 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -152,6 +152,7 @@ static int sst_power_control(struct device *dev, bool state) dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); if (ret < 0) { + pm_runtime_put_sync(dev); dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); return ret; } @@ -204,8 +205,10 @@ static int sst_cdev_open(struct device *dev, struct intel_sst_drv *ctx = dev_get_drvdata(dev); retval = pm_runtime_get_sync(ctx->dev); - if (retval < 0) + if (retval < 0) { + pm_runtime_put_sync(ctx->dev); return retval; + } str_id = sst_get_stream(ctx, str_params); if (str_id > 0) { @@ -672,8 +675,10 @@ static int sst_send_byte_stream(struct device *dev, if (NULL == bytes) return -EINVAL; ret_val = pm_runtime_get_sync(ctx->dev); - if (ret_val < 0) + if (ret_val < 0) { + pm_runtime_put_sync(ctx->dev); return ret_val; + } ret_val = sst_send_byte_stream_mrfld(ctx, bytes); sst_pm_runtime_put(ctx); -- cgit v0.10.2 From 8277df3c66f1a8cecfadc29f7394f623263b4445 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:21:35 +0200 Subject: ASoC: fsl_ssi: enable IPG clock during AC'97 reg access IPG clock have to be enabled during AC'97 CODEC register access in fsl_ssi driver. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c7647e0..9c46c7d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1127,10 +1127,17 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, struct regmap *regs = fsl_ac97_data->regs; unsigned int lreg; unsigned int lval; + int ret; if (reg > 0x7f) return; + ret = clk_prepare_enable(fsl_ac97_data->clk); + if (ret) { + pr_err("ac97 write clk_prepare_enable failed: %d\n", + ret); + return; + } lreg = reg << 12; regmap_write(regs, CCSR_SSI_SACADD, lreg); @@ -1141,6 +1148,8 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK, CCSR_SSI_SACNT_WR); udelay(100); + + clk_disable_unprepare(fsl_ac97_data->clk); } static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, @@ -1151,6 +1160,14 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, unsigned short val = -1; u32 reg_val; unsigned int lreg; + int ret; + + ret = clk_prepare_enable(fsl_ac97_data->clk); + if (ret) { + pr_err("ac97 read clk_prepare_enable failed: %d\n", + ret); + return -1; + } lreg = (reg & 0x7f) << 12; regmap_write(regs, CCSR_SSI_SACADD, lreg); @@ -1162,6 +1179,8 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, regmap_read(regs, CCSR_SSI_SACDAT, ®_val); val = (reg_val >> 4) & 0xffff; + clk_disable_unprepare(fsl_ac97_data->clk); + return val; } -- cgit v0.10.2 From 793e3e9eeffc3e270483a450bc08e60f38e401ff Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:22:53 +0200 Subject: ASoC: fsl_ssi: AC'97 DAI driver needs probe method too AC'97 DAI driver struct need the same probe method as I2S one to setup DMA params in fsl_ssi driver. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 9c46c7d..2ce9e1d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1101,6 +1101,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .bus_control = true, + .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "AC97 Playback", .channels_min = 2, -- cgit v0.10.2 From 06cb373692083d169ab080b31c55af91d22b6d99 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:24:10 +0200 Subject: ASoC: fsl_ssi: enable AC'97 asymmetric rates AC'97 bus can support asymmetric playback/capture rates so enable them in this case in fsl_ssi driver. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2ce9e1d..f3034b9 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1377,7 +1377,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Are the RX and the TX clocks locked? */ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { - ssi_private->cpu_dai_drv.symmetric_rates = 1; + if (!fsl_ssi_is_ac97(ssi_private)) + ssi_private->cpu_dai_drv.symmetric_rates = 1; + ssi_private->cpu_dai_drv.symmetric_channels = 1; ssi_private->cpu_dai_drv.symmetric_samplebits = 1; } -- cgit v0.10.2 From 04143d614f3af84a3f39e79a24a7ca740bd39efd Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:25:31 +0200 Subject: ASoC: fsl_ssi: add AC'97 ops setting check and cleanup Check whether setting AC'97 ops succeeded and clean them on removal so the fsl_ssi driver can be reloaded. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index f3034b9..0b4fcd9 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1340,7 +1340,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) fsl_ac97_data = ssi_private; - snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); + ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); + if (ret) { + dev_err(&pdev->dev, "could not set AC'97 ops\n"); + return ret; + } } else { /* Initialize this copy of the CPU DAI driver structure */ memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, @@ -1480,6 +1484,9 @@ static int fsl_ssi_remove(struct platform_device *pdev) if (ssi_private->soc->imx) fsl_ssi_imx_clean(pdev, ssi_private); + if (fsl_ssi_is_ac97(ssi_private)) + snd_soc_set_ac97_ops(NULL); + return 0; } -- cgit v0.10.2 From 8ed0c842153434fa3aeeb89d16b71ac7dc8e12ee Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:26:44 +0200 Subject: ASoC: fsl_ssi: instantiate AC'97 CODEC Instantiate AC'97 CODEC in fsl_ssi driver AC'97 mode. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 0b4fcd9..e79dc16 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1460,6 +1460,27 @@ done: _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, ssi_private->dai_fmt); + if (fsl_ssi_is_ac97(ssi_private)) { + u32 ssi_idx; + + ret = of_property_read_u32(np, "cell-index", &ssi_idx); + if (ret) { + dev_err(&pdev->dev, "cannot get SSI index property\n"); + goto error_sound_card; + } + + ssi_private->pdev = + platform_device_register_data(NULL, + "ac97-codec", ssi_idx, NULL, 0); + if (IS_ERR(ssi_private->pdev)) { + ret = PTR_ERR(ssi_private->pdev); + dev_err(&pdev->dev, + "failed to register AC97 codec platform: %d\n", + ret); + goto error_sound_card; + } + } + return 0; error_sound_card: -- cgit v0.10.2 From dce0332c85c4d9eb5d96182c56f63cd20566f073 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 5 Aug 2015 17:29:02 +0200 Subject: ASoC: fsl_ssi: adjust set DAI format in AC'97 mode Adjust set DAI format function in fsl_ssi driver so it doesn't fail and clears RXDIR in AC'97 mode. Signed-off-by: Maciej Szmigiero Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e79dc16..f03d57e 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -900,14 +900,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; break; default: - return -EINVAL; + if (!fsl_ssi_is_ac97(ssi_private)) + return -EINVAL; } stcr |= strcr; srcr |= strcr; - if (ssi_private->cpu_dai_drv.symmetric_rates) { - /* Need to clear RXDIR when using SYNC mode */ + if (ssi_private->cpu_dai_drv.symmetric_rates + || fsl_ssi_is_ac97(ssi_private)) { + /* Need to clear RXDIR when using SYNC or AC97 mode */ srcr &= ~CCSR_SSI_SRCR_RXDIR; scr |= CCSR_SSI_SCR_SYN; } -- cgit v0.10.2 From 1a8e7fab70c8d7cad2e606e7b21d46e42e51c2fd Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 10 Aug 2015 22:48:30 +0800 Subject: ASoC: topology: Change pass number of DAI smaller than graph The PCM DAIs need to be loaded and added to ASoC core ealier than the graph (route). Otherwise, adding routes will fail for missing DAIs. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8620dbf..942c1ac 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -44,12 +44,12 @@ #define SOC_TPLG_PASS_VENDOR 1 #define SOC_TPLG_PASS_MIXER 2 #define SOC_TPLG_PASS_WIDGET 3 -#define SOC_TPLG_PASS_GRAPH 4 -#define SOC_TPLG_PASS_PINS 5 -#define SOC_TPLG_PASS_PCM_DAI 6 +#define SOC_TPLG_PASS_PCM_DAI 4 +#define SOC_TPLG_PASS_GRAPH 5 +#define SOC_TPLG_PASS_PINS 6 #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PCM_DAI +#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PINS struct soc_tplg { const struct firmware *fw; -- cgit v0.10.2 From 4f32be677b124a49459e2603321c7a5605ceb9f8 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Fri, 14 Aug 2015 15:34:56 -0700 Subject: mm/hwpoison: fix page refcount of unknown non LRU page After trying to drain pages from pagevec/pageset, we try to get reference count of the page again, however, the reference count of the page is not reduced if the page is still not on LRU list. Fix it by adding the put_page() to drop the page reference which is from __get_any_page(). Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Cc: [3.9+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index ea5a936..81c20a7 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1538,6 +1538,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) */ ret = __get_any_page(page, pfn, 0); if (!PageLRU(page)) { + /* Drop page reference which is from __get_any_page() */ + put_page(page); pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n", pfn, page->flags); return -EIO; -- cgit v0.10.2 From 036138080a4376e5f3e5d0cca8ac99084c5cf06e Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Fri, 14 Aug 2015 15:34:59 -0700 Subject: mm/hwpoison: fix fail isolate hugetlbfs page w/ refcount held Hugetlbfs pages will get a refcount in get_any_page() or madvise_hwpoison() if soft offlining through madvise. The refcount which is held by the soft offline path should be released if we fail to isolate hugetlbfs pages. Fix it by reducing the refcount for both isolation success and failure. Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Cc: [3.9+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 81c20a7..dba52ee 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1569,13 +1569,12 @@ static int soft_offline_huge_page(struct page *page, int flags) unlock_page(hpage); ret = isolate_huge_page(hpage, &pagelist); - if (ret) { - /* - * get_any_page() and isolate_huge_page() takes a refcount each, - * so need to drop one here. - */ - put_page(hpage); - } else { + /* + * get_any_page() and isolate_huge_page() takes a refcount each, + * so need to drop one here. + */ + put_page(hpage); + if (!ret) { pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn); return -EBUSY; } -- cgit v0.10.2 From 602b8593d2b4138c10e922eeaafe306f6b51817b Mon Sep 17 00:00:00 2001 From: "Herton R. Krzesinski" Date: Fri, 14 Aug 2015 15:35:02 -0700 Subject: ipc,sem: fix use after free on IPC_RMID after a task using same semaphore set exits The current semaphore code allows a potential use after free: in exit_sem we may free the task's sem_undo_list while there is still another task looping through the same semaphore set and cleaning the sem_undo list at freeary function (the task called IPC_RMID for the same semaphore set). For example, with a test program [1] running which keeps forking a lot of processes (which then do a semop call with SEM_UNDO flag), and with the parent right after removing the semaphore set with IPC_RMID, and a kernel built with CONFIG_SLAB, CONFIG_SLAB_DEBUG and CONFIG_DEBUG_SPINLOCK, you can easily see something like the following in the kernel log: Slab corruption (Not tainted): kmalloc-64 start=ffff88003b45c1c0, len=64 000: 6b 6b 6b 6b 6b 6b 6b 6b 00 6b 6b 6b 6b 6b 6b 6b kkkkkkkk.kkkkkkk 010: ff ff ff ff 6b 6b 6b 6b ff ff ff ff ff ff ff ff ....kkkk........ Prev obj: start=ffff88003b45c180, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff c0 fb 01 37 00 88 ff ff ...........7.... Next obj: start=ffff88003b45c200, len=64 000: 00 00 00 00 ad 4e ad de ff ff ff ff 5a 5a 5a 5a .....N......ZZZZ 010: ff ff ff ff ff ff ff ff 68 29 a7 3c 00 88 ff ff ........h).<.... BUG: spinlock wrong CPU on CPU#2, test/18028 general protection fault: 0000 [#1] SMP Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 2 PID: 18028 Comm: test Not tainted 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: spin_dump+0x53/0xc0 Call Trace: spin_bug+0x30/0x40 do_raw_spin_unlock+0x71/0xa0 _raw_spin_unlock+0xe/0x10 freeary+0x82/0x2a0 ? _raw_spin_lock+0xe/0x10 semctl_down.clone.0+0xce/0x160 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 SyS_semctl+0x236/0x2c0 ? syscall_trace_leave+0xde/0x130 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 8b 80 88 03 00 00 48 8d 88 60 05 00 00 48 c7 c7 a0 2c a4 81 31 c0 65 8b 15 eb 40 f3 7e e8 08 31 68 00 4d 85 e4 44 8b 4b 08 74 5e <45> 8b 84 24 88 03 00 00 49 8d 8c 24 60 05 00 00 8b 53 04 48 89 RIP [] spin_dump+0x53/0xc0 RSP ---[ end trace 783ebb76612867a0 ]--- NMI watchdog: BUG: soft lockup - CPU#3 stuck for 22s! [test:18053] Modules linked in: 8021q mrp garp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables binfmt_misc ppdev input_leds joydev parport_pc parport floppy serio_raw virtio_balloon virtio_rng virtio_console virtio_net iosf_mbi crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcspkr qxl ttm drm_kms_helper drm snd_hda_codec_generic i2c_piix4 snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore crc32c_intel virtio_pci virtio_ring virtio pata_acpi ata_generic [last unloaded: speedstep_lib] CPU: 3 PID: 18053 Comm: test Tainted: G D 4.2.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 RIP: native_read_tsc+0x0/0x20 Call Trace: ? delay_tsc+0x40/0x70 __delay+0xf/0x20 do_raw_spin_lock+0x96/0x140 _raw_spin_lock+0xe/0x10 sem_lock_and_putref+0x11/0x70 SYSC_semtimedop+0x7bf/0x960 ? handle_mm_fault+0xbf6/0x1880 ? dequeue_task_fair+0x79/0x4a0 ? __do_page_fault+0x19a/0x430 ? kfree_debugcheck+0x16/0x40 ? __do_page_fault+0x19a/0x430 ? __audit_syscall_entry+0xa8/0x100 ? do_audit_syscall_entry+0x66/0x70 ? syscall_trace_enter_phase1+0x139/0x160 SyS_semtimedop+0xe/0x10 SyS_semop+0x10/0x20 entry_SYSCALL_64_fastpath+0x12/0x71 Code: 47 10 83 e8 01 85 c0 89 47 10 75 08 65 48 89 3d 1f 74 ff 7e c9 c3 0f 1f 44 00 00 55 48 89 e5 e8 87 17 04 00 66 90 c9 c3 0f 1f 00 <55> 48 89 e5 0f 31 89 c1 48 89 d0 48 c1 e0 20 89 c9 48 09 c8 c9 Kernel panic - not syncing: softlockup: hung tasks I wasn't able to trigger any badness on a recent kernel without the proper config debugs enabled, however I have softlockup reports on some kernel versions, in the semaphore code, which are similar as above (the scenario is seen on some servers running IBM DB2 which uses semaphore syscalls). The patch here fixes the race against freeary, by acquiring or waiting on the sem_undo_list lock as necessary (exit_sem can race with freeary, while freeary sets un->semid to -1 and removes the same sem_undo from list_proc or when it removes the last sem_undo). After the patch I'm unable to reproduce the problem using the test case [1]. [1] Test case used below: #include #include #include #include #include #include #include #include #include #define NSEM 1 #define NSET 5 int sid[NSET]; void thread() { struct sembuf op; int s; uid_t pid = getuid(); s = rand() % NSET; op.sem_num = pid % NSEM; op.sem_op = 1; op.sem_flg = SEM_UNDO; semop(sid[s], &op, 1); exit(EXIT_SUCCESS); } void create_set() { int i, j; pid_t p; union { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; } un; /* Create and initialize semaphore set */ for (i = 0; i < NSET; i++) { sid[i] = semget(IPC_PRIVATE , NSEM, 0644 | IPC_CREAT); if (sid[i] < 0) { perror("semget"); exit(EXIT_FAILURE); } } un.val = 0; for (i = 0; i < NSET; i++) { for (j = 0; j < NSEM; j++) { if (semctl(sid[i], j, SETVAL, un) < 0) perror("semctl"); } } /* Launch threads that operate on semaphore set */ for (i = 0; i < NSEM * NSET * NSET; i++) { p = fork(); if (p < 0) perror("fork"); if (p == 0) thread(); } /* Free semaphore set */ for (i = 0; i < NSET; i++) { if (semctl(sid[i], NSEM, IPC_RMID)) perror("IPC_RMID"); } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } int main(int argc, char **argv) { pid_t p; srand(time(NULL)); while (1) { p = fork(); if (p < 0) { perror("fork"); exit(EXIT_FAILURE); } if (p == 0) { create_set(); goto end; } /* Wait for forked processes to exit */ while (wait(NULL)) { if (errno == ECHILD) break; }; } end: return 0; } [akpm@linux-foundation.org: use normal comment layout] Signed-off-by: Herton R. Krzesinski Acked-by: Manfred Spraul Cc: Davidlohr Bueso Cc: Rafael Aquini CC: Aristeu Rozanski Cc: David Jeffery Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/ipc/sem.c b/ipc/sem.c index bc3d530..a37aaeb 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -2074,17 +2074,28 @@ void exit_sem(struct task_struct *tsk) rcu_read_lock(); un = list_entry_rcu(ulp->list_proc.next, struct sem_undo, list_proc); - if (&un->list_proc == &ulp->list_proc) - semid = -1; - else - semid = un->semid; + if (&un->list_proc == &ulp->list_proc) { + /* + * We must wait for freeary() before freeing this ulp, + * in case we raced with last sem_undo. There is a small + * possibility where we exit while freeary() didn't + * finish unlocking sem_undo_list. + */ + spin_unlock_wait(&ulp->lock); + rcu_read_unlock(); + break; + } + spin_lock(&ulp->lock); + semid = un->semid; + spin_unlock(&ulp->lock); + /* exit_sem raced with IPC_RMID, nothing to do */ if (semid == -1) { rcu_read_unlock(); - break; + continue; } - sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid); + sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid); /* exit_sem raced with IPC_RMID, nothing to do */ if (IS_ERR(sma)) { rcu_read_unlock(); -- cgit v0.10.2 From a97955844807e327df11aa33869009d14d6b7de0 Mon Sep 17 00:00:00 2001 From: "Herton R. Krzesinski" Date: Fri, 14 Aug 2015 15:35:05 -0700 Subject: ipc,sem: remove uneeded sem_undo_list lock usage in exit_sem() After we acquire the sma->sem_perm lock in exit_sem(), we are protected against a racing IPC_RMID operation. Also at that point, we are the last user of sem_undo_list. Therefore it isn't required that we acquire or use ulp->lock. Signed-off-by: Herton R. Krzesinski Acked-by: Manfred Spraul Cc: Davidlohr Bueso Cc: Rafael Aquini CC: Aristeu Rozanski Cc: David Jeffery Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/ipc/sem.c b/ipc/sem.c index a37aaeb..178f303 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -2123,9 +2123,11 @@ void exit_sem(struct task_struct *tsk) ipc_assert_locked_object(&sma->sem_perm); list_del(&un->list_id); - spin_lock(&ulp->lock); + /* we are the last process using this ulp, acquiring ulp->lock + * isn't required. Besides that, we are also protected against + * IPC_RMID as we hold sma->sem_perm lock now + */ list_del_rcu(&un->list_proc); - spin_unlock(&ulp->lock); /* perform adjustments registered in un */ for (i = 0; i < sma->sem_nsems; i++) { -- cgit v0.10.2 From 7f6bf39bbdd1dcccd103ba7dce8496a8e72e7df4 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Fri, 14 Aug 2015 15:35:08 -0700 Subject: mm/hwpoison: fix panic due to split huge zero page Bug: ------------[ cut here ]------------ kernel BUG at mm/huge_memory.c:1957! invalid opcode: 0000 [#1] SMP Modules linked in: snd_hda_codec_hdmi i915 rpcsec_gss_krb5 snd_hda_codec_realtek snd_hda_codec_generic nfsv4 dns_re CPU: 2 PID: 2576 Comm: test_huge Not tainted 4.2.0-rc5-mm1+ #27 Hardware name: Dell Inc. OptiPlex 7020/0F5C5X, BIOS A03 01/08/2015 task: ffff880204e3d600 ti: ffff8800db16c000 task.ti: ffff8800db16c000 RIP: split_huge_page_to_list+0xdb/0x120 Call Trace: memory_failure+0x32e/0x7c0 madvise_hwpoison+0x8b/0x160 SyS_madvise+0x40/0x240 ? do_page_fault+0x37/0x90 entry_SYSCALL_64_fastpath+0x12/0x71 Code: ff f0 41 ff 4c 24 30 74 0d 31 c0 48 83 c4 08 5b 41 5c 41 5d c9 c3 4c 89 e7 e8 e2 58 fd ff 48 83 c4 08 31 c0 RIP split_huge_page_to_list+0xdb/0x120 RSP ---[ end trace aee7ce0df8e44076 ]--- Testcase: #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define MB 1024*1024 int main(void) { char *mem; posix_memalign((void **)&mem, 2 * MB, 200 * MB); madvise(mem, 200 * MB, MADV_HWPOISON); free(mem); return 0; } Huge zero page is allocated if page fault w/o FAULT_FLAG_WRITE flag. The get_user_pages_fast() which called in madvise_hwpoison() will get huge zero page if the page is not allocated before. Huge zero page is a tranparent huge page, however, it is not an anonymous page. memory_failure will split the huge zero page and trigger BUG_ON(is_huge_zero_page(page)); After commit 98ed2b0052e6 ("mm/memory-failure: give up error handling for non-tail-refcounted thp"), memory_failure will not catch non anon thp from madvise_hwpoison path and this bug occur. Fix it by catching non anon thp in memory_failure in order to not split huge zero page in madvise_hwpoison path. After this patch: Injecting memory failure for page 0x202800 at 0x7fd8ae800000 MCE: 0x202800: non anonymous thp [...] [akpm@linux-foundation.org: remove second split, per Wanpeng] Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index dba52ee..1f4446a9 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1146,8 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags) } if (!PageHuge(p) && PageTransHuge(hpage)) { - if (unlikely(split_huge_page(hpage))) { - pr_err("MCE: %#lx: thp split failed\n", pfn); + if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) { + if (!PageAnon(hpage)) + pr_err("MCE: %#lx: non anonymous thp\n", pfn); + else + pr_err("MCE: %#lx: thp split failed\n", pfn); if (TestClearPageHWPoison(p)) atomic_long_sub(nr_pages, &num_poisoned_pages); put_page(p); -- cgit v0.10.2 From 3ed1f8a99d70ea1cd1508910eb107d0edcae5009 Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Fri, 14 Aug 2015 15:35:10 -0700 Subject: ipc/sem.c: update/correct memory barriers sem_lock() did not properly pair memory barriers: !spin_is_locked() and spin_unlock_wait() are both only control barriers. The code needs an acquire barrier, otherwise the cpu might perform read operations before the lock test. As no primitive exists inside and since it seems noone wants another primitive, the code creates a local primitive within ipc/sem.c. With regards to -stable: The change of sem_wait_array() is a bugfix, the change to sem_lock() is a nop (just a preprocessor redefinition to improve the readability). The bugfix is necessary for all kernels that use sem_wait_array() (i.e.: starting from 3.10). Signed-off-by: Manfred Spraul Reported-by: Oleg Nesterov Acked-by: Peter Zijlstra (Intel) Cc: "Paul E. McKenney" Cc: Kirill Tkhai Cc: Ingo Molnar Cc: Josh Poimboeuf Cc: Davidlohr Bueso Cc: [3.10+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/ipc/sem.c b/ipc/sem.c index 178f303..b471e5a 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -253,6 +253,16 @@ static void sem_rcu_free(struct rcu_head *head) } /* + * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they + * are only control barriers. + * The code must pair with spin_unlock(&sem->lock) or + * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. + * + * smp_rmb() is sufficient, as writes cannot pass the control barrier. + */ +#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() + +/* * Wait until all currently ongoing simple ops have completed. * Caller must own sem_perm.lock. * New simple ops cannot start, because simple ops first check @@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma) sem = sma->sem_base + i; spin_unlock_wait(&sem->lock); } + ipc_smp_acquire__after_spin_is_unlocked(); } /* @@ -327,13 +338,12 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops, /* Then check that the global lock is free */ if (!spin_is_locked(&sma->sem_perm.lock)) { /* - * The ipc object lock check must be visible on all - * cores before rechecking the complex count. Otherwise - * we can race with another thread that does: + * We need a memory barrier with acquire semantics, + * otherwise we can race with another thread that does: * complex_count++; * spin_unlock(sem_perm.lock); */ - smp_rmb(); + ipc_smp_acquire__after_spin_is_unlocked(); /* * Now repeat the test of complex_count: -- cgit v0.10.2 From 2baf9e8948530f2c6af36f0e3d9a26e0315900e6 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Fri, 14 Aug 2015 15:35:13 -0700 Subject: .mailmap: Andrey Ryabinin has moved Update my email address. Signed-off-by: Andrey Ryabinin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/.mailmap b/.mailmap index b4091b7..4b31af5 100644 --- a/.mailmap +++ b/.mailmap @@ -17,6 +17,7 @@ Aleksey Gorelov Al Viro Al Viro Andreas Herrmann +Andrey Ryabinin Andrew Morton Andrew Vasquez Andy Adamson diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 6c513a6..7b28e9c 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -2,7 +2,7 @@ * This file contains shadow memory manipulation code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * Author: Andrey Ryabinin + * Author: Andrey Ryabinin * * Some of code borrowed from https://github.com/xairy/linux by * Andrey Konovalov diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 680ceed..e07c94f 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -2,7 +2,7 @@ * This file contains error reporting code. * * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * Author: Andrey Ryabinin + * Author: Andrey Ryabinin * * Some of code borrowed from https://github.com/xairy/linux by * Andrey Konovalov -- cgit v0.10.2 From f9126ab9241f66562debf69c2c9d8fee32ddcc53 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Fri, 14 Aug 2015 15:35:16 -0700 Subject: memory-hotplug: fix wrong edge when hot add a new node When we add a new node, the edge of memory may be wrong. e.g. system has 4 nodes, and node3 is movable, node3 mem:[24G-32G], 1. hotremove the node3, 2. then hotadd node3 with a part of memory, mem:[26G-30G], 3. call hotadd_new_pgdat() free_area_init_node() get_pfn_range_for_nid() 4. it will return wrong start_pfn and end_pfn, because we have not update the memblock. This patch also fixes a BUG_ON during hot-addition, please see http://marc.info/?l=linux-kernel&m=142961156129456&w=2 Signed-off-by: Xishi Qiu Cc: Yasuaki Ishimatsu Cc: Kamezawa Hiroyuki Cc: Taku Izumi Cc: Tang Chen Cc: Gu Zheng Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 003dbe4..6da82bc 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1277,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size) /* create new memmap entry */ firmware_map_add_hotplug(start, start + size, "System RAM"); + memblock_add_node(start, size, nid); goto out; @@ -2013,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size) /* remove memmap entry */ firmware_map_remove(start, start + size, "System RAM"); + memblock_free(start, size); + memblock_remove(start, size); arch_remove_memory(start, size); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index beda417..df959b7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5060,6 +5060,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid, { unsigned long zone_start_pfn, zone_end_pfn; + /* When hotadd a new node, the node should be empty */ + if (!node_start_pfn && !node_end_pfn) + return 0; + /* Get the start and end of the zone */ zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type]; zone_end_pfn = arch_zone_highest_possible_pfn[zone_type]; @@ -5123,6 +5127,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid, unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type]; unsigned long zone_start_pfn, zone_end_pfn; + /* When hotadd a new node, the node should be empty */ + if (!node_start_pfn && !node_end_pfn) + return 0; + zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high); zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high); -- cgit v0.10.2 From 4ce321f574a97f3453bca5a4117610b43dabd3ee Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Fri, 14 Aug 2015 15:35:19 -0700 Subject: zram: fix pool name truncation zram_meta_alloc() constructs a pool name for zs_create_pool() call as snprintf(pool_name, sizeof(pool_name), "zram%d", device_id); However, it defines pool name buffer to be only 8 bytes long (minus trailing zero), which means that we can have only 1000 pool names: zram0 -- zram999. With CONFIG_ZSMALLOC_STAT enabled an attempt to create a device zram1000 can fail if device zram100 already exists, because snprintf() will truncate new pool name to zram100 and pass it debugfs_create_dir(), causing: debugfs dir creation failed zram: Error creating memory pool ... and so on. Fix it by passing zram->disk->disk_name to zram_meta_alloc() instead of divice_id. We construct zram%d name earlier and keep it as a ->disk_name, no need to snprintf() it again. Signed-off-by: Sergey Senozhatsky Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index fb655e8..763301c 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -496,10 +496,9 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize) kfree(meta); } -static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize) +static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize) { size_t num_pages; - char pool_name[8]; struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL); if (!meta) @@ -512,7 +511,6 @@ static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize) goto out_error; } - snprintf(pool_name, sizeof(pool_name), "zram%d", device_id); meta->mem_pool = zs_create_pool(pool_name, GFP_NOIO | __GFP_HIGHMEM); if (!meta->mem_pool) { pr_err("Error creating memory pool\n"); @@ -1031,7 +1029,7 @@ static ssize_t disksize_store(struct device *dev, return -EINVAL; disksize = PAGE_ALIGN(disksize); - meta = zram_meta_alloc(zram->disk->first_minor, disksize); + meta = zram_meta_alloc(zram->disk->disk_name, disksize); if (!meta) return -ENOMEM; -- cgit v0.10.2 From f21838e056ebc499f5d6ca4cb734e82cf9c275a5 Mon Sep 17 00:00:00 2001 From: Gregory Fong Date: Fri, 14 Aug 2015 15:35:21 -0700 Subject: mm: cma: mark cma_bitmap_maxno() inline in header cma_bitmap_maxno() was marked as static and not static inline, which can cause warnings about this function not being used if this file is included in a file that does not call that function, and violates the conventions used elsewhere. The two options are to move the function implementation back to mm/cma.c or make it inline here, and it's simple enough for the latter to make sense. Signed-off-by: Gregory Fong Cc: Joonsoo Kim Cc: Sasha Levin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/cma.h b/mm/cma.h index 1132d73..17c75a4 100644 --- a/mm/cma.h +++ b/mm/cma.h @@ -16,7 +16,7 @@ struct cma { extern struct cma cma_areas[MAX_CMA_AREAS]; extern unsigned cma_area_count; -static unsigned long cma_bitmap_maxno(struct cma *cma) +static inline unsigned long cma_bitmap_maxno(struct cma *cma) { return cma->count >> cma->order_per_bit; } -- cgit v0.10.2 From 7f11c47605cbe7cb76fd2f8607f452d4afe919f5 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 14 Aug 2015 15:35:24 -0700 Subject: Update maintainers for DRM STI driver Add Vincent Abriou and myself as maintainers. Signed-off-by: Benjamin Gaignard Cc: Vincent Abriou Cc: Dave Airlie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index a9ae6c1..569568f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3587,6 +3587,15 @@ S: Maintained F: drivers/gpu/drm/rockchip/ F: Documentation/devicetree/bindings/video/rockchip* +DRM DRIVERS FOR STI +M: Benjamin Gaignard +M: Vincent Abriou +L: dri-devel@lists.freedesktop.org +T: git http://git.linaro.org/people/benjamin.gaignard/kernel.git +S: Maintained +F: drivers/gpu/drm/sti +F: Documentation/devicetree/bindings/gpu/st,stih4xx.txt + DSBR100 USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org -- cgit v0.10.2 From 02373d7c69b4270bbab930f8a81b0721be794347 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 12 Aug 2015 15:22:16 +0530 Subject: thermal: cpu_cooling: fix lockdep problems in cpu_cooling A recent change to the cpu_cooling code introduced a AB-BA deadlock scenario between the cpufreq_policy_notifier_list rwsem and the cooling_cpufreq_lock. This is caused by cooling_cpufreq_lock being held before the registration/removal of the notifier block (an operation which takes the rwsem), and the notifier code itself which takes the locks in the reverse order: ====================================================== [ INFO: possible circular locking dependency detected ] 3.18.0+ #1453 Not tainted ------------------------------------------------------- rc.local/770 is trying to acquire lock: (cooling_cpufreq_lock){+.+.+.}, at: [] cpufreq_thermal_notifier+0x34/0xfc but task is already holding lock: ((cpufreq_policy_notifier_list).rwsem){++++.+}, at: [] __blocking_notifier_call_chain+0x34/0x68 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 ((cpufreq_policy_notifier_list).rwsem){++++.+}: [] down_write+0x44/0x9c [] blocking_notifier_chain_register+0x28/0xd8 [] cpufreq_register_notifier+0x68/0x90 [] __cpufreq_cooling_register.part.1+0x120/0x180 [] __cpufreq_cooling_register+0x98/0xa4 [] cpufreq_cooling_register+0x18/0x1c [] imx_thermal_probe+0x1c0/0x470 [imx_thermal] [] platform_drv_probe+0x50/0xac [] driver_probe_device+0x114/0x234 [] __driver_attach+0x9c/0xa0 [] bus_for_each_dev+0x5c/0x90 [] driver_attach+0x24/0x28 [] bus_add_driver+0xe0/0x1d8 [] driver_register+0x80/0xfc [] __platform_driver_register+0x50/0x64 [] 0xbf007018 [] do_one_initcall+0x88/0x1d8 [] load_module+0x1768/0x1ef8 [] SyS_init_module+0xe0/0xf4 [] ret_fast_syscall+0x0/0x48 -> #0 (cooling_cpufreq_lock){+.+.+.}: [] lock_acquire+0xb0/0x124 [] mutex_lock_nested+0x5c/0x3d8 [] cpufreq_thermal_notifier+0x34/0xfc [] notifier_call_chain+0x4c/0x8c [] __blocking_notifier_call_chain+0x50/0x68 [] blocking_notifier_call_chain+0x20/0x28 [] cpufreq_set_policy+0x7c/0x1d0 [] store_scaling_governor+0x74/0x9c [] store+0x90/0xc0 [] sysfs_kf_write+0x54/0x58 [] kernfs_fop_write+0xdc/0x190 [] vfs_write+0xac/0x1b4 [] SyS_write+0x44/0x90 [] ret_fast_syscall+0x0/0x48 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock((cpufreq_policy_notifier_list).rwsem); lock(cooling_cpufreq_lock); lock((cpufreq_policy_notifier_list).rwsem); lock(cooling_cpufreq_lock); *** DEADLOCK *** 7 locks held by rc.local/770: #0: (sb_writers#6){.+.+.+}, at: [] vfs_write+0x18c/0x1b4 #1: (&of->mutex){+.+.+.}, at: [] kernfs_fop_write+0xa0/0x190 #2: (s_active#52){.+.+.+}, at: [] kernfs_fop_write+0xa8/0x190 #3: (cpu_hotplug.lock){++++++}, at: [] get_online_cpus+0x34/0x90 #4: (cpufreq_rwsem){.+.+.+}, at: [] store+0x58/0xc0 #5: (&policy->rwsem){+.+.+.}, at: [] store+0x70/0xc0 #6: ((cpufreq_policy_notifier_list).rwsem){++++.+}, at: [] __blocking_notifier_call_chain+0x34/0x68 stack backtrace: CPU: 0 PID: 770 Comm: rc.local Not tainted 3.18.0+ #1453 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r6:c0b85a80 r5:c0b75630 r4:00000000 r3:00000000 [] (show_stack) from [] (dump_stack+0x7c/0x98) [] (dump_stack) from [] (print_circular_bug+0x28c/0x2d8) r4:c0b85a80 r3:d0071d40 [] (print_circular_bug) from [] (__lock_acquire+0x1acc/0x1bb0) r10:c0b50660 r8:c09e6d80 r7:d0071d40 r6:c11d0f0c r5:00000007 r4:d0072240 [] (__lock_acquire) from [] (lock_acquire+0xb0/0x124) r10:00000000 r9:c04abfc4 r8:00000000 r7:00000000 r6:00000000 r5:c0a06f0c r4:00000000 [] (lock_acquire) from [] (mutex_lock_nested+0x5c/0x3d8) r10:ec853800 r9:c0a06ed4 r8:d0071d40 r7:c0a06ed4 r6:c11d0f0c r5:00000000 r4:c04abfc4 [] (mutex_lock_nested) from [] (cpufreq_thermal_notifier+0x34/0xfc) r10:ec853800 r9:ec85380c r8:d00d7d3c r7:c0a06ed4 r6:d00d7d3c r5:00000000 r4:fffffffe [] (cpufreq_thermal_notifier) from [] (notifier_call_chain+0x4c/0x8c) r7:00000000 r6:00000000 r5:00000000 r4:fffffffe [] (notifier_call_chain) from [] (__blocking_notifier_call_chain+0x50/0x68) r8:c0a072a4 r7:00000000 r6:d00d7d3c r5:ffffffff r4:c0a06fc8 r3:ffffffff [] (__blocking_notifier_call_chain) from [] (blocking_notifier_call_chain+0x20/0x28) r7:ec98b540 r6:c13ebc80 r5:ed76e600 r4:d00d7d3c [] (blocking_notifier_call_chain) from [] (cpufreq_set_policy+0x7c/0x1d0) [] (cpufreq_set_policy) from [] (store_scaling_governor+0x74/0x9c) r7:ec98b540 r6:0000000c r5:ec98b540 r4:ed76e600 [] (store_scaling_governor) from [] (store+0x90/0xc0) r6:0000000c r5:ed76e6d4 r4:ed76e600 [] (store) from [] (sysfs_kf_write+0x54/0x58) r8:0000000c r7:d00d7f78 r6:ec98b540 r5:0000000c r4:ec853800 r3:0000000c [] (sysfs_kf_write) from [] (kernfs_fop_write+0xdc/0x190) r6:ec98b540 r5:00000000 r4:00000000 r3:c0175330 [] (kernfs_fop_write) from [] (vfs_write+0xac/0x1b4) r10:0162aa70 r9:d00d6000 r8:0000000c r7:d00d7f78 r6:0162aa70 r5:0000000c r4:eccde500 [] (vfs_write) from [] (SyS_write+0x44/0x90) r10:0162aa70 r8:0000000c r7:eccde500 r6:eccde500 r5:00000000 r4:00000000 [] (SyS_write) from [] (ret_fast_syscall+0x0/0x48) r10:00000000 r8:c000edc4 r7:00000004 r6:000216cc r5:0000000c r4:0162aa70 Solve this by moving to finer grained locking - use one mutex to protect the cpufreq_dev_list as a whole, and a separate lock to ensure correct ordering of cpufreq notifier registration and removal. cooling_list_lock is taken within cooling_cpufreq_lock on (un)registration to preserve the behavior of the code, i.e. to atomically add/remove to the list and (un)register the notifier. Fixes: 2dcd851fe4b4 ("thermal: cpu_cooling: Update always cpufreq policy with Reviewed-by: Viresh Kumar Signed-off-by: Russell King Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 6509c61..5ae0524 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -107,6 +107,9 @@ struct cpufreq_cooling_device { static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); +static unsigned int cpufreq_dev_count; + +static DEFINE_MUTEX(cooling_list_lock); static LIST_HEAD(cpufreq_dev_list); /** @@ -185,14 +188,14 @@ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) { struct cpufreq_cooling_device *cpufreq_dev; - mutex_lock(&cooling_cpufreq_lock); + mutex_lock(&cooling_list_lock); list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { - mutex_unlock(&cooling_cpufreq_lock); + mutex_unlock(&cooling_list_lock); return get_level(cpufreq_dev, freq); } } - mutex_unlock(&cooling_cpufreq_lock); + mutex_unlock(&cooling_list_lock); pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); return THERMAL_CSTATE_INVALID; @@ -221,7 +224,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, switch (event) { case CPUFREQ_ADJUST: - mutex_lock(&cooling_cpufreq_lock); + mutex_lock(&cooling_list_lock); list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) @@ -233,7 +236,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, cpufreq_verify_within_limits(policy, 0, max_freq); } - mutex_unlock(&cooling_cpufreq_lock); + mutex_unlock(&cooling_list_lock); break; default: return NOTIFY_DONE; @@ -866,12 +869,14 @@ __cpufreq_cooling_register(struct device_node *np, mutex_lock(&cooling_cpufreq_lock); + mutex_lock(&cooling_list_lock); + list_add(&cpufreq_dev->node, &cpufreq_dev_list); + mutex_unlock(&cooling_list_lock); + /* Register the notifier for first cpufreq cooling device */ - if (list_empty(&cpufreq_dev_list)) + if (!cpufreq_dev_count++) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); - list_add(&cpufreq_dev->node, &cpufreq_dev_list); - mutex_unlock(&cooling_cpufreq_lock); return cool_dev; @@ -1013,13 +1018,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) return; cpufreq_dev = cdev->devdata; - mutex_lock(&cooling_cpufreq_lock); - list_del(&cpufreq_dev->node); /* Unregister the notifier for the last cpufreq cooling device */ - if (list_empty(&cpufreq_dev_list)) + mutex_lock(&cooling_cpufreq_lock); + if (!--cpufreq_dev_count) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); + + mutex_lock(&cooling_list_lock); + list_del(&cpufreq_dev->node); + mutex_unlock(&cooling_list_lock); + mutex_unlock(&cooling_cpufreq_lock); thermal_cooling_device_unregister(cpufreq_dev->cool_dev); -- cgit v0.10.2 From 76fd38ce21de506a3867768fac42729eb6d7dedf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:30 +0530 Subject: thermal/cpu_cooling: No need to initialize max_freq to 0 Its always set before getting used, don't initialize it. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 5ae0524..c7572df 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -218,7 +218,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct cpufreq_policy *policy = data; - unsigned long max_freq = 0; + unsigned long max_freq; struct cpufreq_cooling_device *cpufreq_dev; switch (event) { -- cgit v0.10.2 From 166529c9b6f91b97d771e2e7ebf748aadb239b44 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:31 +0530 Subject: thermal/cpu_cooling: quit early after updating policy If a valid cpufreq_dev is found for policy->cpu, we should update the policy and quit the for loop. There is no need to keep traversing the list of cpufreq_dev's. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index c7572df..093537f 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -235,6 +235,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, if (policy->max != max_freq) cpufreq_verify_within_limits(policy, 0, max_freq); + break; } mutex_unlock(&cooling_list_lock); break; -- cgit v0.10.2 From a24af233a1fd09002cabc05d6da248cc5656a2e1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:32 +0530 Subject: thermal/cpu_cooling: convert 'switch' block to 'if' block in notifier We just need to take care of single event here and there is no need to increase indentation level of most of the code (which causes lines longer that 80 columns to break). Kill the switch block. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 093537f..1cf897c 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -221,27 +221,21 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, unsigned long max_freq; struct cpufreq_cooling_device *cpufreq_dev; - switch (event) { + if (event != CPUFREQ_ADJUST) + return NOTIFY_DONE; - case CPUFREQ_ADJUST: - mutex_lock(&cooling_list_lock); - list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { - if (!cpumask_test_cpu(policy->cpu, - &cpufreq_dev->allowed_cpus)) - continue; + mutex_lock(&cooling_list_lock); + list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { + if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) + continue; - max_freq = cpufreq_dev->cpufreq_val; + max_freq = cpufreq_dev->cpufreq_val; - if (policy->max != max_freq) - cpufreq_verify_within_limits(policy, 0, - max_freq); - break; - } - mutex_unlock(&cooling_list_lock); + if (policy->max != max_freq) + cpufreq_verify_within_limits(policy, 0, max_freq); break; - default: - return NOTIFY_DONE; } + mutex_unlock(&cooling_list_lock); return NOTIFY_OK; } -- cgit v0.10.2 From 59f0d21883f39d27f14408d4ca211dce80658963 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:33 +0530 Subject: thermal/cpu_cooling: rename cpufreq_val as clipped_freq That's what it is for, lets name it properly. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 1cf897c..9c14622 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -68,7 +68,7 @@ struct power_table { * registered cooling device. * @cpufreq_state: integer value representing the current state of cpufreq * cooling devices. - * @cpufreq_val: integer value representing the absolute value of the clipped + * @clipped_freq: integer value representing the absolute value of the clipped * frequency. * @max_level: maximum cooling level. One less than total number of valid * cpufreq frequencies. @@ -91,7 +91,7 @@ struct cpufreq_cooling_device { int id; struct thermal_cooling_device *cool_dev; unsigned int cpufreq_state; - unsigned int cpufreq_val; + unsigned int clipped_freq; unsigned int max_level; unsigned int *freq_table; /* In descending order */ struct cpumask allowed_cpus; @@ -229,7 +229,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) continue; - max_freq = cpufreq_dev->cpufreq_val; + max_freq = cpufreq_dev->clipped_freq; if (policy->max != max_freq) cpufreq_verify_within_limits(policy, 0, max_freq); @@ -517,7 +517,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, clip_freq = cpufreq_device->freq_table[state]; cpufreq_device->cpufreq_state = state; - cpufreq_device->cpufreq_val = clip_freq; + cpufreq_device->clipped_freq = clip_freq; cpufreq_update_policy(cpu); @@ -859,7 +859,7 @@ __cpufreq_cooling_register(struct device_node *np, pr_debug("%s: freq:%u KHz\n", __func__, freq); } - cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; + cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0]; cpufreq_dev->cool_dev = cool_dev; mutex_lock(&cooling_cpufreq_lock); -- cgit v0.10.2 From abcbcc25cb3edfc3c9af210a88c9386e353191fe Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:34 +0530 Subject: thermal/cpu_cooling: rename max_freq as clipped_freq in notifier That's what it is for, lets name it properly. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 9c14622..71dbede 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -218,7 +218,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct cpufreq_policy *policy = data; - unsigned long max_freq; + unsigned long clipped_freq; struct cpufreq_cooling_device *cpufreq_dev; if (event != CPUFREQ_ADJUST) @@ -229,10 +229,10 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) continue; - max_freq = cpufreq_dev->clipped_freq; + clipped_freq = cpufreq_dev->clipped_freq; - if (policy->max != max_freq) - cpufreq_verify_within_limits(policy, 0, max_freq); + if (policy->max != clipped_freq) + cpufreq_verify_within_limits(policy, 0, clipped_freq); break; } mutex_unlock(&cooling_list_lock); -- cgit v0.10.2 From 1afb9c539daebc2c8a7b33d0e0b8fc9f74671b02 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 12:40:35 +0530 Subject: thermal/cpu_cooling: update policy limits if clipped_freq < policy->max policy->max is the maximum allowed frequency defined by user and clipped_freq is the maximum that thermal constraints allow. If clipped_freq is lower than policy->max, then we need to readjust policy->max. But, if clipped_freq is greater than policy->max, we don't need to do anything. We used to call cpufreq_verify_within_limits() in this case, but it doesn't change anything in this case. Lets skip this unnecessary call and write a comment that explains this. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 71dbede..620dcd4 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -229,9 +229,20 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) continue; + /* + * policy->max is the maximum allowed frequency defined by user + * and clipped_freq is the maximum that thermal constraints + * allow. + * + * If clipped_freq is lower than policy->max, then we need to + * readjust policy->max. + * + * But, if clipped_freq is greater than policy->max, we don't + * need to do anything. + */ clipped_freq = cpufreq_dev->clipped_freq; - if (policy->max != clipped_freq) + if (policy->max > clipped_freq) cpufreq_verify_within_limits(policy, 0, clipped_freq); break; } -- cgit v0.10.2 From 601e4576594543200bde9201e4d23242e73a778b Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Thu, 13 Aug 2015 15:10:19 +0200 Subject: ASoC: ssm2518: Add explicit device tree support Add OF match table to SSM2518 to allow direct matching without going through I2C subsystem. Signed-off-by: Ricard Wanderlof Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 5d94d6c..ddb0203 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -806,6 +806,14 @@ static int ssm2518_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id ssm2518_dt_ids[] = { + { .compatible = "adi,ssm2518", }, + { } +}; +MODULE_DEVICE_TABLE(of, ssm2518_dt_ids); +#endif + static const struct i2c_device_id ssm2518_i2c_ids[] = { { "ssm2518", 0 }, { } @@ -815,6 +823,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); static struct i2c_driver ssm2518_driver = { .driver = { .name = "ssm2518", + .of_match_table = of_match_ptr(ssm2518_dt_ids), }, .probe = ssm2518_i2c_probe, .remove = ssm2518_i2c_remove, -- cgit v0.10.2 From 50e0ee01382b8e08289d3db209738c5856fd25cf Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Fri, 14 Aug 2015 19:11:09 +0800 Subject: ASoC: fsl-asoc-card: add wm8960 support add wm8960 support for fsl-asoc-card Signed-off-by: Zidan Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 040362f..5aeb6ed 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -23,6 +23,7 @@ #include "../codecs/sgtl5000.h" #include "../codecs/wm8962.h" +#include "../codecs/wm8960.h" #define RX 0 #define TX 1 @@ -479,6 +480,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; priv->codec_priv.pll_id = WM8962_FLL; priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) { + codec_dai_name = "wm8960-hifi"; + priv->card.set_bias_level = fsl_asoc_card_set_bias_level; + priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO; + priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); return -EINVAL; @@ -582,6 +589,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-cs42888", }, { .compatible = "fsl,imx-audio-sgtl5000", }, { .compatible = "fsl,imx-audio-wm8962", }, + { .compatible = "fsl,imx-audio-wm8960", }, {} }; -- cgit v0.10.2 From 9f161439e4104b641a7bfb9b89581d801159fec8 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 08:47:59 +0100 Subject: MIPS: Fix seccomp syscall argument for MIPS64 Commit 4c21b8fd8f14 ("MIPS: seccomp: Handle indirect system calls (o32)") fixed indirect system calls on O32 but it also introduced a bug for MIPS64 where it erroneously modified the v0 (syscall) register with the assumption that the sycall offset hasn't been taken into consideration. This breaks seccomp on MIPS64 n64 and n32 ABIs. We fix this by replacing the addition with a move instruction. Fixes: 4c21b8fd8f14 ("MIPS: seccomp: Handle indirect system calls (o32)") Cc: # 3.15+ Reviewed-by: James Hogan Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10951/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index ad4d4463..a6f6b76 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -80,7 +80,7 @@ syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - daddiu a1, v0, __NR_64_Linux + move a1, v0 jal syscall_trace_enter bltz v0, 2f # seccomp failed? Skip syscall diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 446cc65..4b20106 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -72,7 +72,7 @@ n32_syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - daddiu a1, v0, __NR_N32_Linux + move a1, v0 jal syscall_trace_enter bltz v0, 2f # seccomp failed? Skip syscall -- cgit v0.10.2 From 8ed1f0e22f49ef42e63875fd2529389a32ff3566 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Sun, 16 Aug 2015 20:27:01 +0200 Subject: fs/fuse: fix ioctl type confusion fuse_dev_ioctl() performed fuse_get_dev() on a user-supplied fd, leading to a type confusion issue. Fix it by checking file->f_op. Signed-off-by: Jann Horn Acked-by: Miklos Szeredi Signed-off-by: Linus Torvalds diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 80cc1b3..ebb5e37 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2246,7 +2246,15 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd, err = -EINVAL; if (old) { - struct fuse_dev *fud = fuse_get_dev(old); + struct fuse_dev *fud = NULL; + + /* + * Check against file->f_op because CUSE + * uses the same ioctl handler. + */ + if (old->f_op == file->f_op && + old->f_cred->user_ns == file->f_cred->user_ns) + fud = fuse_get_dev(old); if (fud) { mutex_lock(&fuse_mutex); -- cgit v0.10.2 From 12e244f4b550498bbaf654a52f93633f7dde2dc7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 14 Aug 2015 15:02:55 -0700 Subject: x86/ldt: Further fix FPU emulation The previous fix confused a selector with a segment prefix. Fix it. Compile-tested only. Cc: stable@vger.kernel.org Cc: Juergen Gross Reported-by: Linus Torvalds Fixes: 4809146b86c3 ("x86/ldt: Correct FPU emulation access to LDT") Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c index d13cab2..8300db7 100644 --- a/arch/x86/math-emu/get_address.c +++ b/arch/x86/math-emu/get_address.c @@ -157,7 +157,7 @@ static long pm_address(u_char FPU_modrm, u_char segment, addr->selector = PM_REG_(segment); } - descriptor = FPU_get_ldt_descriptor(segment); + descriptor = FPU_get_ldt_descriptor(addr->selector); base_address = SEG_BASE_ADDR(descriptor); address = base_address + offset; limit = base_address -- cgit v0.10.2 From 2c6625cd545bdd66acff14f3394865d43920a5c7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 16 Aug 2015 16:34:13 -0700 Subject: Linux 4.2-rc7 diff --git a/Makefile b/Makefile index 35b4c19..6e88c37 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* -- cgit v0.10.2 From 903ecd0bb970438c3a60c2c33ec9032d6443bf67 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Aug 2015 12:59:19 +0100 Subject: drm/i915: Flag the execlists context object as dirty after every use Everytime we use the logical context with execlists it becomes dirty (as the hardware will write the new register values afterwards, as well as the GPU state that will be used). We need to then flag the context as dirty everytime since after a swap-out/swap-in cycle the dirty flag will be cleared, and a further swap-out cycle will then loose the most recent GPU state. Signed-off-by: Chris Wilson Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9b74ffa..7f2161a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1012,6 +1012,8 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring, ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf); if (ret) goto unpin_ctx_obj; + + ctx_obj->dirty = true; } return ret; -- cgit v0.10.2 From 05aa1a77dcf1b9f9c4fedf09a0a53e15d6b21738 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 7 Aug 2015 12:26:47 +0200 Subject: dmaengine: fix balance of privatecnt inc/dec operations This patch increments privatecnt value and set DMA_PRIVATE in device caps in dma_request_slave_channel() function. This is needed to keep privatecnt increment/decrement balance. As function dma_release_channel() decrements privatecnt counter, we need to increment it when channel is requested. Otherwise privatecnt drops into negatives after few dma_release_channel() calls. Reported-by: Krzysztof Kozlowski Signed-off-by: Robert Baldyga Signed-off-by: Vinod Koul diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 4a4cce1..3ff284c 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -689,6 +689,10 @@ struct dma_chan *dma_request_slave_channel(struct device *dev, struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); if (IS_ERR(ch)) return NULL; + + dma_cap_set(DMA_PRIVATE, ch->device->cap_mask); + ch->device->privatecnt++; + return ch; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); -- cgit v0.10.2 From 0643558f85e740019e0632072c55e8b2f79a8d7d Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Mon, 17 Aug 2015 19:16:51 +0800 Subject: ASoC: mediatek: Remove AIF widgets for backend DAIs DAPM core already creates widgets for DAIs. It is not necessary to declare them by SND_SOC_DAPM_AIF_IN/SND_SOC_DAPM_AIF_OUT. Furthermore, original codes use backend DAI's stream name to be the AIF widget name. It causes the same widget to be created twice, and after commit 92fa12426741 ("ASoC: dapm: Add new widgets to the end of the widget list") the first created widget (by snd_soc_dapm_new_controls) is used, not the 2nd created one (by snd_soc_dapm_new_dai_widgets), so audio path is broken. Signed-off-by: Koro Chen Signed-off-by: Mark Brown diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index cc228db..e3e6331 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -820,10 +820,6 @@ static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { }; static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { - /* Backend DAIs */ - SND_SOC_DAPM_AIF_IN("I2S Capture", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("I2S Playback", NULL, 0, SND_SOC_NOPM, 0, 0), - /* inter-connections */ SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -855,11 +851,6 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { { "O10", "I18 Switch", "I18" }, }; -static const struct snd_soc_dapm_widget mtk_afe_hdmi_widgets[] = { - /* Backend DAIs */ - SND_SOC_DAPM_AIF_OUT("HDMIO Playback", NULL, 0, SND_SOC_NOPM, 0, 0), -}; - static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { {"HDMIO Playback", NULL, "HDMI"}, }; @@ -874,8 +865,6 @@ static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = { static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = { .name = "mtk-afe-hdmi-dai", - .dapm_widgets = mtk_afe_hdmi_widgets, - .num_dapm_widgets = ARRAY_SIZE(mtk_afe_hdmi_widgets), .dapm_routes = mtk_afe_hdmi_routes, .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes), }; -- cgit v0.10.2 From 5d37852bf7d48e5afb5238a658cc167e7b78b381 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Thu, 13 Aug 2015 14:21:34 -0700 Subject: Revert "net: limit tcp/udp rmem/wmem to SOCK_{RCV,SND}BUF_MIN" Commit 8133534c760d4083 ("net: limit tcp/udp rmem/wmem to SOCK_{RCV,SND}BUF_MIN") modified four sysctls to enforce that the values written to them are not less than SOCK_MIN_{RCV,SND}BUF. That change causes 4096 to no longer be accepted as a valid value for 'min' in tcp_wmem and udp_wmem_min. 4096 has been the default for both of those sysctls for a long time, and unfortunately seems to be an extremely popular setting. This change breaks a large number of sysctl configurations at Facebook. That commit referred to b1cb59cf2efe7971 ("net: sysctl_net_core: check SNDBUF and RCVBUF for min length"), which choose to use the SOCK_MIN constants as the lower limits to avoid nasty bugs. But AFAICS, a limit of SOCK_MIN_SNDBUF isn't necessary to do that: the BUG_ON cited in the commit message seems to have happened because unix_stream_sendmsg() expects a minimum of a full page (ie SK_MEM_QUANTUM) and the math broke, not because it had less than SOCK_MIN_SNDBUF allocated. This particular issue doesn't seem to affect TCP however: using a setting of "1 1 1" for tcp_{r,w}mem works, although it's obviously suboptimal. SK_MEM_QUANTUM would be a nice minimum, but it's 64K on some archs, so there would still be breakage. Since a value of one doesn't seem to cause any problems, we can drop the minimum 8133534c added to fix this. This reverts commit 8133534c760d4083f79d2cde42c636ccc0b2792e. Fixes: 8133534c760d4083 ("net: limit tcp/udp rmem/wmem to SOCK_MIN...") Cc: Eric Dumazet Cc: Sorin Dumitru Signed-off-by: Calvin Owens Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 433231c..0330ab2 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -41,8 +41,6 @@ static int tcp_syn_retries_min = 1; static int tcp_syn_retries_max = MAX_TCP_SYNCNT; static int ip_ping_group_range_min[] = { 0, 0 }; static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; -static int min_sndbuf = SOCK_MIN_SNDBUF; -static int min_rcvbuf = SOCK_MIN_RCVBUF; /* Update system visible IP port range */ static void set_local_port_range(struct net *net, int range[2]) @@ -530,7 +528,7 @@ static struct ctl_table ipv4_table[] = { .maxlen = sizeof(sysctl_tcp_wmem), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &min_sndbuf, + .extra1 = &one, }, { .procname = "tcp_notsent_lowat", @@ -545,7 +543,7 @@ static struct ctl_table ipv4_table[] = { .maxlen = sizeof(sysctl_tcp_rmem), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &min_rcvbuf, + .extra1 = &one, }, { .procname = "tcp_app_win", @@ -758,7 +756,7 @@ static struct ctl_table ipv4_table[] = { .maxlen = sizeof(sysctl_udp_rmem_min), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &min_rcvbuf, + .extra1 = &one }, { .procname = "udp_wmem_min", @@ -766,7 +764,7 @@ static struct ctl_table ipv4_table[] = { .maxlen = sizeof(sysctl_udp_wmem_min), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = &min_sndbuf, + .extra1 = &one }, { } }; -- cgit v0.10.2 From 11e122cbe90ea5079622fb57bdf2dffe8cf68e57 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 14 Aug 2015 12:23:40 +0800 Subject: net: phy: fix PHY_RUNNING in phy_state_machine Currently, if phy state is PHY_RUNNING, we always register a CHANGE when phy works in polling or interrupt ignored, this will make the adjust_link being called even the phy link did Not changed. checking the phy link to make sure the link did changed before we register a CHANGE, if link did not changed, we do nothing. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index b2197b5..1e1fbb0 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -811,6 +811,7 @@ void phy_state_machine(struct work_struct *work) bool needs_aneg = false, do_suspend = false; enum phy_state old_state; int err = 0; + int old_link; mutex_lock(&phydev->lock); @@ -896,11 +897,18 @@ void phy_state_machine(struct work_struct *work) phydev->adjust_link(phydev->attached_dev); break; case PHY_RUNNING: - /* Only register a CHANGE if we are - * polling or ignoring interrupts + /* Only register a CHANGE if we are polling or ignoring + * interrupts and link changed since latest checking. */ - if (!phy_interrupt_is_valid(phydev)) - phydev->state = PHY_CHANGELINK; + if (!phy_interrupt_is_valid(phydev)) { + old_link = phydev->link; + err = phy_read_status(phydev); + if (err) + break; + + if (old_link != phydev->link) + phydev->state = PHY_CHANGELINK; + } break; case PHY_CHANGELINK: err = phy_read_status(phydev); -- cgit v0.10.2 From 8cb775bc0a34dc596837e7da03fd22c747be618b Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 14 Aug 2015 10:42:56 +0200 Subject: ppp: fix device unregistration upon netns deletion PPP devices may get automatically unregistered when their network namespace is getting removed. This happens if the ppp control plane daemon (e.g. pppd) exits while it is the last user of this namespace. This leads to several races: * ppp_exit_net() may destroy the per namespace idr (pn->units_idr) before all file descriptors were released. Successive ppp_release() calls may then cleanup PPP devices with ppp_shutdown_interface() and try to use the already destroyed idr. * Automatic device unregistration may also happen before the ppp_release() call for that device gets executed. Once called on the file owning the device, ppp_release() will then clean it up and try to unregister it a second time. To fix these issues, operations defined in ppp_shutdown_interface() are moved to the PPP device's ndo_uninit() callback. This allows PPP devices to be properly cleaned up by unregister_netdev() and friends. So checking for ppp->owner is now an accurate test to decide if a PPP device should be unregistered. Setting ppp->owner is done in ppp_create_interface(), before device registration, in order to avoid unprotected modification of this field. Finally, ppp_exit_net() now starts by unregistering all remaining PPP devices to ensure that none will get unregistered after the call to idr_destroy(). Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 9d15566..fa8f504 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -269,9 +269,9 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); static void ppp_ccp_closed(struct ppp *ppp); static struct compressor *find_compressor(int type); static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); -static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); +static struct ppp *ppp_create_interface(struct net *net, int unit, + struct file *file, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); -static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); @@ -392,8 +392,10 @@ static int ppp_release(struct inode *unused, struct file *file) file->private_data = NULL; if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); + rtnl_lock(); if (file == ppp->owner) - ppp_shutdown_interface(ppp); + unregister_netdevice(ppp->dev); + rtnl_unlock(); } if (atomic_dec_and_test(&pf->refcnt)) { switch (pf->kind) { @@ -593,8 +595,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_lock(&ppp_mutex); if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); + rtnl_lock(); if (file == ppp->owner) - ppp_shutdown_interface(ppp); + unregister_netdevice(ppp->dev); + rtnl_unlock(); } if (atomic_long_read(&file->f_count) < 2) { ppp_release(NULL, file); @@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, /* Create a new ppp unit */ if (get_user(unit, p)) break; - ppp = ppp_create_interface(net, unit, &err); + ppp = ppp_create_interface(net, unit, file, &err); if (!ppp) break; file->private_data = &ppp->file; - ppp->owner = file; err = -EFAULT; if (put_user(ppp->file.index, p)) break; @@ -916,6 +919,16 @@ static __net_init int ppp_init_net(struct net *net) static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + struct ppp *ppp; + LIST_HEAD(list); + int id; + + rtnl_lock(); + idr_for_each_entry(&pn->units_idr, ppp, id) + unregister_netdevice_queue(ppp->dev, &list); + + unregister_netdevice_many(&list); + rtnl_unlock(); idr_destroy(&pn->units_idr); } @@ -1088,8 +1101,28 @@ static int ppp_dev_init(struct net_device *dev) return 0; } +static void ppp_dev_uninit(struct net_device *dev) +{ + struct ppp *ppp = netdev_priv(dev); + struct ppp_net *pn = ppp_pernet(ppp->ppp_net); + + ppp_lock(ppp); + ppp->closing = 1; + ppp_unlock(ppp); + + mutex_lock(&pn->all_ppp_mutex); + unit_put(&pn->units_idr, ppp->file.index); + mutex_unlock(&pn->all_ppp_mutex); + + ppp->owner = NULL; + + ppp->file.dead = 1; + wake_up_interruptible(&ppp->file.rwait); +} + static const struct net_device_ops ppp_netdev_ops = { .ndo_init = ppp_dev_init, + .ndo_uninit = ppp_dev_uninit, .ndo_start_xmit = ppp_start_xmit, .ndo_do_ioctl = ppp_net_ioctl, .ndo_get_stats64 = ppp_get_stats64, @@ -2667,8 +2700,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) * or if there is already a unit with the requested number. * unit == -1 means allocate a new number. */ -static struct ppp * -ppp_create_interface(struct net *net, int unit, int *retp) +static struct ppp *ppp_create_interface(struct net *net, int unit, + struct file *file, int *retp) { struct ppp *ppp; struct ppp_net *pn; @@ -2688,6 +2721,7 @@ ppp_create_interface(struct net *net, int unit, int *retp) ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ + ppp->owner = file; for (i = 0; i < NUM_NP; ++i) ppp->npmode[i] = NPMODE_PASS; INIT_LIST_HEAD(&ppp->channels); @@ -2776,34 +2810,6 @@ init_ppp_file(struct ppp_file *pf, int kind) } /* - * Take down a ppp interface unit - called when the owning file - * (the one that created the unit) is closed or detached. - */ -static void ppp_shutdown_interface(struct ppp *ppp) -{ - struct ppp_net *pn; - - pn = ppp_pernet(ppp->ppp_net); - mutex_lock(&pn->all_ppp_mutex); - - /* This will call dev_close() for us. */ - ppp_lock(ppp); - if (!ppp->closing) { - ppp->closing = 1; - ppp_unlock(ppp); - unregister_netdev(ppp->dev); - unit_put(&pn->units_idr, ppp->file.index); - } else - ppp_unlock(ppp); - - ppp->file.dead = 1; - ppp->owner = NULL; - wake_up_interruptible(&ppp->file.rwait); - - mutex_unlock(&pn->all_ppp_mutex); -} - -/* * Free the memory used by a ppp unit. This is only called once * there are no channels connected to the unit and no file structs * that reference the unit. -- cgit v0.10.2 From 2902bc66fa7a6d959e033e5358fd836e2839b5db Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Aug 2015 11:54:59 +0300 Subject: net: ethernet: micrel: fix an error code The dma_mapping_error() function returns true or false. We should return -ENOMEM if it there is a dma mapping error. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index f78909a..09d2e16 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -952,9 +952,8 @@ static int ks8842_alloc_dma_bufs(struct net_device *netdev) sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev, tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE); - err = dma_mapping_error(adapter->dev, - sg_dma_address(&tx_ctl->sg)); - if (err) { + if (dma_mapping_error(adapter->dev, sg_dma_address(&tx_ctl->sg))) { + err = -ENOMEM; sg_dma_address(&tx_ctl->sg) = 0; goto err; } -- cgit v0.10.2 From 553de19a0e2f21809bc3864d40308864652521eb Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 15 Aug 2015 08:01:55 +0530 Subject: ASoC: davinci-vcif: Use devm_snd_soc_register_component Use resource managed function devm_snd_soc_register_component for component registration instead of snd_soc_register_component. Also, remove davinci_vcif_remove as it is now redundant. Signed-off-by: Vaishali Thakkar Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index fabd05f..c77d921 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -231,8 +231,9 @@ static int davinci_vcif_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, davinci_vcif_dev); - ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component, - &davinci_vcif_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &davinci_vcif_component, + &davinci_vcif_dai, 1); if (ret != 0) { dev_err(&pdev->dev, "could not register dai\n"); return ret; @@ -241,23 +242,14 @@ static int davinci_vcif_probe(struct platform_device *pdev) 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); return ret; } return 0; } -static int davinci_vcif_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - - return 0; -} - static struct platform_driver davinci_vcif_driver = { .probe = davinci_vcif_probe, - .remove = davinci_vcif_remove, .driver = { .name = "davinci-vcif", }, -- cgit v0.10.2 From 776829de90c5972895db398993ddfa9417ff8b01 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Fri, 14 Aug 2015 20:11:02 +0300 Subject: net: phy: workaround for buggy cable detection by LAN8700 after cable plugging * Due to HW bug, LAN8700 sometimes does not detect presence of energy in the Ethernet cable in Energy Detect Power-Down mode (e.g while EDPWRDOWN bit is set, the ENERGYON bit does not asserted sometimes). This is a common bug of LAN87xx family of PHY chips. * The lan87xx_read_status() was improved to acquire ENERGYON bit. Its previous algorythm still not reliable on 100 % and sometimes skip cable plugging. Signed-off-by: Igor Plyatov Signed-off-by: David S. Miller diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index c0f6479e..d64f016 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev) } /* - * The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each - * other in order to set the ENERGYON bit and exit EDPD mode. If a link partner - * does send the pulses within this interval, the PHY will remained powered - * down. - * - * This workaround will manually toggle the PHY on/off upon calls to read_status - * in order to generate link test pulses if the link is down. If a link partner - * is present, it will respond to the pulses, which will cause the ENERGYON bit - * to be set and will cause the EDPD mode to be exited. + * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable + * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to + * unstable detection of plugging in Ethernet cable. + * This workaround disables Energy Detect Power-Down mode and waiting for + * response on link pulses to detect presence of plugged Ethernet cable. + * The Energy Detect Power-Down mode is enabled again in the end of procedure to + * save approximately 220 mW of power if cable is unplugged. */ static int lan87xx_read_status(struct phy_device *phydev) { int err = genphy_read_status(phydev); + int i; if (!phydev->link) { /* Disable EDPD to wake up PHY */ @@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev) if (rc < 0) return rc; - /* Sleep 64 ms to allow ~5 link test pulses to be sent */ - msleep(64); + /* Wait max 640 ms to detect energy */ + for (i = 0; i < 64; i++) { + /* Sleep to allow link test pulses to be sent */ + msleep(10); + rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); + if (rc < 0) + return rc; + if (rc & MII_LAN83C185_ENERGYON) + break; + }; /* Re-enable EDPD */ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); @@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = { /* basic functions */ .config_aneg = genphy_config_aneg, - .read_status = genphy_read_status, + .read_status = lan87xx_read_status, .config_init = smsc_phy_config_init, .soft_reset = smsc_phy_reset, -- cgit v0.10.2 From ad706862890171e02df1d7391b05599fb676ec18 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 14 Aug 2015 11:05:52 -0700 Subject: ipv6: Remove un-used argument from ip6_dst_alloc() After 4b32b5ad31a6 ("ipv6: Stop rt6_info from using inet_peer's metrics"), ip6_dst_alloc() does not need the 'table' argument. This patch cleans it up. Signed-off-by: Martin KaFai Lau CC: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 9de4d2b..c95c319 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -318,8 +318,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = { /* allocate dst with ip6_dst_ops */ static struct rt6_info *__ip6_dst_alloc(struct net *net, struct net_device *dev, - int flags, - struct fib6_table *table) + int flags) { struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0, DST_OBSOLETE_FORCE_CHK, flags); @@ -336,10 +335,9 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net, static struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev, - int flags, - struct fib6_table *table) + int flags) { - struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table); + struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags); if (rt) { rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC); @@ -950,8 +948,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) ort = (struct rt6_info *)ort->dst.from; - rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, - 0, ort->rt6i_table); + rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0); if (!rt) return NULL; @@ -983,8 +980,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) struct rt6_info *pcpu_rt; pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev), - rt->dst.dev, rt->dst.flags, - rt->rt6i_table); + rt->dst.dev, rt->dst.flags); if (!pcpu_rt) return NULL; @@ -1555,7 +1551,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, if (unlikely(!idev)) return ERR_PTR(-ENODEV); - rt = ip6_dst_alloc(net, dev, 0, NULL); + rt = ip6_dst_alloc(net, dev, 0); if (unlikely(!rt)) { in6_dev_put(idev); dst = ERR_PTR(-ENOMEM); @@ -1742,7 +1738,8 @@ int ip6_route_add(struct fib6_config *cfg) if (!table) goto out; - rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table); + rt = ip6_dst_alloc(net, NULL, + (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT); if (!rt) { err = -ENOMEM; @@ -2399,7 +2396,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, { struct net *net = dev_net(idev->dev); struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, - DST_NOCOUNT, NULL); + DST_NOCOUNT); if (!rt) return ERR_PTR(-ENOMEM); -- cgit v0.10.2 From a73e4195636c17f310b8530643a576f42b82385f Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 14 Aug 2015 11:05:53 -0700 Subject: ipv6: Add rt6_make_pcpu_route() It is a prep work for fixing a potential deadlock when creating a pcpu rt. The current rt6_get_pcpu_route() will also create a pcpu rt if one does not exist. This patch moves the pcpu rt creation logic into another function, rt6_make_pcpu_route(). Signed-off-by: Martin KaFai Lau CC: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c95c319..0a82653 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -993,13 +993,21 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) /* It should be called with read_lock_bh(&tb6_lock) acquired */ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) { - struct rt6_info *pcpu_rt, *prev, **p; + struct rt6_info *pcpu_rt, **p; p = this_cpu_ptr(rt->rt6i_pcpu); pcpu_rt = *p; - if (pcpu_rt) - goto done; + if (pcpu_rt) { + dst_hold(&pcpu_rt->dst); + rt6_dst_from_metrics_check(pcpu_rt); + } + return pcpu_rt; +} + +static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt) +{ + struct rt6_info *pcpu_rt, *prev, **p; pcpu_rt = ip6_rt_pcpu_alloc(rt); if (!pcpu_rt) { @@ -1009,6 +1017,7 @@ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) goto done; } + p = this_cpu_ptr(rt->rt6i_pcpu); prev = cmpxchg(p, NULL, pcpu_rt); if (prev) { /* If someone did it before us, return prev instead */ @@ -1093,8 +1102,11 @@ redo_rt6_select: rt->dst.lastuse = jiffies; rt->dst.__use++; pcpu_rt = rt6_get_pcpu_route(rt); - read_unlock_bh(&table->tb6_lock); + if (!pcpu_rt) + pcpu_rt = rt6_make_pcpu_route(rt); + + read_unlock_bh(&table->tb6_lock); return pcpu_rt; } } -- cgit v0.10.2 From 9c7370a166b4e157137bfbfe2ad296d57147547c Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 14 Aug 2015 11:05:54 -0700 Subject: ipv6: Fix a potential deadlock when creating pcpu rt rt6_make_pcpu_route() is called under read_lock(&table->tb6_lock). rt6_make_pcpu_route() calls ip6_rt_pcpu_alloc(rt) which then calls dst_alloc(). dst_alloc() _may_ call ip6_dst_gc() which takes the write_lock(&tabl->tb6_lock). A visualized version: read_lock(&table->tb6_lock); rt6_make_pcpu_route(); => ip6_rt_pcpu_alloc(); => dst_alloc(); => ip6_dst_gc(); => write_lock(&table->tb6_lock); /* oops */ The fix is to do a read_unlock first before calling ip6_rt_pcpu_alloc(). A reported stack: [141625.537638] INFO: rcu_sched self-detected stall on CPU { 27} (t=60000 jiffies g=4159086 c=4159085 q=2139) [141625.547469] Task dump for CPU 27: [141625.550881] mtr R running task 0 22121 22081 0x00000008 [141625.558069] 0000000000000000 ffff88103f363d98 ffffffff8106e488 000000000000001b [141625.565641] ffffffff81684900 ffff88103f363db8 ffffffff810702b0 0000000008000000 [141625.573220] ffffffff81684900 ffff88103f363de8 ffffffff8108df9f ffff88103f375a00 [141625.580803] Call Trace: [141625.583345] [] sched_show_task+0xc1/0xc6 [141625.589650] [] dump_cpu_task+0x35/0x39 [141625.595144] [] rcu_dump_cpu_stacks+0x6a/0x8c [141625.601320] [] rcu_check_callbacks+0x1f6/0x5d4 [141625.607669] [] update_process_times+0x2a/0x4f [141625.613925] [] tick_sched_handle+0x32/0x3e [141625.619923] [] tick_sched_timer+0x35/0x5c [141625.625830] [] __hrtimer_run_queues+0x8f/0x18d [141625.632171] [] hrtimer_interrupt+0xa0/0x166 [141625.638258] [] local_apic_timer_interrupt+0x4e/0x52 [141625.645036] [] smp_apic_timer_interrupt+0x39/0x4a [141625.651643] [] apic_timer_interrupt+0x68/0x70 [141625.657895] [] ? dst_destroy+0x7c/0xb5 [141625.664188] [] ? fib6_flush_trees+0x20/0x20 [141625.670272] [] ? queue_write_lock_slowpath+0x60/0x6f [141625.677140] [] _raw_write_lock_bh+0x23/0x25 [141625.683218] [] __fib6_clean_all+0x40/0x82 [141625.689124] [] ? fib6_flush_trees+0x20/0x20 [141625.695207] [] fib6_clean_all+0xe/0x10 [141625.700854] [] fib6_run_gc+0x79/0xc8 [141625.706329] [] ip6_dst_gc+0x85/0xf9 [141625.711718] [] dst_alloc+0x55/0x159 [141625.717105] [] __ip6_dst_alloc.isra.32+0x19/0x63 [141625.723620] [] ip6_pol_route+0x36a/0x3e8 [141625.729441] [] ip6_pol_route_output+0x11/0x13 [141625.735700] [] fib6_rule_action+0xa7/0x1bf [141625.741698] [] ? ip6_pol_route_input+0x17/0x17 [141625.748043] [] fib_rules_lookup+0xb5/0x12a [141625.754050] [] ? poll_select_copy_remaining+0xf9/0xf9 [141625.761002] [] fib6_rule_lookup+0x37/0x5c [141625.766914] [] ? ip6_pol_route_input+0x17/0x17 [141625.773260] [] ip6_route_output+0x7a/0x82 [141625.779177] [] ip6_dst_lookup_tail+0x53/0x112 [141625.785437] [] ip6_dst_lookup_flow+0x2a/0x6b [141625.791604] [] rawv6_sendmsg+0x407/0x9b6 [141625.797423] [] ? do_ipv6_setsockopt.isra.8+0xd87/0xde2 [141625.804464] [] inet_sendmsg+0x57/0x8e [141625.810028] [] sock_sendmsg+0x2e/0x3c [141625.815588] [] SyS_sendto+0xfe/0x143 [141625.821063] [] ? rawv6_setsockopt+0x5e/0x67 [141625.827146] [] ? sock_common_setsockopt+0xf/0x11 [141625.833660] [] ? SyS_setsockopt+0x81/0xa2 [141625.839565] [] entry_SYSCALL_64_fastpath+0x12/0x6a Fixes: d52d3997f843 ("pv6: Create percpu rt6_info") Signed-off-by: Martin KaFai Lau CC: Hannes Frederic Sowa Reported-by: Steinar H. Gunderson Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 55d1986..548c623 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -172,6 +172,8 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) *ppcpu_rt = NULL; } } + + non_pcpu_rt->rt6i_pcpu = NULL; } static void rt6_release(struct rt6_info *rt) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0a82653..d155864 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1007,27 +1007,39 @@ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt) { + struct fib6_table *table = rt->rt6i_table; struct rt6_info *pcpu_rt, *prev, **p; pcpu_rt = ip6_rt_pcpu_alloc(rt); if (!pcpu_rt) { struct net *net = dev_net(rt->dst.dev); - pcpu_rt = net->ipv6.ip6_null_entry; - goto done; + dst_hold(&net->ipv6.ip6_null_entry->dst); + return net->ipv6.ip6_null_entry; } - p = this_cpu_ptr(rt->rt6i_pcpu); - prev = cmpxchg(p, NULL, pcpu_rt); - if (prev) { - /* If someone did it before us, return prev instead */ + read_lock_bh(&table->tb6_lock); + if (rt->rt6i_pcpu) { + p = this_cpu_ptr(rt->rt6i_pcpu); + prev = cmpxchg(p, NULL, pcpu_rt); + if (prev) { + /* If someone did it before us, return prev instead */ + dst_destroy(&pcpu_rt->dst); + pcpu_rt = prev; + } + } else { + /* rt has been removed from the fib6 tree + * before we have a chance to acquire the read_lock. + * In this case, don't brother to create a pcpu rt + * since rt is going away anyway. The next + * dst_check() will trigger a re-lookup. + */ dst_destroy(&pcpu_rt->dst); - pcpu_rt = prev; + pcpu_rt = rt; } - -done: dst_hold(&pcpu_rt->dst); rt6_dst_from_metrics_check(pcpu_rt); + read_unlock_bh(&table->tb6_lock); return pcpu_rt; } @@ -1103,11 +1115,21 @@ redo_rt6_select: rt->dst.__use++; pcpu_rt = rt6_get_pcpu_route(rt); - if (!pcpu_rt) + if (pcpu_rt) { + read_unlock_bh(&table->tb6_lock); + } else { + /* We have to do the read_unlock first + * because rt6_make_pcpu_route() may trigger + * ip6_dst_gc() which will take the write_lock. + */ + dst_hold(&rt->dst); + read_unlock_bh(&table->tb6_lock); pcpu_rt = rt6_make_pcpu_route(rt); + dst_release(&rt->dst); + } - read_unlock_bh(&table->tb6_lock); return pcpu_rt; + } } -- cgit v0.10.2 From af19e68683ba9c29e778d0f8be5be61a0ebb4166 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Fri, 14 Aug 2015 22:30:01 +0200 Subject: be2net: avoid vxlan offloading on multichannel configs VxLAN offloading is not functional if the NIC is running in multichannel mode (UMC, FLEX-10, VNIC...). Enabling this additionally kills whole connectivity through the NIC and the device needs to be down and up to restore it. The firmware should take care about it and does not allow the conversion of interface to tunnel type (be_cmd_manage_iface) or should support VxLAN offloading if multichannel config is enabled. I have tested this on the latest available firmware (10.6.144.21). Result: [root@sm-04 ~]# ip link set enp5s0f0 up[root@sm-04 ~]# ip addr add 172.30.10.50/24 dev enp5s0f0 [root@sm-04 ~]# ping -c 3 172.30.10.254PING 172.30.10.254 (172.30.10.254) 56(84) bytes of data. 64 bytes from 172.30.10.254: icmp_seq=1 ttl=64 time=0.317 ms 64 bytes from 172.30.10.254: icmp_seq=2 ttl=64 time=0.187 ms 64 bytes from 172.30.10.254: icmp_seq=3 ttl=64 time=0.188 ms --- 172.30.10.254 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.187/0.230/0.317/0.063 ms [root@sm-04 ~]# ip link add link enp5s0f0 vxlan10 type vxlan id 10 remote 172.30.10.60 dstport 4789 [root@sm-04 ~]# ip link set vxlan10 up [ 7900.442811] be2net 0000:05:00.0: Enabled VxLAN offloads for UDP port 4789 [ 7900.455722] be2net 0000:05:00.1: Enabled VxLAN offloads for UDP port 4789 [ 7900.468635] be2net 0000:05:00.2: Enabled VxLAN offloads for UDP port 4789 [ 7900.481553] be2net 0000:05:00.3: Enabled VxLAN offloads for UDP port 4789 [root@sm-04 ~]# ping -c 3 172.30.10.254 PING 172.30.10.254 (172.30.10.254) 56(84) bytes of data. --- 172.30.10.254 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 1999ms [root@sm-04 ~]# ip link set vxlan10 down [ 7959.434093] be2net 0000:05:00.0: Disabled VxLAN offloads for UDP port 4789 [ 7959.444792] be2net 0000:05:00.1: Disabled VxLAN offloads for UDP port 4789 [ 7959.455592] be2net 0000:05:00.2: Disabled VxLAN offloads for UDP port 4789 [ 7959.466416] be2net 0000:05:00.3: Disabled VxLAN offloads for UDP port 4789 [root@sm-04 ~]# ip link del vxlan10 [root@sm-04 ~]# ping -c 3 172.30.10.254 PING 172.30.10.254 (172.30.10.254) 56(84) bytes of data. --- 172.30.10.254 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 1999ms [root@sm-04 ~]# ip link set enp5s0f0 down [root@sm-04 ~]# ip link set enp5s0f0 up [ 8071.019003] be2net 0000:05:00.0 enp5s0f0: Link is Up [root@sm-04 ~]# ping -c 3 172.30.10.254 PING 172.30.10.254 (172.30.10.254) 56(84) bytes of data. 64 bytes from 172.30.10.254: icmp_seq=1 ttl=64 time=0.318 ms 64 bytes from 172.30.10.254: icmp_seq=2 ttl=64 time=0.196 ms 64 bytes from 172.30.10.254: icmp_seq=3 ttl=64 time=0.194 ms --- 172.30.10.254 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.194/0.236/0.318/0.057 ms Cc: Sathya Perla Cc: Ajit Khaparde Cc: Padmanabh Ratnakar Cc: Sriharsha Basavapatna Signed-off-by: Ivan Vecera Acked-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c28e3bf..6ca693b 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5174,7 +5174,7 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family, struct device *dev = &adapter->pdev->dev; int status; - if (lancer_chip(adapter) || BEx_chip(adapter)) + if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter)) return; if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) { @@ -5221,7 +5221,7 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family, { struct be_adapter *adapter = netdev_priv(netdev); - if (lancer_chip(adapter) || BEx_chip(adapter)) + if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter)) return; if (adapter->vxlan_port != port) -- cgit v0.10.2 From a8079092c1bbf9aec3756b35256c7816b8845af7 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sat, 15 Aug 2015 20:12:30 -0400 Subject: net: qmi_wwan: add HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module This is an HP-branded Sierra Wireless EM7355: https://bugzilla.redhat.com/show_bug.cgi?id=1223646#c2 Signed-off-by: David Ward Signed-off-by: David S. Miller diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 9d43460..64a60af 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -785,6 +785,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ /* 4. Gobi 1000 devices */ -- cgit v0.10.2 From ff94c742dfeea3110f1e1d27399d728f8494d29e Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 18 Aug 2015 06:31:42 +0800 Subject: net: phy: fix semicolon.cocci warnings drivers/net/phy/smsc.c:127:3-4: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Igor Plyatov Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index d64f016..70b0895 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -124,7 +124,7 @@ static int lan87xx_read_status(struct phy_device *phydev) return rc; if (rc & MII_LAN83C185_ENERGYON) break; - }; + } /* Re-enable EDPD */ rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); -- cgit v0.10.2 From 512255a2ad2c832ca7d4de9f31245f73781922d0 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 17 Aug 2015 12:22:50 -0700 Subject: Revert "sched/x86_64: Don't save flags on context switch" This reverts commit: 2c7577a75837 ("sched/x86_64: Don't save flags on context switch") It was a nice speedup. It's also not quite correct: SYSENTER enables interrupts too early. We can re-add this optimization once the SYSENTER code is beaten into shape, which should happen in 4.3 or 4.4. Signed-off-by: Andy Lutomirski Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org # v3.19 Link: http://lkml.kernel.org/r/85f56651f59f76624e80785a8fd3bdfdd089a818.1439838962.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h index 751bf4b..d7f3b3b 100644 --- a/arch/x86/include/asm/switch_to.h +++ b/arch/x86/include/asm/switch_to.h @@ -79,12 +79,12 @@ do { \ #else /* CONFIG_X86_32 */ /* frame pointer must be last for get_wchan */ -#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t" -#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t" +#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t" +#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t" #define __EXTRA_CLOBBER \ , "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \ - "r12", "r13", "r14", "r15", "flags" + "r12", "r13", "r14", "r15" #ifdef CONFIG_CC_STACKPROTECTOR #define __switch_canary \ @@ -100,11 +100,7 @@ do { \ #define __switch_canary_iparam #endif /* CC_STACKPROTECTOR */ -/* - * There is no need to save or restore flags, because flags are always - * clean in kernel mode, with the possible exception of IOPL. Kernel IOPL - * has no effect. - */ +/* Save restore flags to clear handle leaking NT */ #define switch_to(prev, next, last) \ asm volatile(SAVE_CONTEXT \ "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \ -- cgit v0.10.2 From dbb3df2d58754e4df58620e60370d166c2cb6744 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 14 Aug 2015 13:58:20 +0200 Subject: drm/atmel-hlcdc: Compile suspend/resume for PM_SLEEP only If PM is enabled but PM_SLEEP is disabled, the suspend/resume functions are still unused and produce a compiler warning. Signed-off-by: Thierry Reding Signed-off-by: Boris Brezillon Cc: # 4.1+ diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 6fad1f9..ef6182b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -559,7 +559,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int atmel_hlcdc_dc_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); -- cgit v0.10.2 From 158d3b2ad18ca4570c9929b9b31d298d86fa2c02 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Aug 2015 11:25:50 +0200 Subject: MIPS: Fix LLVM build issue. Matthew Fortune reports: The genex.S file appears to mix the case of a macro between its definition and use. A cut down example of this is below. The macro __build_clear_none has lower case 'build' but ends up being instantiated with upper case BUILD. Can this be fixed on master. It has been picked up by the LLVM integrated assembler which is currently case sensitive. We are likely to fix the assembler as well but the code is currently inconsistent in the kernel. .macro __build_clear_none .endm .macro __BUILD_HANDLER exception handler clear verbose ext .align 5 .globl handle_\exception; .align 2; .type handle_\exception, @function; .ent handle_\exception, 0; handle_\exception: .frame $29, 184, $29 .set noat .globl handle_\exception\ext; .type handle_\exception\ext, @function; handle_\exception\ext: __BUILD_clear_\clear .endm .macro BUILD_HANDLER exception handler clear verbose __BUILD_HANDLER \exception \handler \clear \verbose _int .endm BUILD_HANDLER ftlb ftlb none silent Signed-off-by: Ralf Baechle Reported-by: Matthew Fortune diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index af42e70..baa7b6f 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -407,7 +407,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .set noat SAVE_ALL FEXPORT(handle_\exception\ext) - __BUILD_clear_\clear + __build_clear_\clear .set at __BUILD_\verbose \exception move a0, sp -- cgit v0.10.2 From 0f64b247e63ac8c214efa6725366b42563ab138c Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 12 Aug 2015 16:45:02 +0100 Subject: ARM: 8414/1: __copy_to_user_memcpy: fix mmap semaphore usage The mmap semaphore should not be taken when page faults are disabled. Since pagefault_disable() no longer disables preemption, we now need to use faulthandler_disabled() in place of in_atomic(). Signed-off-by: Nicolas Pitre Tested-by: Mark Salter Signed-off-by: Russell King diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 3e58d71..4b39af2 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -96,7 +96,7 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) } /* the mmap semaphore is taken only if not in an atomic context */ - atomic = in_atomic(); + atomic = faulthandler_disabled(); if (!atomic) down_read(¤t->mm->mmap_sem); -- cgit v0.10.2 From 3939f3345050b1ace675675c47d99fd7b606d9e3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 17 Aug 2015 04:03:33 +0100 Subject: ARM: 8418/1: add boot image dependencies to not generate invalid images U-Boot is often used to boot the kernel on ARM boards, but uImage is not built by "make all", so we are often inclined to do "make all uImage" to generate DTBs, modules and uImage in a single command, but we should notice a pitfall behind it. In fact, "make all uImage" could generate an invalid uImage if it is run with the parallel option (-j). You can reproduce this problem with the following procedure: [1] First, build "all" and "uImage" separately. You will get a valid uImage $ git clean -f -x -d $ export CROSS_COMPILE= $ make -s -j8 ARCH=arm multi_v7_defconfig $ make -s -j8 ARCH=arm all $ make -j8 ARCH=arm UIMAGE_LOADADDR=0x80208000 uImage CHK include/config/kernel.release CHK include/generated/uapi/linux/version.h CHK include/generated/utsrelease.h make[1]: `include/generated/mach-types.h' is up to date. CHK include/generated/timeconst.h CHK include/generated/bounds.h CHK include/generated/asm-offsets.h CALL scripts/checksyscalls.sh CHK include/generated/compile.h Kernel: arch/arm/boot/Image is ready Kernel: arch/arm/boot/zImage is ready UIMAGE arch/arm/boot/uImage Image Name: Linux-4.2.0-rc5-00156-gdd2384a-d Created: Sat Aug 8 23:21:35 2015 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 6138648 Bytes = 5994.77 kB = 5.85 MB Load Address: 80208000 Entry Point: 80208000 Image arch/arm/boot/uImage is ready $ ls -l arch/arm/boot/*Image -rwxrwxr-x 1 masahiro masahiro 13766656 Aug 8 23:20 arch/arm/boot/Image -rw-rw-r-- 1 masahiro masahiro 6138712 Aug 8 23:21 arch/arm/boot/uImage -rwxrwxr-x 1 masahiro masahiro 6138648 Aug 8 23:20 arch/arm/boot/zImage [2] Update some source file(s) $ touch init/main.c [3] Then, re-build "all" and "uImage" simultaneously. You will get an invalid uImage at random. $ make -j8 ARCH=arm UIMAGE_LOADADDR=0x80208000 all uImage CHK include/config/kernel.release CHK include/generated/uapi/linux/version.h CHK include/generated/utsrelease.h make[1]: `include/generated/mach-types.h' is up to date. CHK include/generated/timeconst.h CHK include/generated/bounds.h CHK include/generated/asm-offsets.h CALL scripts/checksyscalls.sh CC init/main.o CHK include/generated/compile.h LD init/built-in.o LINK vmlinux LD vmlinux.o MODPOST vmlinux.o GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o LD init/built-in.o KSYM .tmp_kallsyms1.o KSYM .tmp_kallsyms2.o LD vmlinux SORTEX vmlinux SYSMAP System.map OBJCOPY arch/arm/boot/Image Building modules, stage 2. Kernel: arch/arm/boot/Image is ready GZIP arch/arm/boot/compressed/piggy.gzip AS arch/arm/boot/compressed/piggy.gzip.o Kernel: arch/arm/boot/Image is ready LD arch/arm/boot/compressed/vmlinux GZIP arch/arm/boot/compressed/piggy.gzip OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready UIMAGE arch/arm/boot/uImage Image Name: Linux-4.2.0-rc5-00156-gdd2384a-d Created: Sat Aug 8 23:23:14 2015 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 26472 Bytes = 25.85 kB = 0.03 MB Load Address: 80208000 Entry Point: 80208000 Image arch/arm/boot/uImage is ready MODPOST 192 modules AS arch/arm/boot/compressed/piggy.gzip.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready $ ls -l arch/arm/boot/*Image -rwxrwxr-x 1 masahiro masahiro 13766656 Aug 8 23:23 arch/arm/boot/Image -rw-rw-r-- 1 masahiro masahiro 26536 Aug 8 23:23 arch/arm/boot/uImage -rwxrwxr-x 1 masahiro masahiro 6138648 Aug 8 23:23 arch/arm/boot/zImage Please notice the uImage is extremely small when this issue is encountered. Besides, "Kernel: arch/arm/boot/zImage is ready" is displayed twice, before and after the uImage log. The root cause of this is the race condition between zImage and uImage. Actually, uImage depends on zImage, but the dependency between the two is only described in arch/arm/boot/Makefile. Because arch/arm/boot/Makefile is not included from the top-level Makefile, it cannot know the dependency between zImage and uImage. Consequently, when we run make with the parallel option, Kbuild updates vmlinux first, and then two different threads descends into the arch/arm/boot/Makefile almost at the same time, one for updating zImage and the other for uImage. While one thread is re-generating zImage, the other also tries to update zImage before creating uImage on top of that. zImage is overwritten by the slower thread and then uImage is created based on the half-written zImage. This is the reason why "Kernel: arch/arm/boot/zImage is ready" is displayed twice, and a broken uImage is created. The same problem could happen on bootpImage. This commit adds dependencies among Image, zImage, uImage, and bootpImage to arch/arm/Makefile, which is included from the top-level Makefile. Signed-off-by: Masahiro Yamada Signed-off-by: Russell King diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 07ab3d2..7451b44 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -312,6 +312,9 @@ INSTALL_TARGETS = zinstall uinstall install PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS) +bootpImage uImage: zImage +zImage: Image + $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ -- cgit v0.10.2 From d0023a1448abdcc892b8bca631e74bb1888efd02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 17 Aug 2015 10:18:48 -0700 Subject: timer: Write timer->flags atomically lock_timer_base() cannot prevent the following : CPU1 ( in __mod_timer() timer->flags |= TIMER_MIGRATING; spin_unlock(&base->lock); base = new_base; spin_lock(&base->lock); // The next line clears TIMER_MIGRATING timer->flags &= ~TIMER_BASEMASK; CPU2 (in lock_timer_base()) see timer base is cpu0 base spin_lock_irqsave(&base->lock, *flags); if (timer->flags == tf) return base; // oops, wrong base timer->flags |= base->cpu // too late We must write timer->flags in one go, otherwise we can fool other cpus. Fixes: bc7a34b8b9eb ("timer: Reduce timer migration overhead if disabled") Signed-off-by: Eric Dumazet Cc: Jon Christopherson Cc: David Miller Cc: xen-devel@lists.xen.org Cc: david.vrabel@citrix.com Cc: Sander Eikelenboom Link: http://lkml.kernel.org/r/1439831928.32680.11.camel@edumazet-glaptop2.roam.corp.google.com Signed-off-by: Thomas Gleixner Cc: Thomas Gleixner diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 5e097fa..84190f0 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -807,8 +807,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, spin_unlock(&base->lock); base = new_base; spin_lock(&base->lock); - timer->flags &= ~TIMER_BASEMASK; - timer->flags |= base->cpu; + WRITE_ONCE(timer->flags, + (timer->flags & ~TIMER_BASEMASK) | base->cpu); } } -- cgit v0.10.2 From db196935d9562abec4510f48d887bc1f1e054fcf Mon Sep 17 00:00:00 2001 From: Hiral Shah Date: Tue, 14 Jul 2015 07:08:57 -0700 Subject: fnic: Use the local variable instead of I/O flag to acquire io_req_lock in fnic_queuecommand() to avoid deadloack We added changes in fnic driver patch 1.6.0.16 to acquire io_req_lock in fnic_queuecommand() before issuing I/O so that io completion is serialized. But when releasing the lock we check for the I/O flag and this could be modified if IO abort occurs before I/O completion. In this case we wont release the lock and causes deadlock in some scenerios. Using the local variable to check the IO lock status will resolve the problem. Fixes: 41df7b02db82cf6c14f094757bac3830d10a827f Signed-off-by: Hiral Shah Signed-off-by: Sesidhar Baddela Signed-off-by: Anil Chintalapati Reviewed-by: Martin K. Petersen Cc: stable@vger.kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 26270c3..ce129e5 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -39,7 +39,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.17" +#define DRV_VERSION "1.6.0.17a" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 155b286..25436cd 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -425,6 +425,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ unsigned long ptr; struct fc_rport_priv *rdata; spinlock_t *io_lock = NULL; + int io_lock_acquired = 0; if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) return SCSI_MLQUEUE_HOST_BUSY; @@ -518,6 +519,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ spin_lock_irqsave(io_lock, flags); /* initialize rest of io_req */ + io_lock_acquired = 1; io_req->port_id = rport->port_id; io_req->start_time = jiffies; CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; @@ -571,7 +573,7 @@ out: (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc))); /* if only we issued IO, will we have the io lock */ - if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED) + if (io_lock_acquired) spin_unlock_irqrestore(io_lock, flags); atomic_dec(&fnic->in_flight); -- cgit v0.10.2 From 49718f0fb8c9af192b33d8af3a2826db04025371 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 17 Aug 2015 11:02:42 -0400 Subject: SCSI: Fix NULL pointer dereference in runtime PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The routines in scsi_rpm.c assume that if a runtime-PM callback is invoked for a SCSI device, it can only mean that the device's driver has asked the block layer to handle the runtime power management (by calling blk_pm_runtime_init(), which among other things sets q->dev). However, this assumption turns out to be wrong for things like the ses driver. Normally ses devices are not allowed to do runtime PM, but userspace can override this setting. If this happens, the kernel gets a NULL pointer dereference when blk_post_runtime_resume() tries to use the uninitialized q->dev pointer. This patch fixes the problem by calling the block layer's runtime-PM routines only if the device's driver really does have a runtime-PM callback routine. Since ses doesn't define any such callbacks, the crash won't occur. This fixes Bugzilla #101371. Signed-off-by: Alan Stern Reported-by: Stanisław Pitucha Reported-by: Ilan Cohen Tested-by: Ilan Cohen Reviewed-by: Johannes Thumshirn Cc: stable@vger.kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 9e43ae1..e4b7998 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -217,15 +217,15 @@ static int sdev_runtime_suspend(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; struct scsi_device *sdev = to_scsi_device(dev); - int err; + int err = 0; - err = blk_pre_runtime_suspend(sdev->request_queue); - if (err) - return err; - if (pm && pm->runtime_suspend) + if (pm && pm->runtime_suspend) { + err = blk_pre_runtime_suspend(sdev->request_queue); + if (err) + return err; err = pm->runtime_suspend(dev); - blk_post_runtime_suspend(sdev->request_queue, err); - + blk_post_runtime_suspend(sdev->request_queue, err); + } return err; } @@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int err = 0; - blk_pre_runtime_resume(sdev->request_queue); - if (pm && pm->runtime_resume) + if (pm && pm->runtime_resume) { + blk_pre_runtime_resume(sdev->request_queue); err = pm->runtime_resume(dev); - blk_post_runtime_resume(sdev->request_queue, err); - + blk_post_runtime_resume(sdev->request_queue, err); + } return err; } -- cgit v0.10.2 From 527f0a91e91cd55ec79fce80451b0ad5d5e6a21a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 18 Aug 2015 23:20:20 +0800 Subject: x86/irq: Build correct vector mapping for multiple MSI interrupts Alex Deucher, Mark Rustad and Alexander Holler reported a regression with the latest v4.2-rc4 kernel, which breaks some SATA controllers. With multi-MSI capable SATA controllers, only the first port works, all other ports time out when executing SATA commands. This happens because the first argument to assign_irq_vector_policy() is always the base linux irq number of the multi MSI interrupt block, so all subsequent vector assignments operate on the base linux irq number, so all MSI irqs are handled as the first irq number. Therefor the other MSI irqs of a device are never set up correctly and never fire. Add the loop iterator to the base irq number so all vectors are assigned correctly. Fixes: b5dc8e6c21e7 "x86/irq: Use hierarchical irqdomain to manage CPU interrupt vectors" Reported-and-tested-by: Alex Deucher Reported-and-tested-by: Mark Rustad Reported-and-tested-by: Alexander Holler Signed-off-by: Jiang Liu Cc: Tony Luck Link: http://lkml.kernel.org/r/1439911228-9880-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index f813261..2683f36 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -322,7 +322,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, irq_data->chip = &lapic_controller; irq_data->chip_data = data; irq_data->hwirq = virq + i; - err = assign_irq_vector_policy(virq, irq_data->node, data, + err = assign_irq_vector_policy(virq + i, irq_data->node, data, info); if (err) goto error; -- cgit v0.10.2 From 84eac6196c4b3930fc81f9bcd76c4a1a2161fd34 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Aug 2015 17:58:01 +0800 Subject: ASoC: wm8741: Drop misleading readable_reg callback implementation regmap_readable() returns false if map->format.format_write is set. For .reg_bits = 7, .val_bits = 9, setting, map->format.format_write = regmap_format_7_9_write; Even current code has implemented map->readable_reg, regmap_readable() still returns false anyway. Thus drop the misleading readable_reg callback implementation. Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 506792b..c24c1a3 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -61,25 +61,6 @@ static const struct reg_default wm8741_reg_defaults[] = { { 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */ }; -static bool wm8741_readable(struct device *dev, unsigned int reg) -{ - switch (reg) { - case WM8741_DACLLSB_ATTENUATION: - case WM8741_DACLMSB_ATTENUATION: - case WM8741_DACRLSB_ATTENUATION: - case WM8741_DACRMSB_ATTENUATION: - case WM8741_VOLUME_CONTROL: - case WM8741_FORMAT_CONTROL: - case WM8741_FILTER_CONTROL: - case WM8741_MODE_CONTROL_1: - case WM8741_MODE_CONTROL_2: - case WM8741_ADDITIONAL_CONTROL_1: - return true; - default: - return false; - } -} - static int wm8741_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, WM8741_RESET, 0); @@ -541,8 +522,6 @@ static const struct regmap_config wm8741_regmap = { .reg_defaults = wm8741_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), .cache_type = REGCACHE_RBTREE, - - .readable_reg = wm8741_readable, }; static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741) -- cgit v0.10.2 From 1d15f21dc8030c4511964819b89b50e39d5a7013 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 18 Aug 2015 17:26:45 +0530 Subject: ASoC: tegra: Revert part of "ASoC: tegra: Convert to managed resources" Revert the problematic part of commit 470805eb9f31 ("ASoC: tegra: Convert to managed resources"). Before this commit, PM cleanup was performed after the component was unregistered. But returning directly will skip PM cleanup. So, to be on safe side it is better to use snd_soc_register_component instead of devm_snd_soc_register_component. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index a814da0..66237bc 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -329,9 +329,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = devm_snd_soc_register_component(&pdev->dev, - &tegra20_spdif_component, - &tegra20_spdif_dai, 1); + ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, + &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; @@ -341,11 +340,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) ret = tegra_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - return ret; + goto err_unregister_component; } return 0; +err_unregister_component: + snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); @@ -364,6 +365,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev) tegra20_spdif_runtime_suspend(&pdev->dev); tegra_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From fd7dec25a18f495e50d2040398fd263836ff3b28 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 18 Aug 2015 13:37:01 +0200 Subject: batman-adv: Fix memory leak on tt add with invalid vlan The object tt_local is allocated with kmalloc and not initialized when the function batadv_tt_local_add checks for the vlan. But this function can only cleanup the object when the (not yet initialized) reference counter of the object is 1. This is unlikely and thus the object would leak when the vlan could not be found. Instead the uninitialized object tt_local has to be freed manually and the pointer has to set to NULL to avoid calling the function which would try to decrement the reference counter of the not existing object. CID: 1316518 Fixes: 354136bcc3c4 ("batman-adv: fix kernel crash due to missing NULL checks") Signed-off-by: Sven Eckelmann Signed-off-by: David S. Miller diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5e953297..5809b39 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -595,8 +595,11 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, /* increase the refcounter of the related vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", - addr, BATADV_PRINT_VID(vid))) + addr, BATADV_PRINT_VID(vid))) { + kfree(tt_local); + tt_local = NULL; goto out; + } batadv_dbg(BATADV_DBG_TT, bat_priv, "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", -- cgit v0.10.2 From 0f69a38737538c8a265f75d26996818f98c899e4 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 13 Aug 2015 21:59:19 -0700 Subject: target: Fix handling of small allocation lengths in REPORT LUNS REPORT LUNS should not fail just because the allocation length is less than 16. The relevant section of SPC-4 is: 4.2.5.6 Allocation length The ALLOCATION LENGTH field specifies the maximum number of bytes or blocks that an application client has allocated in the Data-In Buffer. The ALLOCATION LENGTH field specifies bytes unless a different requirement is stated in the command definition. An allocation length of zero specifies that no data shall be transferred. This condition shall not be considered an error. So we should just truncate our response rather than return an error. Signed-off-by: Roland Dreier Signed-off-by: Spencer Baugh Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 556ea1b..f87d4ce 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1203,17 +1203,13 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) struct se_dev_entry *deve; struct se_session *sess = cmd->se_sess; struct se_node_acl *nacl; + struct scsi_lun slun; unsigned char *buf; u32 lun_count = 0, offset = 8; - - if (cmd->data_length < 16) { - pr_warn("REPORT LUNS allocation length %u too small\n", - cmd->data_length); - return TCM_INVALID_CDB_FIELD; - } + __be32 len; buf = transport_kmap_data_sg(cmd); - if (!buf) + if (cmd->data_length && !buf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; /* @@ -1234,10 +1230,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) * See SPC2-R20 7.19. */ lun_count++; - if ((offset + 8) > cmd->data_length) + if (offset >= cmd->data_length) continue; - int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); + int_to_scsilun(deve->mapped_lun, &slun); + memcpy(buf + offset, &slun, + min(8u, cmd->data_length - offset)); offset += 8; } rcu_read_unlock(); @@ -1250,16 +1248,18 @@ done: * If no LUNs are accessible, report virtual LUN 0. */ if (lun_count == 0) { - int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); + int_to_scsilun(0, &slun); + if (cmd->data_length > 8) + memcpy(buf + offset, &slun, + min(8u, cmd->data_length - offset)); lun_count = 1; } - lun_count *= 8; - buf[0] = ((lun_count >> 24) & 0xff); - buf[1] = ((lun_count >> 16) & 0xff); - buf[2] = ((lun_count >> 8) & 0xff); - buf[3] = (lun_count & 0xff); - transport_kunmap_data_sg(cmd); + if (buf) { + len = cpu_to_be32(lun_count * 8); + memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length)); + transport_kunmap_data_sg(cmd); + } target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8); return 0; -- cgit v0.10.2 From bf1a5fd2eccf20b19941b8461ce9c90899054bd5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 18 Aug 2015 12:33:36 +0300 Subject: Revert "drm/i915: Allow parsing of variable size child device entries from VBT" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 047fe6e6db9161e69271f56daaafdaf2add023b1 Author: David Weinehall Date: Tue Aug 4 16:55:52 2015 +0300 drm/i915: Allow parsing of variable size child device entries from VBT That commit is not valid for v4.2, however it will be valid for v4.3. It was simply queued too early. The referenced regressing commit is just fine until the size of struct common_child_dev_config changes, and that won't happen until v4.3. Indeed, the expected size checks here rely on the increased size of the struct, breaking new platforms. Fixes: 047fe6e6db91 ("drm/i915: Allow parsing of variable size child device entries from VBT") Cc: Daniel Vetter Cc: David Weinehall Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 3dcd59e..198fc3c 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1075,34 +1075,15 @@ parse_device_mapping(struct drm_i915_private *dev_priv, const union child_device_config *p_child; union child_device_config *child_dev_ptr; int i, child_device_num, count; - u8 expected_size; - u16 block_size; + u16 block_size; p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (!p_defs) { DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); return; } - if (bdb->version < 195) { - expected_size = 33; - } else if (bdb->version == 195) { - expected_size = 37; - } else if (bdb->version <= 197) { - expected_size = 38; - } else { - expected_size = 38; - DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n", - expected_size, bdb->version); - } - - if (expected_size > sizeof(*p_child)) { - DRM_ERROR("child_device_config cannot fit in p_child\n"); - return; - } - - if (p_defs->child_dev_size != expected_size) { - DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n", - p_defs->child_dev_size, expected_size, bdb->version); + if (p_defs->child_dev_size < sizeof(*p_child)) { + DRM_ERROR("General definiton block child device size is too small.\n"); return; } /* get the block size of general definitions */ @@ -1149,7 +1130,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, child_dev_ptr = dev_priv->vbt.child_dev + count; count++; - memcpy(child_dev_ptr, p_child, p_defs->child_dev_size); + memcpy(child_dev_ptr, p_child, sizeof(*p_child)); } return; } -- cgit v0.10.2 From 33747cc5ec036036ae3088d02982d3571c7d8500 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Tue, 18 Aug 2015 11:07:56 +0530 Subject: Revert "drm/i915: Add eDP intermediate frequencies for CHV" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fe51bfb95c996733150c44d21e1c9f4b6322a326. Author: Ville Syrjälä Date: Thu Mar 12 17:10:38 2015 +0200 CHV does not support intermediate frequencies so reverting the patch that added it in the first place Cc: stable@vger.kernel.org # v4.1+ Reviewed-by: Ville Syrjälä Signed-off-by: Sivakumar Thulasimani Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6e8faa2..6c8bf34 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -93,9 +93,6 @@ static const struct dp_link_dpll chv_dpll[] = { static const int skl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000 }; -static const int chv_rates[] = { 162000, 202500, 210000, 216000, - 243000, 270000, 324000, 405000, - 420000, 432000, 540000 }; static const int default_rates[] = { 162000, 270000, 540000 }; /** @@ -1175,9 +1172,6 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) if (IS_SKYLAKE(dev)) { *source_rates = skl_rates; return ARRAY_SIZE(skl_rates); - } else if (IS_CHERRYVIEW(dev)) { - *source_rates = chv_rates; - return ARRAY_SIZE(chv_rates); } *source_rates = default_rates; -- cgit v0.10.2 From 5e86dfe39f54ab13fd8079ac3d6cb100318909a3 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Tue, 18 Aug 2015 11:07:57 +0530 Subject: drm/i915: remove HBR2 from chv supported list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes 5.4Gbps from supported link rate for CHV since it is not supported in it. v2: change the ordering for better readability (Ville) Cc: stable@vger.kernel.org # v4.1+ Reviewed-by: Ville Syrjälä Signed-off-by: Sivakumar Thulasimani Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6c8bf34..7ad0e0b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1176,11 +1176,12 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) *source_rates = default_rates; + /* WaDisableHBR2:skl */ if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) - /* WaDisableHBR2:skl */ return (DP_LINK_BW_2_7 >> 3) + 1; - else if (INTEL_INFO(dev)->gen >= 8 || - (IS_HASWELL(dev) && !IS_HSW_ULX(dev))) + + if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || + (INTEL_INFO(dev)->gen >= 9)) return (DP_LINK_BW_5_4 >> 3) + 1; else return (DP_LINK_BW_2_7 >> 3) + 1; -- cgit v0.10.2 From ed63baaf849e91c84ac3e042b1fd6a0af07c16f3 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Tue, 18 Aug 2015 15:30:37 +0530 Subject: drm/i915: Avoid TP3 on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes TP3 support on CHV since there is no support for HBR2 on this platform. v2: rename the function to indicate it checks source rates (Jani) v3: update comment to indicate TP3 dependency on HBR2 supported hardware (Jani) Cc: stable@vger.kernel.org # v4.1+ Reviewed-by: Ville Syrjälä Signed-off-by: Sivakumar Thulasimani [Jani: fixed a couple of checkpatch warnings.] Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7ad0e0b..1df0e1f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1166,6 +1166,19 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) return (intel_dp_max_link_bw(intel_dp) >> 3) + 1; } +static bool intel_dp_source_supports_hbr2(struct drm_device *dev) +{ + /* WaDisableHBR2:skl */ + if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) + return false; + + if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || + (INTEL_INFO(dev)->gen >= 9)) + return true; + else + return false; +} + static int intel_dp_source_rates(struct drm_device *dev, const int **source_rates) { @@ -1176,12 +1189,8 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) *source_rates = default_rates; - /* WaDisableHBR2:skl */ - if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) - return (DP_LINK_BW_2_7 >> 3) + 1; - - if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || - (INTEL_INFO(dev)->gen >= 9)) + /* This depends on the fact that 5.4 is last value in the array */ + if (intel_dp_source_supports_hbr2(dev)) return (DP_LINK_BW_5_4 >> 3) + 1; else return (DP_LINK_BW_2_7 >> 3) + 1; @@ -3936,10 +3945,15 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) } } - /* Training Pattern 3 support, both source and sink */ + /* Training Pattern 3 support, Intel platforms that support HBR2 alone + * have support for TP3 hence that check is used along with dpcd check + * to ensure TP3 can be enabled. + * SKL < B0: due it's WaDisableHBR2 is the only exception where TP3 is + * supported but still not enabled. + */ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 && intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED && - (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)) { + intel_dp_source_supports_hbr2(dev)) { intel_dp->use_tps3 = true; DRM_DEBUG_KMS("Displayport TPS3 supported\n"); } else -- cgit v0.10.2 From 23f28f2adcf608170c9062b1f490c4f0dcc995e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:31 -0300 Subject: Revert "[media] rc: nuvoton-cir: Add support for writing wakeup samples via sysfs filter callback" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit da7ee60b03bd66bb10974d7444aa444de6391312. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index baeb597..85af7a8 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -526,130 +526,6 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) return 0; } -static int nvt_write_wakeup_codes(struct rc_dev *dev, - const u8 *wakeup_sample_buf, int count) -{ - int i = 0; - u8 reg, reg_learn_mode; - unsigned long flags; - struct nvt_dev *nvt = dev->priv; - - nvt_dbg_wake("writing wakeup samples"); - - reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); - reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0; - reg_learn_mode |= CIR_WAKE_IRCON_MODE1; - - /* Lock the learn area to prevent racing with wake-isr */ - spin_lock_irqsave(&nvt->nvt_lock, flags); - - /* Enable fifo writes */ - nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON); - - /* Clear cir wake rx fifo */ - nvt_clear_cir_wake_fifo(nvt); - - if (count > WAKE_FIFO_LEN) { - nvt_dbg_wake("HW FIFO too small for all wake samples"); - count = WAKE_FIFO_LEN; - } - - if (count) - pr_info("Wake samples (%d) =", count); - else - pr_info("Wake sample fifo cleared"); - - /* Write wake samples to fifo */ - for (i = 0; i < count; i++) { - pr_cont(" %02x", wakeup_sample_buf[i]); - nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i], - CIR_WAKE_WR_FIFO_DATA); - } - pr_cont("\n"); - - /* Switch cir to wakeup mode and disable fifo writing */ - nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON); - - /* Set number of bytes needed for wake */ - nvt_cir_wake_reg_write(nvt, count ? count : - CIR_WAKE_FIFO_CMP_BYTES, - CIR_WAKE_FIFO_CMP_DEEP); - - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - return 0; -} - -static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev, - struct rc_scancode_filter *sc_filter) -{ - u8 *reg_buf; - u8 buf_val; - int i, ret, count; - unsigned int val; - struct ir_raw_event *raw; - bool complete; - - /* Require both mask and data to be set before actually committing */ - if (!sc_filter->mask || !sc_filter->data) - return 0; - - raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL); - if (!raw) - return -ENOMEM; - - ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter, - raw, WAKE_FIFO_LEN); - complete = (ret != -ENOBUFS); - if (!complete) - ret = WAKE_FIFO_LEN; - else if (ret < 0) - goto out_raw; - - reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL); - if (!reg_buf) { - ret = -ENOMEM; - goto out_raw; - } - - /* Inspect the ir samples */ - for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) { - val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD; - - /* Split too large values into several smaller ones */ - while (val > 0 && count < WAKE_FIFO_LEN) { - - /* Skip last value for better comparison tolerance */ - if (complete && i == ret - 1 && val < BUF_LEN_MASK) - break; - - /* Clamp values to BUF_LEN_MASK at most */ - buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val; - - reg_buf[count] = buf_val; - val -= buf_val; - if ((raw[i]).pulse) - reg_buf[count] |= BUF_PULSE_BIT; - count++; - } - } - - ret = nvt_write_wakeup_codes(dev, reg_buf, count); - - kfree(reg_buf); -out_raw: - kfree(raw); - - return ret; -} - -/* Dummy implementation. nuvoton is agnostic to the protocol used */ -static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev, - u64 *rc_type) -{ - return 0; -} - /* * nvt_tx_ir * @@ -1167,14 +1043,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->encode_wakeup = true; rdev->allowed_protocols = RC_BIT_ALL; rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; - rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; - rdev->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol; rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; rdev->input_phys = "nuvoton/cir0"; rdev->input_id.bustype = BUS_HOST; diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 9d0e161..e1cf23c 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -63,7 +63,6 @@ static int debug; */ #define TX_BUF_LEN 256 #define RX_BUF_LEN 32 -#define WAKE_FIFO_LEN 67 struct nvt_dev { struct pnp_dev *pdev; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 45534da5..df73d85 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -246,7 +246,6 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev) #define US_TO_NS(usec) ((usec) * 1000) #define MS_TO_US(msec) ((msec) * 1000) #define MS_TO_NS(msec) ((msec) * 1000 * 1000) -#define NS_TO_US(nsec) DIV_ROUND_UP(nsec, 1000L) void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); -- cgit v0.10.2 From 8abfebdb00fa8f2acb3923386e3cb1570d2c1d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:36 -0300 Subject: Revert "[media] rc: rc-loopback: Add loopback of filter scancodes" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 2e4ebde269236da2a41183522127715b6d9d80ce. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index d8bdf63..63dace8 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #define DRIVER_NAME "rc-loopback" @@ -177,39 +176,6 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable) return 0; } -static int loop_set_wakeup_filter(struct rc_dev *dev, - struct rc_scancode_filter *sc_filter) -{ - static const unsigned int max = 512; - struct ir_raw_event *raw; - int ret; - int i; - - /* fine to disable filter */ - if (!sc_filter->mask) - return 0; - - /* encode the specified filter and loop it back */ - raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL); - ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter, - raw, max); - /* still loop back the partial raw IR even if it's incomplete */ - if (ret == -ENOBUFS) - ret = max; - if (ret >= 0) { - /* do the loopback */ - for (i = 0; i < ret; ++i) - ir_raw_event_store(dev, &raw[i]); - ir_raw_event_handle(dev); - - ret = 0; - } - - kfree(raw); - - return ret; -} - static int __init loop_init(void) { struct rc_dev *rc; @@ -229,7 +195,6 @@ static int __init loop_init(void) rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->encode_wakeup = true; rc->allowed_protocols = RC_BIT_ALL; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; @@ -244,7 +209,6 @@ static int __init loop_init(void) rc->s_idle = loop_set_idle; rc->s_learning_mode = loop_set_learning_mode; rc->s_carrier_report = loop_set_carrier_report; - rc->s_wakeup_filter = loop_set_wakeup_filter; loopdev.txmask = RXMASK_REGULAR; loopdev.txcarrier = 36000; -- cgit v0.10.2 From 3a03b86fdc1634e81d77f84e987c5a15426eff3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:41 -0300 Subject: Revert "[media] rc: rc-core: Add support for encode_wakeup drivers" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 0d830b2d1295fee82546d57185da5a6604f11ae2. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 4b994aa..5266ecc7 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -189,7 +189,6 @@ int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, * Routines from rc-raw.c to be used internally and by decoders */ u64 ir_raw_get_allowed_protocols(void); -u64 ir_raw_get_encode_protocols(void); int ir_raw_event_register(struct rc_dev *dev); void ir_raw_event_unregister(struct rc_dev *dev); int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b9e4645..6c9580e 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -30,7 +30,6 @@ static LIST_HEAD(ir_raw_client_list); static DEFINE_MUTEX(ir_raw_handler_lock); static LIST_HEAD(ir_raw_handler_list); static u64 available_protocols; -static u64 encode_protocols; static int ir_raw_event_thread(void *data) { @@ -241,18 +240,6 @@ ir_raw_get_allowed_protocols(void) return protocols; } -/* used internally by the sysfs interface */ -u64 -ir_raw_get_encode_protocols(void) -{ - u64 protocols; - - mutex_lock(&ir_raw_handler_lock); - protocols = encode_protocols; - mutex_unlock(&ir_raw_handler_lock); - return protocols; -} - static int change_protocol(struct rc_dev *dev, u64 *rc_type) { /* the caller will update dev->enabled_protocols */ @@ -463,8 +450,6 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_register(raw->dev); available_protocols |= ir_raw_handler->protocols; - if (ir_raw_handler->encode) - encode_protocols |= ir_raw_handler->protocols; mutex_unlock(&ir_raw_handler_lock); return 0; @@ -481,8 +466,6 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_unregister(raw->dev); available_protocols &= ~ir_raw_handler->protocols; - if (ir_raw_handler->encode) - encode_protocols &= ~ir_raw_handler->protocols; mutex_unlock(&ir_raw_handler_lock); } EXPORT_SYMBOL(ir_raw_handler_unregister); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9d015db..0ff388a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -865,8 +865,6 @@ static ssize_t show_protocols(struct device *device, } else { enabled = dev->enabled_wakeup_protocols; allowed = dev->allowed_wakeup_protocols; - if (dev->encode_wakeup && !allowed) - allowed = ir_raw_get_encode_protocols(); } mutex_unlock(&dev->lock); @@ -1408,16 +1406,13 @@ int rc_register_device(struct rc_dev *dev) path ? path : "N/A"); kfree(path); - if (dev->driver_type == RC_DRIVER_IR_RAW || dev->encode_wakeup) { + if (dev->driver_type == RC_DRIVER_IR_RAW) { /* Load raw decoders, if they aren't already */ if (!raw_init) { IR_dprintk(1, "Loading raw decoders\n"); ir_raw_init(); raw_init = true; } - } - - if (dev->driver_type == RC_DRIVER_IR_RAW) { /* calls ir_register_device so unlock mutex here*/ mutex_unlock(&dev->lock); rc = ir_raw_event_register(dev); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index df73d85..f0d0959 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -74,8 +74,6 @@ enum rc_filter_type { * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software * @idle: used to keep track of RX state - * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed - * wakeup protocols is the set of all raw encoders * @allowed_protocols: bitmask with the supported RC_BIT_* protocols * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols @@ -136,7 +134,6 @@ struct rc_dev { struct input_dev *input_dev; enum rc_driver_type driver_type; bool idle; - bool encode_wakeup; u64 allowed_protocols; u64 enabled_protocols; u64 allowed_wakeup_protocols; -- cgit v0.10.2 From 70e7112e7d22ac5077ede777917cb057c1950ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:46 -0300 Subject: Revert "[media] rc: ir-rc6-decoder: Add encode capability" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf257e288ad3a134d4bb809c542a3ae6c87ddfa3. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index f9c70ba..d16bc67 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -291,133 +291,11 @@ out: return -EINVAL; } -static struct ir_raw_timings_manchester ir_rc6_timings[4] = { - { - .leader = RC6_PREFIX_PULSE, - .pulse_space_start = 0, - .clock = RC6_UNIT, - .invert = 1, - .trailer_space = RC6_PREFIX_SPACE, - }, - { - .clock = RC6_UNIT, - .invert = 1, - }, - { - .clock = RC6_UNIT * 2, - .invert = 1, - }, - { - .clock = RC6_UNIT, - .invert = 1, - .trailer_space = RC6_SUFFIX_SPACE, - }, -}; - -static int ir_rc6_validate_filter(const struct rc_scancode_filter *scancode, - unsigned int important_bits) -{ - /* all important bits of scancode should be set in mask */ - if (~scancode->mask & important_bits) - return -EINVAL; - /* extra bits in mask should be zero in data */ - if (scancode->mask & scancode->data & ~important_bits) - return -EINVAL; - return 0; -} - -/** - * ir_rc6_encode() - Encode a scancode as a stream of raw events - * - * @protocols: allowed protocols - * @scancode: scancode filter describing scancode (helps distinguish between - * protocol subtypes when scancode is ambiguous) - * @events: array of raw ir events to write into - * @max: maximum size of @events - * - * Returns: The number of events written. - * -ENOBUFS if there isn't enough space in the array to fit the - * encoding. In this case all @max events will have been written. - * -EINVAL if the scancode is ambiguous or invalid. - */ -static int ir_rc6_encode(u64 protocols, - const struct rc_scancode_filter *scancode, - struct ir_raw_event *events, unsigned int max) -{ - int ret; - struct ir_raw_event *e = events; - - if (protocols & RC_BIT_RC6_0 && - !ir_rc6_validate_filter(scancode, 0xffff)) { - - /* Modulate the preamble */ - ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); - if (ret < 0) - return ret; - - /* Modulate the header (Start Bit & Mode-0) */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[1], - RC6_HEADER_NBITS, (1 << 3)); - if (ret < 0) - return ret; - - /* Modulate Trailer Bit */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[2], 1, 0); - if (ret < 0) - return ret; - - /* Modulate rest of the data */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[3], RC6_0_NBITS, - scancode->data); - if (ret < 0) - return ret; - - } else if (protocols & (RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | - RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) && - !ir_rc6_validate_filter(scancode, 0x8fffffff)) { - - /* Modulate the preamble */ - ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); - if (ret < 0) - return ret; - - /* Modulate the header (Start Bit & Header-version 6 */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[1], - RC6_HEADER_NBITS, (1 << 3 | 6)); - if (ret < 0) - return ret; - - /* Modulate Trailer Bit */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[2], 1, 0); - if (ret < 0) - return ret; - - /* Modulate rest of the data */ - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc6_timings[3], - fls(scancode->mask), - scancode->data); - if (ret < 0) - return ret; - - } else { - return -EINVAL; - } - - return e - events; -} - static struct ir_raw_handler rc6_handler = { .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE, .decode = ir_rc6_decode, - .encode = ir_rc6_encode, }; static int __init ir_rc6_decode_init(void) -- cgit v0.10.2 From e49b361d4f73cee46e35319c3b7265f414689052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:51 -0300 Subject: Revert "[media] rc: ir-rc5-decoder: Add encode capability" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a0466f15b4654cf1ac9e387d7c1a401eff494b4f. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 8939ebd..84fa6e9 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -184,125 +184,9 @@ out: return -EINVAL; } -static struct ir_raw_timings_manchester ir_rc5_timings = { - .leader = RC5_UNIT, - .pulse_space_start = 0, - .clock = RC5_UNIT, - .trailer_space = RC5_UNIT * 10, -}; - -static struct ir_raw_timings_manchester ir_rc5x_timings[2] = { - { - .leader = RC5_UNIT, - .pulse_space_start = 0, - .clock = RC5_UNIT, - .trailer_space = RC5X_SPACE, - }, - { - .clock = RC5_UNIT, - .trailer_space = RC5_UNIT * 10, - }, -}; - -static struct ir_raw_timings_manchester ir_rc5_sz_timings = { - .leader = RC5_UNIT, - .pulse_space_start = 0, - .clock = RC5_UNIT, - .trailer_space = RC5_UNIT * 10, -}; - -static int ir_rc5_validate_filter(const struct rc_scancode_filter *scancode, - unsigned int important_bits) -{ - /* all important bits of scancode should be set in mask */ - if (~scancode->mask & important_bits) - return -EINVAL; - /* extra bits in mask should be zero in data */ - if (scancode->mask & scancode->data & ~important_bits) - return -EINVAL; - return 0; -} - -/** - * ir_rc5_encode() - Encode a scancode as a stream of raw events - * - * @protocols: allowed protocols - * @scancode: scancode filter describing scancode (helps distinguish between - * protocol subtypes when scancode is ambiguous) - * @events: array of raw ir events to write into - * @max: maximum size of @events - * - * Returns: The number of events written. - * -ENOBUFS if there isn't enough space in the array to fit the - * encoding. In this case all @max events will have been written. - * -EINVAL if the scancode is ambiguous or invalid. - */ -static int ir_rc5_encode(u64 protocols, - const struct rc_scancode_filter *scancode, - struct ir_raw_event *events, unsigned int max) -{ - int ret; - struct ir_raw_event *e = events; - unsigned int data, xdata, command, commandx, system; - - /* Detect protocol and convert scancode to raw data */ - if (protocols & RC_BIT_RC5 && - !ir_rc5_validate_filter(scancode, 0x1f7f)) { - /* decode scancode */ - command = (scancode->data & 0x003f) >> 0; - commandx = (scancode->data & 0x0040) >> 6; - system = (scancode->data & 0x1f00) >> 8; - /* encode data */ - data = !commandx << 12 | system << 6 | command; - - /* Modulate the data */ - ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings, RC5_NBITS, - data); - if (ret < 0) - return ret; - } else if (protocols & RC_BIT_RC5X && - !ir_rc5_validate_filter(scancode, 0x1f7f3f)) { - /* decode scancode */ - xdata = (scancode->data & 0x00003f) >> 0; - command = (scancode->data & 0x003f00) >> 8; - commandx = (scancode->data & 0x004000) >> 14; - system = (scancode->data & 0x1f0000) >> 16; - /* commandx and system overlap, bits must match when encoded */ - if (commandx == (system & 0x1)) - return -EINVAL; - /* encode data */ - data = 1 << 18 | system << 12 | command << 6 | xdata; - - /* Modulate the data */ - ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0], - CHECK_RC5X_NBITS, - data >> (RC5X_NBITS-CHECK_RC5X_NBITS)); - if (ret < 0) - return ret; - ret = ir_raw_gen_manchester(&e, max - (e - events), - &ir_rc5x_timings[1], - RC5X_NBITS - CHECK_RC5X_NBITS, - data); - if (ret < 0) - return ret; - } else if (protocols & RC_BIT_RC5_SZ && - !ir_rc5_validate_filter(scancode, 0x2fff)) { - /* RC5-SZ scancode is raw enough for Manchester as it is */ - ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings, - RC5_SZ_NBITS, scancode->data & 0x2fff); - if (ret < 0) - return ret; - } else { - return -EINVAL; - } - - return e - events; -} - static struct ir_raw_handler rc5_handler = { .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ, .decode = ir_rc5_decode, - .encode = ir_rc5_encode, }; static int __init ir_rc5_decode_init(void) -- cgit v0.10.2 From 86f216640ed58718553e826dc8d4ee419ad2a6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:16:56 -0300 Subject: Revert "[media] rc: rc-ir-raw: Add Manchester encoder (phase encoder) helper" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1d971d927efa2e10194c96ed0475b6d6054342d8. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 5266ecc7..122c25f 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -152,39 +152,6 @@ static inline bool is_timing_event(struct ir_raw_event ev) #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") -/* functions for IR encoders */ - -static inline void init_ir_raw_event_duration(struct ir_raw_event *ev, - unsigned int pulse, - u32 duration) -{ - init_ir_raw_event(ev); - ev->duration = duration; - ev->pulse = pulse; -} - -/** - * struct ir_raw_timings_manchester - Manchester coding timings - * @leader: duration of leader pulse (if any) 0 if continuing - * existing signal (see @pulse_space_start) - * @pulse_space_start: 1 for starting with pulse (0 for starting with space) - * @clock: duration of each pulse/space in ns - * @invert: if set clock logic is inverted - * (0 = space + pulse, 1 = pulse + space) - * @trailer_space: duration of trailer space in ns - */ -struct ir_raw_timings_manchester { - unsigned int leader; - unsigned int pulse_space_start:1; - unsigned int clock; - unsigned int invert:1; - unsigned int trailer_space; -}; - -int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, - const struct ir_raw_timings_manchester *timings, - unsigned int n, unsigned int data); - /* * Routines from rc-raw.c to be used internally and by decoders */ diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 6c9580e..dd47fe5 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -247,91 +247,6 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) } /** - * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation. - * @ev: Pointer to pointer to next free event. *@ev is incremented for - * each raw event filled. - * @max: Maximum number of raw events to fill. - * @timings: Manchester modulation timings. - * @n: Number of bits of data. - * @data: Data bits to encode. - * - * Encodes the @n least significant bits of @data using Manchester (bi-phase) - * modulation with the timing characteristics described by @timings, writing up - * to @max raw IR events using the *@ev pointer. - * - * Returns: 0 on success. - * -ENOBUFS if there isn't enough space in the array to fit the - * full encoded data. In this case all @max events will have been - * written. - */ -int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, - const struct ir_raw_timings_manchester *timings, - unsigned int n, unsigned int data) -{ - bool need_pulse; - unsigned int i; - int ret = -ENOBUFS; - - i = 1 << (n - 1); - - if (timings->leader) { - if (!max--) - return ret; - if (timings->pulse_space_start) { - init_ir_raw_event_duration((*ev)++, 1, timings->leader); - - if (!max--) - return ret; - init_ir_raw_event_duration((*ev), 0, timings->leader); - } else { - init_ir_raw_event_duration((*ev), 1, timings->leader); - } - i >>= 1; - } else { - /* continue existing signal */ - --(*ev); - } - /* from here on *ev will point to the last event rather than the next */ - - while (n && i > 0) { - need_pulse = !(data & i); - if (timings->invert) - need_pulse = !need_pulse; - if (need_pulse == !!(*ev)->pulse) { - (*ev)->duration += timings->clock; - } else { - if (!max--) - goto nobufs; - init_ir_raw_event_duration(++(*ev), need_pulse, - timings->clock); - } - - if (!max--) - goto nobufs; - init_ir_raw_event_duration(++(*ev), !need_pulse, - timings->clock); - i >>= 1; - } - - if (timings->trailer_space) { - if (!(*ev)->pulse) - (*ev)->duration += timings->trailer_space; - else if (!max--) - goto nobufs; - else - init_ir_raw_event_duration(++(*ev), 0, - timings->trailer_space); - } - - ret = 0; -nobufs: - /* point to the next event rather than last event before returning */ - ++(*ev); - return ret; -} -EXPORT_SYMBOL(ir_raw_gen_manchester); - -/** * ir_raw_encode_scancode() - Encode a scancode as raw events * * @protocols: permitted protocols -- cgit v0.10.2 From 72c5b7b24f3800bf8b1b1c78511c6da09d33c590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Mon, 20 Jul 2015 16:17:01 -0300 Subject: Revert "[media] rc: rc-ir-raw: Add scancode encoder callback" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9869da5bacc5c9b865a183bd36c04be76cdd325d. The current code is not mature enough, the API should allow a single protocol to be specified. Also, the current code contains heuristics that will depend on module load order. Signed-off-by: David Härdeman Acked-by: Antti Seppälä Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 122c25f..b68d4f76 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -25,8 +25,6 @@ struct ir_raw_handler { u64 protocols; /* which are handled by this handler */ int (*decode)(struct rc_dev *dev, struct ir_raw_event event); - int (*encode)(u64 protocols, const struct rc_scancode_filter *scancode, - struct ir_raw_event *events, unsigned int max); /* These two should only be used by the lirc decoder */ int (*raw_register)(struct rc_dev *dev); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index dd47fe5..b732ac6 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -246,43 +246,6 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) return 0; } -/** - * ir_raw_encode_scancode() - Encode a scancode as raw events - * - * @protocols: permitted protocols - * @scancode: scancode filter describing a single scancode - * @events: array of raw events to write into - * @max: max number of raw events - * - * Attempts to encode the scancode as raw events. - * - * Returns: The number of events written. - * -ENOBUFS if there isn't enough space in the array to fit the - * encoding. In this case all @max events will have been written. - * -EINVAL if the scancode is ambiguous or invalid, or if no - * compatible encoder was found. - */ -int ir_raw_encode_scancode(u64 protocols, - const struct rc_scancode_filter *scancode, - struct ir_raw_event *events, unsigned int max) -{ - struct ir_raw_handler *handler; - int ret = -EINVAL; - - mutex_lock(&ir_raw_handler_lock); - list_for_each_entry(handler, &ir_raw_handler_list, list) { - if (handler->protocols & protocols && handler->encode) { - ret = handler->encode(protocols, scancode, events, max); - if (ret >= 0 || ret == -ENOBUFS) - break; - } - } - mutex_unlock(&ir_raw_handler_lock); - - return ret; -} -EXPORT_SYMBOL(ir_raw_encode_scancode); - /* * Used to (un)register raw event clients */ diff --git a/include/media/rc-core.h b/include/media/rc-core.h index f0d0959..644bdc6 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -250,9 +250,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type); int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev); void ir_raw_event_set_idle(struct rc_dev *dev, bool idle); -int ir_raw_encode_scancode(u64 protocols, - const struct rc_scancode_filter *scancode, - struct ir_raw_event *events, unsigned int max); static inline void ir_raw_event_reset(struct rc_dev *dev) { -- cgit v0.10.2 From 02387b5f25bdba668c7fe2618697bae24f973667 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Aug 2015 14:11:41 -0300 Subject: [media] mantis: Fix error handling in mantis_dma_init() Current code assigns 0 to variable 'err', which makes mantis_dma_init() to return success even if mantis_alloc_buffers() fails. Fix it by checking the return value from mantis_alloc_buffers() and propagating it in the case of error. Reported-by: RUC_Soft_Sec Signed-off-by: Fabio Estevam Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c index 1d59c7e..87990ec 100644 --- a/drivers/media/pci/mantis/mantis_dma.c +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -130,10 +130,11 @@ err: int mantis_dma_init(struct mantis_pci *mantis) { - int err = 0; + int err; dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); - if (mantis_alloc_buffers(mantis) < 0) { + err = mantis_alloc_buffers(mantis); + if (err < 0) { dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); /* Stop RISC Engine */ -- cgit v0.10.2 From 72ccc89e38031183323f8e715503d7e61fcff2ab Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 19 Aug 2015 10:32:23 +0800 Subject: FIRMWARE: bcm47xx_nvram: Fix module license. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Axel Lin Cc: Hauke Mehrtens Cc: Rafał Miłecki Cc: Paul Walmsley Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11020/ Signed-off-by: Ralf Baechle diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c index 87add3f..e415945 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c @@ -245,4 +245,4 @@ char *bcm47xx_nvram_get_contents(size_t *nvram_size) } EXPORT_SYMBOL(bcm47xx_nvram_get_contents); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From ebb75c0bdba238013976b53e256f8d13216304e4 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 15 Aug 2015 07:21:00 +0530 Subject: ASoC: rockchip: i2s: Adjust devm usage Remove use of snd_soc_unregister_component in remove function as devm_snd_soc_register_component in probe function automatically handles it. Also, convert call of snd_dmaengine_pcm_register to managed resource function devm_snd_dmaengine_pcm_register and remove usage of snd_dmaengine_pcm_unregister in probe and remove functions. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index acb5be5..b936102 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -483,16 +483,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_suspend; } - ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); - goto err_pcm_register; + return ret; } return 0; -err_pcm_register: - snd_dmaengine_pcm_unregister(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) i2s_runtime_suspend(&pdev->dev); @@ -512,8 +510,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev) clk_disable_unprepare(i2s->mclk); clk_disable_unprepare(i2s->hclk); - snd_dmaengine_pcm_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); return 0; } -- cgit v0.10.2 From 1cf5a330c05ae37a0a98ac7c9800a6f50d5579ec Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Wed, 19 Aug 2015 16:02:24 +0100 Subject: ASoC: arizona: Fix gain settings of FLL in free-run mode The wrong register was used to set the gain of ref loop, when changing the FLL output on an active FLL. This patch corrects the offset of the gain register. Signed-off-by: Nikesh Oswal Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05e..4e5d0a9 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2058,7 +2058,7 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (already_enabled) { /* Facilitate smooth refclk across the transition */ - regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7, + regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, -- cgit v0.10.2 From 0d7e7acc47133e82911e24758178815cfee309e9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 19 Aug 2015 17:29:19 +0300 Subject: perf tools: Avoid deadlock when map_groups are broken Attempting to clone map groups onto themselves will deadlock. It only happens because of other bugs, but the code should protect itself anyway. Reported-by: Linus Torvalds Signed-off-by: Adrian Hunter Tested-by: Jiri Olsa Link: http://lkml.kernel.org/r/1439994561-27436-2-git-send-email-adrian.hunter@intel.com [ Use pr_debug() instead of dump_fprintf() ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 28c4b74..0a9ae80 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -191,6 +191,12 @@ static int thread__clone_map_groups(struct thread *thread, if (thread->pid_ == parent->pid_) return 0; + if (thread->mg == parent->mg) { + pr_debug("broken map groups on thread %d/%d parent %d/%d\n", + thread->pid_, thread->tid, parent->pid_, parent->tid); + return 0; + } + /* But this one is new process, copy maps. */ for (i = 0; i < MAP__NR_TYPES; ++i) if (map_groups__clone(thread->mg, parent->mg, i) < 0) -- cgit v0.10.2 From 5cb73340d92a716fd2776700742c3558206ae298 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 19 Aug 2015 17:29:20 +0300 Subject: perf tools: Make fork event processing more resilient When processing a fork event, the tools lookup the parent thread by its tid. In a couple of cases, it is possible for that thread to have the wrong pid. That can happen if the data is being processed out of order, or if the (fork) event that would have removed the erroneous thread was lost. Assume the latter case, print a dump message, remove the erroneous thread, create a new one with the correct pid, and keep going. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Adrian Hunter Tested-by: Jiri Olsa Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1439994561-27436-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 7ff6827..f1a4c83 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1387,6 +1387,24 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event event->fork.ptid); int err = 0; + if (dump_trace) + perf_event__fprintf_task(event, stdout); + + /* + * There may be an existing thread that is not actually the parent, + * either because we are processing events out of order, or because the + * (fork) event that would have removed the thread was lost. Assume the + * latter case and continue on as best we can. + */ + if (parent->pid_ != (pid_t)event->fork.ppid) { + dump_printf("removing erroneous parent thread %d/%d\n", + parent->pid_, parent->tid); + machine__remove_thread(machine, parent); + thread__put(parent); + parent = machine__findnew_thread(machine, event->fork.ppid, + event->fork.ptid); + } + /* if a thread currently exists for the thread id remove it */ if (thread != NULL) { machine__remove_thread(machine, thread); @@ -1395,8 +1413,6 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); - if (dump_trace) - perf_event__fprintf_task(event, stdout); if (thread == NULL || parent == NULL || thread__fork(thread, parent, sample->time) < 0) { -- cgit v0.10.2 From cca8482c0651cea97aade58cc22109ce9fffbfa2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 19 Aug 2015 17:29:21 +0300 Subject: perf tools: Fix buildid processing After recording, 'perf record' post-processes the data to determine which buildids are needed. That processing must process the data in time order, if possible, because otherwise dependent events, like forks and mmaps, will not make sense. Signed-off-by: Adrian Hunter Tested-by: Jiri Olsa Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1439994561-27436-4-git-send-email-adrian.hunter@intel.com [ Moved the sample_id_add to after trying to open the events, use pr_warning ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index de165a1..20b56eb 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -521,6 +521,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) goto out_child; } + /* + * Normally perf_session__new would do this, but it doesn't have the + * evlist. + */ + if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) { + pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n"); + rec->tool.ordered_events = false; + } + if (!rec->evlist->nr_groups) perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); @@ -965,9 +974,11 @@ static struct record record = { .tool = { .sample = process_sample_event, .fork = perf_event__process_fork, + .exit = perf_event__process_exit, .comm = perf_event__process_comm, .mmap = perf_event__process_mmap, .mmap2 = perf_event__process_mmap2, + .ordered_events = true, }, }; -- cgit v0.10.2 From 09f4d78ab0af0973e1a49c10eb7bf977c68cc3aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Aug 2015 15:16:08 -0300 Subject: perf top: Show backtrace when handling a SIGSEGV on --stdio mode It was just freezing instead of informing about the SEGV, fix it and also print a backtrace, just like in the TUI mode and in 'perf trace'. Tested by provoking a NULL deref when pressing 'z': 0.31% libc-2.20.so [.] malloc_consolidate 0.31% ld-2.20.so [.] _dl_relocate_object 0.28% cc1 [.] ht_lookup 0.28% cc1 [.] ira_init_register_move_cost perf: Segmentation fault Obtained 7 stack frames. perf(dump_stack+0x32) [0x4d69f2] perf(sighandler_dump_stack+0x29) [0x4d6a89] /lib64/libc.so.6(+0x34960) [0x7f5064333960] perf() [0x438790] /lib64/libpthread.so.0(+0x752a) [0x7f50663dd52a] /lib64/libc.so.6(clone+0x6d) [0x7f50643ff22d] # Reported-by: Linus Torvalds Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pewrpzqd29rgmhu2wkk7fhww@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ecf3197..6135cc0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -601,8 +601,8 @@ static void display_sig(int sig __maybe_unused) static void display_setup_sig(void) { - signal(SIGSEGV, display_sig); - signal(SIGFPE, display_sig); + signal(SIGSEGV, sighandler_dump_stack); + signal(SIGFPE, sighandler_dump_stack); signal(SIGINT, display_sig); signal(SIGQUIT, display_sig); signal(SIGTERM, display_sig); -- cgit v0.10.2 From b35b1df5e6c213b0b0322e6c231b7111efe4a390 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Mon, 17 Aug 2015 18:47:58 +0800 Subject: PCI: Tolerate hierarchies with no Root Port We should not assume any particular hardware topology. Commit d0751b98dfa3 ("PCI: Add dev->has_secondary_link to track downstream PCIe links") relied on the assumption that every PCIe hierarchy is rooted at a Root Port. But we can't rely on any assumption about what hardware we will find; we just have to deal with the world as it is. On some platforms, PCIe devices (endpoints, switch upstream ports, etc.) appear directly on the root bus, and there is no Root Port in the PCI bus hierarchy. For example, Meelis observed these top-level devices on a Sparc V245: 0000:02:00.0 PCI bridge to [bus 03-0d] Switch Upstream Port 0001:02:00.0 PCI bridge to [bus 03] PCIe to PCI/PCI-X Bridge These devices *look* like they have links going upstream, but there really are no upstream devices. In set_pcie_port_type(), we used the parent device to figure out which side of a switch port has a link, so if the parent device did not exist, we dereferenced a NULL parent pointer. Check whether the parent device exists before dereferencing it. Meelis observed this oops on Sparc V245 and T2000. Ben Herrenschmidt says this is also possible on IBM PowerVM guests on PowerPC. [bhelgaas: changelog, comment] Link: http://lkml.kernel.org/r/alpine.LRH.2.20.1508122118210.18637@math.ut.ee Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: David S. Miller diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636..b978bbf 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -997,7 +997,12 @@ void set_pcie_port_type(struct pci_dev *pdev) else if (type == PCI_EXP_TYPE_UPSTREAM || type == PCI_EXP_TYPE_DOWNSTREAM) { parent = pci_upstream_bridge(pdev); - if (!parent->has_secondary_link) + + /* + * Usually there's an upstream device (Root Port or Switch + * Downstream Port), but we can't assume one exists. + */ + if (parent && !parent->has_secondary_link) pdev->has_secondary_link = 1; } } -- cgit v0.10.2 From 6d4affea7d5aa5ca5ff4c3e5fbf3ee16801cc527 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:25 +0300 Subject: genirq: Don't return ENOSYS in irq_chip_retrigger_hierarchy irq_chip_retrigger_hierarchy() returns -ENOSYS if it was not able to find at least one .irq_retrigger() callback implemented in the IRQ domain hierarchy. That's wrong, because check_irq_resend() expects a 0 return value from the callback in case that the hardware assisted resend was not possible. If the return value is non zero the core code assumes hardware resend success and the software resend is not invoked. This results in lost interrupts on platforms where none of the parent irq chips in the hierarchy implements the retrigger callback. This is observable on TI OMAP, where the hierarchy is: ARM GIC <- OMAP wakeupgen <- TI Crossbar Return 0 instead so the software resend mechanism gets invoked. [ tglx: Massaged changelog ] Fixes: 85f08c17de26 ('genirq: Introduce helper functions...') Signed-off-by: Grygorii Strashko Reviewed-by: Marc Zyngier Reviewed-by: Jiang Liu Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-2-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 27f4332..6de638b 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -997,7 +997,7 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data) if (data->chip && data->chip->irq_retrigger) return data->chip->irq_retrigger(data); - return -ENOSYS; + return 0; } /** -- cgit v0.10.2 From b7560de198222994374c1340a389f12d5efb244a Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:26 +0300 Subject: genirq: Introduce irq_chip_set_type_parent() helper This helper is required for irq chips which do not implement a irq_set_type callback and need to call down the irq domain hierarchy for the actual trigger type change. This helper is required to fix further wreckage caused by the conversion of TI OMAP to hierarchical irq domains and therefor tagged for stable. [ tglx: Massaged changelog ] Signed-off-by: Grygorii Strashko Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-3-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 92188b0..51744bc 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -484,6 +484,7 @@ extern int irq_chip_set_affinity_parent(struct irq_data *data, extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on); extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info); +extern int irq_chip_set_type_parent(struct irq_data *data, unsigned int type); #endif /* Handling of unhandled and spurious interrupts: */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6de638b..ae21682 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -985,6 +985,23 @@ int irq_chip_set_affinity_parent(struct irq_data *data, } /** + * irq_chip_set_type_parent - Set IRQ type on the parent interrupt + * @data: Pointer to interrupt specific data + * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h + * + * Conditional, as the underlying parent chip might not implement it. + */ +int irq_chip_set_type_parent(struct irq_data *data, unsigned int type) +{ + data = data->parent_data; + + if (data->chip->irq_set_type) + return data->chip->irq_set_type(data, type); + + return -ENOSYS; +} + +/** * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware * @data: Pointer to interrupt specific data * -- cgit v0.10.2 From e269ec42328783e51be08c191aa935dba56141fc Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:27 +0300 Subject: irqchip/crossbar: Restore the irq_set_type() mechanism The conversion of the crossbar irqchip to hierarchical irq domains failed to provide a mechanism to properly set the trigger type of an interrupt. The crossbar irq chip itself has no mechanism and therefor no irq_set_type() callback. The code before the conversion relayed the trigger configuration directly to the underlying GIC. Restore the correct behaviour by setting the crossbar irq_set_type callback to irq_chip_set_type_parent(). This propagates the set_trigger() call to the underlying GIC irqchip. [ tglx: Massaged changelog ] Fixes: 783d31863fb8 ('irqchip: crossbar: Convert dra7 crossbar...') Signed-off-by: Grygorii Strashko Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-4-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index 692fe2b..3ba58e7 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -69,6 +69,7 @@ static struct irq_chip crossbar_chip = { .irq_unmask = irq_chip_unmask_parent, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_wake = irq_chip_set_wake_parent, + .irq_set_type = irq_chip_set_type_parent, #ifdef CONFIG_SMP .irq_set_affinity = irq_chip_set_affinity_parent, #endif -- cgit v0.10.2 From 63059a272398ef5dc1bd7065a036e8b6e82d1af7 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:28 +0300 Subject: ARM: OMAP: wakeupgen: Restore the irq_set_type() mechanism The conversion of the wakeupgen irqchip to hierarchical irq domains failed to provide a mechanism to properly set the trigger type of an interrupt. The wakeupgen irq chip itself has no mechanism and therefor no irq_set_type() callback. The code before the conversion relayed the trigger configuration directly to the underlying GIC. Restore the correct behaviour by setting the wakeupgen irq_set_type callback to irq_chip_set_type_parent(). This propagates the set_trigger() call to the underlying GIC irqchip. [ tglx: Massaged changelog ] Fixes: 7136d457f365 ('ARM: omap: convert wakeupgen to stacked domains') Signed-off-by: Grygorii Strashko Acked-by: Tony Lindgren Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-5-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 8e52621..e1d2e99 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -392,6 +392,7 @@ static struct irq_chip wakeupgen_chip = { .irq_mask = wakeupgen_mask, .irq_unmask = wakeupgen_unmask, .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = irq_chip_set_type_parent, .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, #ifdef CONFIG_SMP .irq_set_affinity = irq_chip_set_affinity_parent, -- cgit v0.10.2 From 4fd8f47e7e5b64a74b60f23c2e08ba8234d659d1 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:29 +0300 Subject: irqchip/crossbar: Restore the mask on suspend behaviour The ARM GIC requires that all interrupts which are not used as a wakeup source have to be masked during suspend. The conversion of the crossbar irqchip to hierarchical irq domains failed to mark the crossbar irqchip with the IRQCHIP_MASK_ON_SUSPEND flag and therefor broke the suspend requirement of the GIC. Before the conversion the flags were visible because the GIC was the top level irqchip. After the conversion the crossbar irqchip is the top level irq chip whose flags are evaluated in suspend_device_irq(). As the flag is not set the masking of the non-wakeup irqs is not invoked which breaks suspend. Add the IRQCHIP_MASK_ON_SUSPEND flag to the crossbar irqchip, so the GIC interrupts get masked properly. [ tglx: Massaged changelog ] Fixes: 783d31863fb8 ('irqchip: crossbar: Convert dra7 crossbar...') Signed-off-by: Grygorii Strashko Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-6-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index 3ba58e7..f5a72cc 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -70,6 +70,7 @@ static struct irq_chip crossbar_chip = { .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_wake = irq_chip_set_wake_parent, .irq_set_type = irq_chip_set_type_parent, + .flags = IRQCHIP_MASK_ON_SUSPEND, #ifdef CONFIG_SMP .irq_set_affinity = irq_chip_set_affinity_parent, #endif -- cgit v0.10.2 From 8200fe4347870d4ad6475048bcdf3e7c106c5268 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 14 Aug 2015 15:20:30 +0300 Subject: irqchip/crossbar: Restore set_wake functionality The TI crossbar irqchip doesn't provides any facility to configure the wakeup sources, but the conversion to hierarchical irqdomains set the irq_set_wake callback to irq_chip_set_wake_parent. The parent chip (OMAP wakeupgen) has no irq_set_wake function either so the call will fail with -ENOSYS. As a result the irq_set_wake() call in the resume path will trigger an 'Unbalanced wake disable' warning. Before the conversion the GIC irqchip was the top level irqchip and correctly flagged with IRQCHIP_SKIP_SET_WAKE. Restore the correct behaviour by removing the irq_set_type callback from the crossbar irqchip and set the IRQCHIP_SKIP_SET_WAKE flag which lets the irq_set_irq_wake() call from the driver succeed. [ tglx: Massaged changelog ] Fixes: 783d31863fb8 ('irqchip: crossbar: Convert dra7 crossbar...') Signed-off-by: Grygorii Strashko Cc: Sudeep Holla Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1439554830-19502-7-git-send-email-grygorii.strashko@ti.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index f5a72cc..c12bb93 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -68,9 +68,9 @@ static struct irq_chip crossbar_chip = { .irq_mask = irq_chip_mask_parent, .irq_unmask = irq_chip_unmask_parent, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_set_wake = irq_chip_set_wake_parent, .irq_set_type = irq_chip_set_type_parent, - .flags = IRQCHIP_MASK_ON_SUSPEND, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, #ifdef CONFIG_SMP .irq_set_affinity = irq_chip_set_affinity_parent, #endif -- cgit v0.10.2 From 1c73d3b10e6976919ce3caa5110e05e04326a7ec Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 28 Mar 2015 18:13:52 +0000 Subject: drm/edid: add function to help find SADs Add a function to find the start of the SADs in the ELD. This complements the helper to retrieve the SAD count. [airlied: this fixes a build problem with the alsa eld helper which required this]. Signed-off-by: Russell King Signed-off-by: Dave Airlie diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 7990501..53c53c4 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -348,6 +348,25 @@ static inline int drm_eld_mnl(const uint8_t *eld) } /** + * drm_eld_sad - Get ELD SAD structures. + * @eld: pointer to an eld memory structure with sad_count set + */ +static inline const uint8_t *drm_eld_sad(const uint8_t *eld) +{ + unsigned int ver, mnl; + + ver = (eld[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT; + if (ver != 2 && ver != 31) + return NULL; + + mnl = drm_eld_mnl(eld); + if (mnl > 16) + return NULL; + + return eld + DRM_ELD_CEA_SAD(mnl, 0); +} + +/** * drm_eld_sad_count - Get ELD SAD count. * @eld: pointer to an eld memory structure with sad_count set */ -- cgit v0.10.2 From 87ffd2b9bb74061c120f450e4d0f3409bb603ae0 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 20 Aug 2015 11:33:41 +0100 Subject: x86/xen: make CONFIG_XEN depend on CONFIG_X86_LOCAL_APIC Since commit feb44f1f7a4ac299d1ab1c3606860e70b9b89d69 (x86/xen: Provide a "Xen PV" APIC driver to support >255 VCPUs) Xen guests need a full APIC driver and thus should depend on X86_LOCAL_APIC. This fixes an i386 build failure with !SMP && !CONFIG_X86_UP_APIC by disabling Xen support in this configuration. Users needing Xen support in a non-SMP i386 kernel will need to enable CONFIG_X86_UP_APIC. Signed-off-by: David Vrabel Cc: diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index e88fda8..4841453 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -8,7 +8,7 @@ config XEN select PARAVIRT_CLOCK select XEN_HAVE_PVMMU depends on X86_64 || (X86_32 && X86_PAE) - depends on X86_TSC + depends on X86_LOCAL_APIC && X86_TSC help This is the Linux Xen port. Enabling this will allow the kernel to boot in a paravirtualized environment under the @@ -17,7 +17,7 @@ config XEN config XEN_DOM0 def_bool y depends on XEN && PCI_XEN && SWIOTLB_XEN - depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI + depends on X86_IO_APIC && ACPI && PCI config XEN_PVHVM def_bool y -- cgit v0.10.2 From be3b0f9babc0b29931b75f7048d81f966473ce13 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 20 Aug 2015 03:27:21 -0700 Subject: clocksource/imx: Fix boot with non-DT systems Commit 6dd747825b20 ("ARM: imx: move timer resources into a structure") moved initialization parameters into a data structure, but neglected to set the irq field in that data structure for non-DT boots. This causes the system to hang if a non-DT boot is attempted. Fixes: 6dd747825b20 ("ARM: imx: move timer resources into a structure") Signed-off-by: Guenter Roeck Cc: Shawn Guo Cc: Daniel Lezcano Link: http://lkml.kernel.org/r/1440066441-13930-1-git-send-email-linux@roeck-us.net Signed-off-by: Thomas Gleixner diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 2d59038..86c7eb6 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -462,6 +462,7 @@ void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type) BUG_ON(!imxtm->base); imxtm->type = type; + imxtm->irq = irq; _mxc_timer_init(imxtm); } -- cgit v0.10.2 From 14a500fe1396934c6b3ed8f009459a4723da7862 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 20 Aug 2015 22:11:15 +0530 Subject: ASoC: samsung: Remove redundant arndale_audio_remove There is no use of snd_soc_unregister_card in remove function as devm_snd_soc_register_card in probe function automatically handles it. So, remove use of snd_soc_unregister_card and with this change remove arndale_audio_remove as it is now redundant. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index 8bf2e2c..9e371eb 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -116,15 +116,6 @@ static int arndale_audio_probe(struct platform_device *pdev) return ret; } -static int arndale_audio_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - snd_soc_unregister_card(card); - - return 0; -} - static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { { .compatible = "samsung,arndale-rt5631", }, { .compatible = "samsung,arndale-alc5631", }, @@ -139,7 +130,6 @@ static struct platform_driver arndale_audio_driver = { .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), }, .probe = arndale_audio_probe, - .remove = arndale_audio_remove, }; module_platform_driver(arndale_audio_driver); -- cgit v0.10.2 From e134cb2041359c927b735b81568373624ea26baf Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Fri, 14 Aug 2015 11:22:16 +0800 Subject: ASoC: wm8994: fix add dynamic path error If there don't exist dynamic sink or source widget, it will failed to add dynamic path. "AIF3ADCDAT" is snd_soc_dapm_aif_out, can't be dynamic sink widget. So change the audio route to fix this issue. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 962e1d3..2ccbb32 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1942,14 +1942,16 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF2ADCDAT", NULL, "AIF2ADC Mux" }, /* AIF3 output */ - { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1L" }, - { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC1R" }, - { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2L" }, - { "AIF3ADCDAT", "AIF1ADCDAT", "AIF1ADC2R" }, - { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCL" }, - { "AIF3ADCDAT", "AIF2ADCDAT", "AIF2ADCR" }, - { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, - { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, + { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1L" }, + { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1R" }, + { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2L" }, + { "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2R" }, + { "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, + { "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, + { "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACL" }, + { "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACR" }, + + { "AIF3ADCDAT", NULL, "AIF3ADC Mux" }, /* Loopback */ { "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" }, -- cgit v0.10.2 From 1ae5ddb6f8837558928a1a694c7b8af7f09fdd21 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Thu, 20 Aug 2015 12:00:19 -0700 Subject: Input: gpio_keys_polled - request GPIO pin as input. GPIOF_IN flag was lost in: Commit 633a21d80b4a("input: gpio_keys_polled: Add support for GPIO descriptors"). Without this flag, legacy code path (for non-descriptor GPIO declarations) would configure GPIO as output (0 meaning GPIOF_DIR_OUT | GPIOF_INIT_LOW). Cc: stable@vger.kernel.org Signed-off-by: Vincent Pelletier Reviewed-by: Mika Westerberg Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 90df4df..959b826 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -246,7 +246,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) * convert it to descriptor. */ if (!button->gpiod && gpio_is_valid(button->gpio)) { - unsigned flags = 0; + unsigned flags = GPIOF_IN; if (button->active_low) flags |= GPIOF_ACTIVE_LOW; -- cgit v0.10.2 From e43d0189ac02415fe4487f79fc35e8f147e9ea0d Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 20 Aug 2015 12:54:39 +0800 Subject: x86/idle: Restore trace_cpu_idle to mwait_idle() calls Commit b253149b843f ("sched/idle/x86: Restore mwait_idle() to fix boot hangs, to improve power savings and to improve performance") restores mwait_idle(), but the trace_cpu_idle related calls are missing. This causes powertop on my old desktop powered by Intel Core2 E6550 to report zero wakeups and zero events. Add them back to restore the proper behaviour. Fixes: b253149b843f ("sched/idle/x86: Restore mwait_idle() to ...") Signed-off-by: Jisheng Zhang Cc: Cc: stable@vger.kernel.org # 4.1 Link: http://lkml.kernel.org/r/1440046479-4262-1-git-send-email-jszhang@marvell.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 397688b..c27cad7 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -408,6 +408,7 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c) static void mwait_idle(void) { if (!current_set_polling_and_test()) { + trace_cpu_idle_rcuidle(1, smp_processor_id()); if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR)) { smp_mb(); /* quirk */ clflush((void *)¤t_thread_info()->flags); @@ -419,6 +420,7 @@ static void mwait_idle(void) __sti_mwait(0, 0); else local_irq_enable(); + trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); } else { local_irq_enable(); } -- cgit v0.10.2 From 45ea2a5fed6dacb9bb0558d8b21eacc1c45d5bb4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 20 Aug 2015 00:08:15 -0500 Subject: PCI: Don't use 64-bit bus addresses on PA-RISC Meelis and Helge reported that 3a9ad0b4fdcd ("PCI: Add pci_bus_addr_t") caused HPMCs on A500 and hangs on rp5470. PA-RISC does not set ARCH_DMA_ADDR_T_64BIT, even for 64-bit kernels, so prior to 3a9ad0b4fdcd, we always used 32-bit PCI addresses. After 3a9ad0b4fdcd, we do use 64-bit PCI addresses in 64-bit kernels, and apparently there's some PA-RISC problem related to them. Fixes: 3a9ad0b4fdcd ("PCI: Add pci_bus_addr_t") Link: http://lkml.kernel.org/r/alpine.LRH.2.11.1507260929000.30065@math.ut.ee Reported-by: Meelis Roos Reported-by: Helge Deller Tested-by: Helge Deller Based-on-idea-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu CC: stable@vger.kernel.org # v3.19+ diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 73de4ef..944f500 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -2,7 +2,7 @@ # PCI configuration # config PCI_BUS_ADDR_T_64BIT - def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) + def_bool y if (ARCH_DMA_ADDR_T_64BIT || (64BIT && !PARISC)) depends on PCI config PCI_MSI -- cgit v0.10.2 From 7f98ca454ad373fc1b76be804fa7138ff68c1d27 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 20 Aug 2015 10:13:55 +1000 Subject: drm/radeon: fix hotplug race at startup We apparantly get a hotplug irq before we've initialised modesetting, [drm] Loading R100 Microcode BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] __mutex_lock_slowpath+0x23/0x91 *pde = 00000000 Oops: 0002 [#1] Modules linked in: radeon(+) drm_kms_helper ttm drm i2c_algo_bit backlight pcspkr psmouse evdev sr_mod input_leds led_class cdrom sg parport_pc parport floppy intel_agp intel_gtt lpc_ich acpi_cpufreq processor button mfd_core agpgart uhci_hcd ehci_hcd rng_core snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm usbcore usb_common i2c_i801 i2c_core snd_timer snd soundcore thermal_sys CPU: 0 PID: 15 Comm: kworker/0:1 Not tainted 4.2.0-rc7-00015-gbf67402 #111 Hardware name: MicroLink /D850MV , BIOS MV85010A.86A.0067.P24.0304081124 04/08/2003 Workqueue: events radeon_hotplug_work_func [radeon] task: f6ca5900 ti: f6d3e000 task.ti: f6d3e000 EIP: 0060:[] EFLAGS: 00010282 CPU: 0 EIP is at __mutex_lock_slowpath+0x23/0x91 EAX: 00000000 EBX: f5e900fc ECX: 00000000 EDX: fffffffe ESI: f6ca5900 EDI: f5e90100 EBP: f5e90000 ESP: f6d3ff0c DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 CR0: 8005003b CR2: 00000000 CR3: 36f61000 CR4: 000006d0 Stack: f5e90100 00000000 c103c4c1 f6d2a5a0 f5e900fc f6df394c c125f162 f8b0faca f6d2a5a0 c138ca00 f6df394c f7395600 c1034741 00d40000 00000000 f6d2a5a0 c138ca00 f6d2a5b8 c138ca10 c1034b58 00000001 f6d40000 f6ca5900 f6d0c940 Call Trace: [] ? dequeue_task_fair+0xa4/0xb7 [] ? mutex_lock+0x9/0xa [] ? radeon_hotplug_work_func+0x17/0x57 [radeon] [] ? process_one_work+0xfc/0x194 [] ? worker_thread+0x18d/0x218 [] ? rescuer_thread+0x1d5/0x1d5 [] ? kthread+0x7b/0x80 [] ? ret_from_kernel_thread+0x20/0x30 [] ? init_completion+0x18/0x18 Code: 42 08 e8 8e a6 dd ff c3 57 56 53 83 ec 0c 8b 35 48 f7 37 c1 8b 10 4a 74 1a 89 c3 8d 78 04 8b 40 08 89 63 Reported-and-Tested-by: Meelis Roos Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 1162bfa..171d3e4 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -79,6 +79,11 @@ static void radeon_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + /* we can race here at startup, some boards seem to trigger + * hotplug irqs when they shouldn't. */ + if (!rdev->mode_info.mode_config_initialized) + return; + mutex_lock(&mode_config->mutex); if (mode_config->num_connector) { list_for_each_entry(connector, &mode_config->connector_list, head) -- cgit v0.10.2 From 54d8697fa5036df0e27f8d62edb7ebc35c3f73d6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Aug 2015 20:59:21 +0800 Subject: ASoC: Set missing card owner field Set the card owner field to prevent the module from being removed from underneath its users. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bfin-eval-adau1x61.c b/sound/soc/blackfin/bfin-eval-adau1x61.c index 4229f76..fddfe00c 100644 --- a/sound/soc/blackfin/bfin-eval-adau1x61.c +++ b/sound/soc/blackfin/bfin-eval-adau1x61.c @@ -108,6 +108,7 @@ static struct snd_soc_dai_link bfin_eval_adau1x61_dai = { static struct snd_soc_card bfin_eval_adau1x61 = { .name = "bfin-eval-adau1x61", + .owner = THIS_MODULE, .driver_name = "eval-adau1x61", .dai_link = &bfin_eval_adau1x61_dai, .num_links = 1, diff --git a/sound/soc/intel/boards/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c index 7ab8cc9..d9f81b8 100644 --- a/sound/soc/intel/boards/byt-max98090.c +++ b/sound/soc/intel/boards/byt-max98090.c @@ -126,6 +126,7 @@ static struct snd_soc_dai_link byt_max98090_dais[] = { static struct snd_soc_card byt_max98090_card = { .name = "byt-max98090", + .owner = THIS_MODULE, .dai_link = byt_max98090_dais, .num_links = ARRAY_SIZE(byt_max98090_dais), .dapm_widgets = byt_max98090_widgets, diff --git a/sound/soc/intel/boards/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c index ae89b9b9..de9788a 100644 --- a/sound/soc/intel/boards/byt-rt5640.c +++ b/sound/soc/intel/boards/byt-rt5640.c @@ -197,6 +197,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static struct snd_soc_card byt_rt5640_card = { .name = "byt-rt5640", + .owner = THIS_MODULE, .dai_link = byt_rt5640_dais, .num_links = ARRAY_SIZE(byt_rt5640_dais), .dapm_widgets = byt_rt5640_widgets, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 7f55d59..c445312 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -185,6 +185,7 @@ static struct snd_soc_dai_link byt_dailink[] = { /* SoC card */ static struct snd_soc_card snd_soc_card_byt = { .name = "baytrailcraudio", + .owner = THIS_MODULE, .dai_link = byt_dailink, .num_links = ARRAY_SIZE(byt_dailink), .dapm_widgets = byt_dapm_widgets, diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d604ee8..cd25953 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -279,6 +279,7 @@ static struct snd_soc_dai_link cht_dailink[] = { /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { .name = "chtmax98090", + .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), .aux_dev = &cht_max98090_headset_dev, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index bdcaf46..7be8461 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -305,6 +305,7 @@ static struct snd_soc_dai_link cht_dailink[] = { /* SoC card */ static struct snd_soc_card snd_soc_card_chtrt5645 = { .name = "chtrt5645", + .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), .dapm_widgets = cht_dapm_widgets, @@ -317,6 +318,7 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = { static struct snd_soc_card snd_soc_card_chtrt5650 = { .name = "chtrt5650", + .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), .dapm_widgets = cht_dapm_widgets, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 2c9cc5b..23fe040 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -323,6 +323,7 @@ static int cht_resume_post(struct snd_soc_card *card) /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { .name = "cherrytrailcraudio", + .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), .dapm_widgets = cht_dapm_widgets, diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c index 4d44b58..fb8f97e 100644 --- a/sound/soc/mediatek/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173-max98090.c @@ -139,6 +139,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { static struct snd_soc_card mt8173_max98090_card = { .name = "mt8173-max98090", + .owner = THIS_MODULE, .dai_link = mt8173_max98090_dais, .num_links = ARRAY_SIZE(mt8173_max98090_dais), .controls = mt8173_max98090_controls, diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 0940553..caf8c47 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c @@ -194,6 +194,7 @@ static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = { static struct snd_soc_card mt8173_rt5650_rt5676_card = { .name = "mtk-rt5650-rt5676", + .owner = THIS_MODULE, .dai_link = mt8173_rt5650_rt5676_dais, .num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais), .codec_conf = mt8173_rt5650_rt5676_codec_conf, diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index acace20..cc26f81 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -147,6 +147,7 @@ static struct snd_soc_dai_link rk_dailink = { static struct snd_soc_card snd_soc_card_rk = { .name = "ROCKCHIP-I2S", + .owner = THIS_MODULE, .dai_link = &rk_dailink, .num_links = 1, .aux_dev = &rk_98090_headset_dev, diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 3c6bb1e..0940279 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -146,6 +146,7 @@ static struct snd_soc_dai_link rk_dailink = { static struct snd_soc_card snd_soc_card_rk = { .name = "I2S-RT5650", + .owner = THIS_MODULE, .dai_link = &rk_dailink, .num_links = 1, .dapm_widgets = rk_dapm_widgets, diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index 8bf2e2c..323aa0d 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -71,6 +71,7 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = { static struct snd_soc_card arndale_rt5631 = { .name = "Arndale RT5631", + .owner = THIS_MODULE, .dai_link = arndale_rt5631_dai, .num_links = ARRAY_SIZE(arndale_rt5631_dai), }; diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 7651dc9..07ce2cf 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -56,6 +56,7 @@ static int snow_late_probe(struct snd_soc_card *card) static struct snd_soc_card snow_snd = { .name = "Snow-I2S", + .owner = THIS_MODULE, .dai_link = snow_dai, .num_links = ARRAY_SIZE(snow_dai), -- cgit v0.10.2 From 2f064f3485cd29633ad1b3cfb00cc519509a3d72 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Fri, 21 Aug 2015 14:11:51 -0700 Subject: mm: make page pfmemalloc check more robust Commit c48a11c7ad26 ("netvm: propagate page->pfmemalloc to skb") added checks for page->pfmemalloc to __skb_fill_page_desc(): if (page->pfmemalloc && !page->mapping) skb->pfmemalloc = true; It assumes page->mapping == NULL implies that page->pfmemalloc can be trusted. However, __delete_from_page_cache() can set set page->mapping to NULL and leave page->index value alone. Due to being in union, a non-zero page->index will be interpreted as true page->pfmemalloc. So the assumption is invalid if the networking code can see such a page. And it seems it can. We have encountered this with a NFS over loopback setup when such a page is attached to a new skbuf. There is no copying going on in this case so the page confuses __skb_fill_page_desc which interprets the index as pfmemalloc flag and the network stack drops packets that have been allocated using the reserves unless they are to be queued on sockets handling the swapping which is the case here and that leads to hangs when the nfs client waits for a response from the server which has been dropped and thus never arrive. The struct page is already heavily packed so rather than finding another hole to put it in, let's do a trick instead. We can reuse the index again but define it to an impossible value (-1UL). This is the page index so it should never see the value that large. Replace all direct users of page->pfmemalloc by page_is_pfmemalloc which will hide this nastiness from unspoiled eyes. The information will get lost if somebody wants to use page->index obviously but that was the case before and the original code expected that the information should be persisted somewhere else if that is really needed (e.g. what SLAB and SLUB do). [akpm@linux-foundation.org: fix blooper in slub] Fixes: c48a11c7ad26 ("netvm: propagate page->pfmemalloc to skb") Signed-off-by: Michal Hocko Debugged-by: Vlastimil Babka Debugged-by: Jiri Bohac Cc: Eric Dumazet Cc: David Miller Acked-by: Mel Gorman Cc: [3.6+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 982fdcd..b5b2925 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -216,7 +216,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring, static inline bool fm10k_page_is_reserved(struct page *page) { - return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; + return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); } static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 2f70a9b..830466c 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6566,7 +6566,7 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring, static inline bool igb_page_is_reserved(struct page *page) { - return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; + return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); } static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9aa6104..ae21e0b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1832,7 +1832,7 @@ static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring, static inline bool ixgbe_page_is_reserved(struct page *page) { - return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; + return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); } /** diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index e71cdde..1d7b00b 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -765,7 +765,7 @@ static void ixgbevf_reuse_rx_page(struct ixgbevf_ring *rx_ring, static inline bool ixgbevf_page_is_reserved(struct page *page) { - return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; + return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page); } /** diff --git a/include/linux/mm.h b/include/linux/mm.h index 2e872f9..bf6f117 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1003,6 +1003,34 @@ static inline int page_mapped(struct page *page) } /* + * Return true only if the page has been allocated with + * ALLOC_NO_WATERMARKS and the low watermark was not + * met implying that the system is under some pressure. + */ +static inline bool page_is_pfmemalloc(struct page *page) +{ + /* + * Page index cannot be this large so this must be + * a pfmemalloc page. + */ + return page->index == -1UL; +} + +/* + * Only to be called by the page allocator on a freshly allocated + * page. + */ +static inline void set_page_pfmemalloc(struct page *page) +{ + page->index = -1UL; +} + +static inline void clear_page_pfmemalloc(struct page *page) +{ + page->index = 0; +} + +/* * Different kinds of faults, as returned by handle_mm_fault(). * Used to decide whether a process gets delivered SIGBUS or * just gets major/minor fault counters bumped up. diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 0038ac7..1554957 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -63,15 +63,6 @@ struct page { union { pgoff_t index; /* Our offset within mapping. */ void *freelist; /* sl[aou]b first free object */ - bool pfmemalloc; /* If set by the page allocator, - * ALLOC_NO_WATERMARKS was set - * and the low watermark was not - * met implying that the system - * is under some pressure. The - * caller should try ensure - * this page is only used to - * free other pages. - */ }; union { diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 22b6d9c..9b88536 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1602,20 +1602,16 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; /* - * Propagate page->pfmemalloc to the skb if we can. The problem is - * that not all callers have unique ownership of the page. If - * pfmemalloc is set, we check the mapping as a mapping implies - * page->index is set (index and pfmemalloc share space). - * If it's a valid mapping, we cannot use page->pfmemalloc but we - * do not lose pfmemalloc information as the pages would not be - * allocated using __GFP_MEMALLOC. + * Propagate page pfmemalloc to the skb if we can. The problem is + * that not all callers have unique ownership of the page but rely + * on page_is_pfmemalloc doing the right thing(tm). */ frag->page.p = page; frag->page_offset = off; skb_frag_size_set(frag, size); page = compound_head(page); - if (page->pfmemalloc && !page->mapping) + if (page_is_pfmemalloc(page)) skb->pfmemalloc = true; } @@ -2263,7 +2259,7 @@ static inline struct page *dev_alloc_page(void) static inline void skb_propagate_pfmemalloc(struct page *page, struct sk_buff *skb) { - if (page && page->pfmemalloc) + if (page_is_pfmemalloc(page)) skb->pfmemalloc = true; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index df959b7..5b5240b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1343,12 +1343,15 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, set_page_owner(page, order, gfp_flags); /* - * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was necessary to + * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to * allocate the page. The expectation is that the caller is taking * steps that will free more memory. The caller should avoid the page * being used for !PFMEMALLOC purposes. */ - page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS); + if (alloc_flags & ALLOC_NO_WATERMARKS) + set_page_pfmemalloc(page); + else + clear_page_pfmemalloc(page); return 0; } @@ -3345,7 +3348,7 @@ refill: atomic_add(size - 1, &page->_count); /* reset page count bias and offset to start of new frag */ - nc->pfmemalloc = page->pfmemalloc; + nc->pfmemalloc = page_is_pfmemalloc(page); nc->pagecnt_bias = size; nc->offset = size; } diff --git a/mm/slab.c b/mm/slab.c index 200e224..bbd0b47 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1603,7 +1603,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, } /* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */ - if (unlikely(page->pfmemalloc)) + if (page_is_pfmemalloc(page)) pfmemalloc_active = true; nr_pages = (1 << cachep->gfporder); @@ -1614,7 +1614,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, add_zone_page_state(page_zone(page), NR_SLAB_UNRECLAIMABLE, nr_pages); __SetPageSlab(page); - if (page->pfmemalloc) + if (page_is_pfmemalloc(page)) SetPageSlabPfmemalloc(page); if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) { diff --git a/mm/slub.c b/mm/slub.c index 816df00..f68c0e5 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1427,7 +1427,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) inc_slabs_node(s, page_to_nid(page), page->objects); page->slab_cache = s; __SetPageSlab(page); - if (page->pfmemalloc) + if (page_is_pfmemalloc(page)) SetPageSlabPfmemalloc(page); start = page_address(page); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bf9a5d9..7b84330 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -340,7 +340,7 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size) if (skb && frag_size) { skb->head_frag = 1; - if (virt_to_head_page(data)->pfmemalloc) + if (page_is_pfmemalloc(virt_to_head_page(data))) skb->pfmemalloc = 1; } return skb; -- cgit v0.10.2 From e525293d97b93a04038e7dc15cee3e9075c32dbd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 21 Aug 2015 14:11:54 -0700 Subject: Add hch to .get_maintainer.ignore While the idea behind get_maintainer seems highly useful it's unfortunately way to trigger happy to grab people that once had a few commits to files. For someone like me who does a lot of tree-wide API work that leads to an incredible amount of Cc spam. Signed-off-by: Christoph Hellwig Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/.get_maintainer.ignore b/.get_maintainer.ignore new file mode 100644 index 0000000..cca6d87 --- /dev/null +++ b/.get_maintainer.ignore @@ -0,0 +1 @@ +Christoph Hellwig -- cgit v0.10.2 From 88a17d8fb7c4a156ec13e6668b46dbbedf670ff7 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 18 Aug 2015 18:11:51 +0800 Subject: ASoC: topology: Bind vendor specific kcontrol handlers before standard ones Vendor specific handlers should override standard handlers. So we can handle things in the order from specific to generic. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 865a141..a6541a1 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -136,7 +136,7 @@ struct snd_soc_tplg_ops { int (*manifest)(struct snd_soc_component *, struct snd_soc_tplg_manifest *); - /* bespoke kcontrol handlers available for binding */ + /* vendor specific kcontrol handlers available for binding */ const struct snd_soc_tplg_kcontrol_ops *io_ops; int io_ops_count; }; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 73e959c..ca551b9 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -66,7 +66,7 @@ struct soc_tplg { u32 index; /* current block index */ u32 req_index; /* required index, only loaded/free matching blocks */ - /* kcontrol operations */ + /* vendor specific kcontrol operations */ const struct snd_soc_tplg_kcontrol_ops *io_ops; int io_ops_count; @@ -513,22 +513,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, { int i; - /* try and map standard kcontrols handler first */ - for (i = 0; i < num_ops; i++) { - - if (ops[i].id == hdr->ops.put) - k->put = ops[i].put; - if (ops[i].id == hdr->ops.get) - k->get = ops[i].get; - if (ops[i].id == hdr->ops.info) - k->info = ops[i].info; - } - - /* standard handlers found ? */ - if (k->put && k->get && k->info) - return 0; - - /* none found so try bespoke handlers */ + /* try and map vendor specific kcontrol handlers first */ for (i = 0; i < num_bops; i++) { if (k->put == NULL && bops[i].id == hdr->ops.put) @@ -539,7 +524,22 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, k->info = bops[i].info; } - /* bespoke handlers found ? */ + /* vendor specific handlers found ? */ + if (k->put && k->get && k->info) + return 0; + + /* none found so try standard kcontrol handlers */ + for (i = 0; i < num_ops; i++) { + + if (k->put == NULL && ops[i].id == hdr->ops.put) + k->put = ops[i].put; + if (k->get == NULL && ops[i].id == hdr->ops.get) + k->get = ops[i].get; + if (k->info == NULL && ops[i].id == hdr->ops.info) + k->info = ops[i].info; + } + + /* standard handlers found ? */ if (k->put && k->get && k->info) return 0; -- cgit v0.10.2 From 2b5cdb9156f76162d5302e2847f84a79de8a3ad1 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 18 Aug 2015 18:12:01 +0800 Subject: ASoC: topology: Reduce arguments of soc_tplg_kcontrol_bind_io() Add the pointer of struct soc_tplg as one argument, so no need to pass standard/vendor specific kcontrol handlers and their count. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ca551b9..c4a58d7 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -508,20 +508,22 @@ static void remove_pcm_dai(struct snd_soc_component *comp, /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, - const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops, - const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops) + const struct soc_tplg *tplg) { - int i; + const struct snd_soc_tplg_kcontrol_ops *ops; + int num_ops, i; /* try and map vendor specific kcontrol handlers first */ - for (i = 0; i < num_bops; i++) { - - if (k->put == NULL && bops[i].id == hdr->ops.put) - k->put = bops[i].put; - if (k->get == NULL && bops[i].id == hdr->ops.get) - k->get = bops[i].get; - if (k->info == NULL && bops[i].id == hdr->ops.info) - k->info = bops[i].info; + ops = tplg->io_ops; + num_ops = tplg->io_ops_count; + for (i = 0; i < num_ops; i++) { + + if (k->put == NULL && ops[i].id == hdr->ops.put) + k->put = ops[i].put; + if (k->get == NULL && ops[i].id == hdr->ops.get) + k->get = ops[i].get; + if (k->info == NULL && ops[i].id == hdr->ops.info) + k->info = ops[i].info; } /* vendor specific handlers found ? */ @@ -529,6 +531,8 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, return 0; /* none found so try standard kcontrol handlers */ + ops = io_ops; + num_ops = ARRAY_SIZE(io_ops); for (i = 0; i < num_ops; i++) { if (k->put == NULL && ops[i].id == hdr->ops.put) @@ -682,8 +686,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, INIT_LIST_HEAD(&sbe->dobj.list); /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); if (err) { soc_control_err(tplg, &be->hdr, be->hdr.name); kfree(sbe); @@ -777,8 +780,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, INIT_LIST_HEAD(&sm->dobj.list); /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); if (err) { soc_control_err(tplg, &mc->hdr, mc->hdr.name); kfree(sm); @@ -950,8 +952,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, } /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg); if (err) { soc_control_err(tplg, &ec->hdr, ec->hdr.name); kfree(se); @@ -1137,8 +1138,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( INIT_LIST_HEAD(&sm->dobj.list); /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg); if (err) { soc_control_err(tplg, &mc->hdr, mc->hdr.name); kfree(sm); @@ -1235,8 +1235,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( } /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); if (err) { soc_control_err(tplg, &ec->hdr, ec->hdr.name); goto err_se; @@ -1306,9 +1305,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( INIT_LIST_HEAD(&sbe->dobj.list); /* map standard io handlers and check for external handlers */ - err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops, - ARRAY_SIZE(io_ops), tplg->io_ops, - tplg->io_ops_count); + err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg); if (err) { soc_control_err(tplg, &be->hdr, be->hdr.name); kfree(sbe); -- cgit v0.10.2 From 1a3232d2f61d2853a848464b7bde2d54960c58bb Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 18 Aug 2015 18:12:20 +0800 Subject: ASoC: topology: Add support for TLV bytes controls Allow vendor drivers to define bespoke bytes ext handlers and IDs for TLV bytes controls. And the topology core will bind these handlers by matching IDs defined by the vendor driver and user space topology data file. And TLV callback binding is moved to soc_tplg_kcontrol_bind_io(). This function process all handler binding now. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index a6541a1..ea387ed 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -89,6 +89,13 @@ struct snd_soc_tplg_kcontrol_ops { struct snd_ctl_elem_info *uinfo); }; +/* Bytes ext operations, for TLV byte controls */ +struct snd_soc_tplg_bytes_ext_ops { + u32 id; + int (*get)(unsigned int __user *bytes, unsigned int size); + int (*put)(const unsigned int __user *bytes, unsigned int size); +}; + /* * DAPM widget event handlers - used to map handlers onto widgets. */ @@ -139,6 +146,10 @@ struct snd_soc_tplg_ops { /* vendor specific kcontrol handlers available for binding */ const struct snd_soc_tplg_kcontrol_ops *io_ops; int io_ops_count; + + /* vendor specific bytes ext handlers available for binding */ + const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops; + int bytes_ext_ops_count; }; /* gets a pointer to data from the firmware block header */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c4a58d7..5690b7e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -70,6 +70,10 @@ struct soc_tplg { const struct snd_soc_tplg_kcontrol_ops *io_ops; int io_ops_count; + /* vendor specific bytes ext handlers, for TLV bytes controls */ + const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops; + int bytes_ext_ops_count; + /* optional fw loading callbacks to component drivers */ struct snd_soc_tplg_ops *ops; }; @@ -511,8 +515,40 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, const struct soc_tplg *tplg) { const struct snd_soc_tplg_kcontrol_ops *ops; + const struct snd_soc_tplg_bytes_ext_ops *ext_ops; int num_ops, i; + if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES + && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER + && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE + && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + struct soc_bytes_ext *sbe; + struct snd_soc_tplg_bytes_control *be; + + sbe = (struct soc_bytes_ext *)k->private_value; + be = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); + + /* TLV bytes controls need standard kcontrol info handler, + * TLV callback and extended put/get handlers. + */ + k->info = snd_soc_bytes_info; + k->tlv.c = snd_soc_bytes_tlv_callback; + + ext_ops = tplg->bytes_ext_ops; + num_ops = tplg->bytes_ext_ops_count; + for (i = 0; i < num_ops; i++) { + if (!sbe->put && ext_ops[i].id == be->ext_ops.put) + sbe->put = ext_ops[i].put; + if (!sbe->get && ext_ops[i].id == be->ext_ops.get) + sbe->get = ext_ops[i].get; + } + + if (sbe->put && sbe->get) + return 0; + else + return -EINVAL; + } + /* try and map vendor specific kcontrol handlers first */ ops = tplg->io_ops; num_ops = tplg->io_ops_count; @@ -613,9 +649,7 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) return 0; - if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - kc->tlv.c = snd_soc_bytes_tlv_callback; - } else { + if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { tplg_tlv = &tc->tlv; switch (tplg_tlv->type) { case SNDRV_CTL_TLVT_DB_SCALE: @@ -1733,6 +1767,8 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, tplg.req_index = id; tplg.io_ops = ops->io_ops; tplg.io_ops_count = ops->io_ops_count; + tplg.bytes_ext_ops = ops->bytes_ext_ops; + tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count; return soc_tplg_load(&tplg); } -- cgit v0.10.2 From 5fc960380ea44ba529c78b558b6cd4250e5e1958 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 22 Aug 2015 09:52:06 +0200 Subject: x86/fpu/math-emu: Fix math-emu boot crash On a math-emu bootup the following crash occurs: Initializing CPU#0 ------------[ cut here ]------------ kernel BUG at arch/x86/kernel/traps.c:779! invalid opcode: 0000 [#1] SMP [...] EIP is at do_device_not_available+0xe/0x70 [...] Call Trace: [] error_code+0x5a/0x60 [] ? math_error+0x140/0x140 [] ? fpu__init_cpu+0x59/0xa0 [] cpu_init+0x202/0x330 [] ? __native_set_fixmap+0x1f/0x30 [] trap_init+0x305/0x346 [] start_kernel+0x1a5/0x35d [] i386_start_kernel+0x82/0x86 The reason is that in the following commit: b1276c48e91b ("x86/fpu: Initialize fpregs in fpu__init_cpu_generic()") I failed to consider math-emu's limitation that it cannot execute the FNINIT instruction in kernel mode. The long term fix might be to allow math-emu to execute (certain) kernel mode FPU instructions, but for now apply the safe (albeit somewhat ugly) fix: initialize the emulation state explicitly without trapping out to the FPU emulator. Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 1e173f6..d14e9ac 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -40,7 +40,12 @@ static void fpu__init_cpu_generic(void) write_cr0(cr0); /* Flush out any pending x87 state: */ - asm volatile ("fninit"); +#ifdef CONFIG_MATH_EMULATION + if (!cpu_has_fpu) + fpstate_init_soft(¤t->thread.fpu.state.soft); + else +#endif + asm volatile ("fninit"); } /* -- cgit v0.10.2 From 827409b2f5b58573ae3774fe6bd2d6daeb335878 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 May 2015 12:22:29 +0200 Subject: x86/fpu/math-emu: Fix crash in fork() During later stages of math-emu bootup the following crash triggers: math_emulate: 0060:c100d0a8 Kernel panic - not syncing: Math emulation needed in kernel CPU: 0 PID: 1511 Comm: login Not tainted 4.2.0-rc7+ #1012 [...] Call Trace: [] dump_stack+0x41/0x52 [] panic+0x77/0x189 [] ? math_error+0x140/0x140 [] math_emulate+0xba7/0xbd0 [] ? fpu__copy+0x138/0x1c0 [] ? __alloc_pages_nodemask+0x12c/0x870 [] ? proc_clear_tty+0x40/0x70 [] ? session_clear_tty+0x1e/0x30 [] ? math_error+0x140/0x140 [] do_device_not_available+0x45/0x70 [] ? fpu__copy+0x138/0x1c0 [] error_code+0x5a/0x60 [] ? math_error+0x140/0x140 [] ? fpu__copy+0x138/0x1c0 [] arch_dup_task_struct+0x25/0x30 [] copy_process.part.51+0xea/0x1480 [] ? dput+0x175/0x200 [] ? no_tty+0x30/0x30 [] ? do_vfs_ioctl+0x322/0x540 [] _do_fork+0xca/0x340 [] ? SyS_rt_sigaction+0x66/0x90 [] SyS_clone+0x27/0x30 [] sysenter_do_call+0x12/0x12 The reason is the incorrect assumption in fpu_copy(), that FNSAVE can be executed from math-emu kernels as well. Don't try to copy the registers, the soft state will be copied by fork anyway, so the child task inherits the parent task's soft math state. With this fix applied math-emu kernels boot up fine on modern hardware and the 'no387 nofxsr' boot options. Cc: Andy Lutomirski Cc: Bobby Powers Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 79de954..d25097c 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -270,7 +270,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) dst_fpu->fpregs_active = 0; dst_fpu->last_cpu = -1; - if (src_fpu->fpstate_active) + if (src_fpu->fpstate_active && cpu_has_fpu) fpu_copy(dst_fpu, src_fpu); return 0; -- cgit v0.10.2 From 999b8b88c6060adf7a9b7907740ae86ace65291e Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 15 Aug 2015 15:49:13 +0200 Subject: 9p: ensure err is initialized to 0 in p9_client_read/write Some use of those functions were providing unitialized values to those functions. Notably, when reading 0 bytes from an empty file on a 9P filesystem, the return code of read() was not 0. Tested with this simple program: #include #include #include #include #include int main(int argc, const char **argv) { assert(argc == 2); char buffer[256]; int fd = open(argv[1], O_RDONLY|O_NOCTTY); assert(fd >= 0); assert(read(fd, buffer, 0) == 0); return 0; } Cc: stable@vger.kernel.org # v4.1 Signed-off-by: Vincent Bernat Signed-off-by: Al Viro diff --git a/net/9p/client.c b/net/9p/client.c index 498454b..ea79ee9 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1541,6 +1541,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err) struct p9_client *clnt = fid->clnt; struct p9_req_t *req; int total = 0; + *err = 0; p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); @@ -1620,6 +1621,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) struct p9_client *clnt = fid->clnt; struct p9_req_t *req; int total = 0; + *err = 0; p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n", fid->fid, (unsigned long long) offset, -- cgit v0.10.2 From c13dcf9f2d6f5f06ef1bf79ec456df614c5e058b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 23 Aug 2015 20:52:59 -0700 Subject: Linux 4.2-rc8 diff --git a/Makefile b/Makefile index 6e88c37..246053f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -rc7 +EXTRAVERSION = -rc8 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* -- cgit v0.10.2 From f755d114cba98708932cba89d8c98c4ab89a83b0 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 23 Aug 2015 00:30:19 +0800 Subject: ASoC: cs4349: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/cs4349.c:389: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: Tim Howe Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 0d010c2..0ac8fc5 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -378,7 +378,6 @@ MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id); static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", - .owner = THIS_MODULE, .of_match_table = cs4349_of_match, }, .id_table = cs4349_i2c_id, -- cgit v0.10.2 From 508a43fdd73072c959f849b4e9eb60a9b523396f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:47:36 +0800 Subject: ASoC: davinci: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 56cb4d9..ec98548 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -651,23 +651,15 @@ static const struct snd_soc_component_driver davinci_i2s_component = { static int davinci_i2s_probe(struct platform_device *pdev) { struct davinci_mcbsp_dev *dev; - struct resource *mem, *ioarea, *res; + struct resource *mem, *res; + void __iomem *io_base; int *dma; int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - - ioarea = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "McBSP region already claimed\n"); - return -EBUSY; - } + io_base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev), GFP_KERNEL); @@ -679,12 +671,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) return -ENODEV; clk_enable(dev->clk); - dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!dev->base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_release_clk; - } + dev->base = io_base; dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b960e62..add6bb9 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1613,7 +1613,7 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; - struct resource *mem, *ioarea, *res, *dat; + struct resource *mem, *res, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; @@ -1648,22 +1648,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } } - ioarea = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "Audio region already claimed\n"); - return -EBUSY; - } + mcasp->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(mcasp->base)) + return PTR_ERR(mcasp->base); pm_runtime_enable(&pdev->dev); - mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!mcasp->base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err; - } - mcasp->op_mode = pdata->op_mode; /* sanity check for tdm slots parameter */ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { -- cgit v0.10.2 From 5aec892a6ebe5a3e2a006d969b5fab59e6c79f63 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:49:05 +0800 Subject: ASoC: omap-mcbsp: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 68a1252..c7563e2 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -965,25 +965,15 @@ int omap_mcbsp_init(struct platform_device *pdev) mcbsp->free = true; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - if (!res) { + if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(mcbsp->dev, "invalid memory resource\n"); - return -ENOMEM; - } - } - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(mcbsp->dev, "memory region already claimed\n"); - return -ENODEV; - } + + mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mcbsp->io_base)) + return PTR_ERR(mcbsp->io_base); mcbsp->phys_base = res->start; mcbsp->reg_cache_size = resource_size(res); - mcbsp->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!mcbsp->io_base) - return -ENOMEM; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); if (!res) -- cgit v0.10.2 From 552ef80389ec2567566be1ccc0dd79f08ba32cce Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:52:30 +0800 Subject: ASoC: SPEAr: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index a402860..977a078 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -203,35 +203,25 @@ static int spdif_in_probe(struct platform_device *pdev) struct spdif_in_dev *host; struct spear_spdif_platform_data *pdata; struct resource *res, *res_fifo; + void __iomem *io_base; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res_fifo) return -EINVAL; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_warn(&pdev->dev, "Failed to get memory resourse\n"); - return -ENOENT; - } - host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) { dev_warn(&pdev->dev, "kzalloc fail\n"); return -ENOMEM; } - host->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!host->io_base) { - dev_warn(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - + host->io_base = io_base; host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) return -EINVAL; -- cgit v0.10.2 From 5e9a3fcfa2ca10e3ff76938fe9a12515ffa41003 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Aug 2015 10:07:13 +0800 Subject: ASoC: tegra: Fix unused variable 'spdif' warning Fix below build warning: CC [M] sound/soc/tegra/tegra20_spdif.o sound/soc/tegra/tegra20_spdif.c: In function 'tegra20_spdif_platform_remove': sound/soc/tegra/tegra20_spdif.c:361:24: warning: unused variable 'spdif' [-Wunused-variable] Signed-off-by: Axel Lin Reviewed-by: Vaishali Thakkar Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 66237bc..0809b1e 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -358,8 +358,6 @@ err_pm_disable: static int tegra20_spdif_platform_remove(struct platform_device *pdev) { - struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); -- cgit v0.10.2 From 7d4d443eb4386d6dbd420fa96303dd8fbc1eefc8 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 21 Aug 2015 21:17:00 -0700 Subject: ASoC: rt5677: Allow arbitrary block read/write via SPI Added rt5677_spi_read() and refactored rt5677_spi_write() so that an arbitrary block in the DSP address space can be read/written via SPI. For example, this allows us to load an ELF DSP firmware with sparse sections, and stream audio samples from DSP ring buffer. Signed-off-by: Ben Zhang Acked-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index ef6348c..3505aaf 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -31,84 +31,197 @@ #include "rt5677-spi.h" +#define RT5677_SPI_BURST_LEN 240 +#define RT5677_SPI_HEADER 5 +#define RT5677_SPI_FREQ 6000000 + +/* The AddressPhase and DataPhase of SPI commands are MSB first on the wire. + * DataPhase word size of 16-bit commands is 2 bytes. + * DataPhase word size of 32-bit commands is 4 bytes. + * DataPhase word size of burst commands is 8 bytes. + * The DSP CPU is little-endian. + */ +#define RT5677_SPI_WRITE_BURST 0x5 +#define RT5677_SPI_READ_BURST 0x4 +#define RT5677_SPI_WRITE_32 0x3 +#define RT5677_SPI_READ_32 0x2 +#define RT5677_SPI_WRITE_16 0x1 +#define RT5677_SPI_READ_16 0x0 + static struct spi_device *g_spi; +static DEFINE_MUTEX(spi_mutex); -/** - * rt5677_spi_write - Write data to SPI. - * @txbuf: Data Buffer for writing. - * @len: Data length. +/* Select a suitable transfer command for the next transfer to ensure + * the transfer address is always naturally aligned while minimizing + * the total number of transfers required. + * + * 3 transfer commands are available: + * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes + * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes + * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes + * + * For example, reading 260 bytes at 0x60030002 uses the following commands: + * 0x60030002 RT5677_SPI_READ_16 2 bytes + * 0x60030004 RT5677_SPI_READ_32 4 bytes + * 0x60030008 RT5677_SPI_READ_BURST 240 bytes + * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes + * 0x60030100 RT5677_SPI_READ_32 4 bytes + * 0x60030104 RT5677_SPI_READ_16 2 bytes * + * Input: + * @read: true for read commands; false for write commands + * @align: alignment of the next transfer address + * @remain: number of bytes remaining to transfer * - * Returns true for success. + * Output: + * @len: number of bytes to transfer with the selected command + * Returns the selected command */ -int rt5677_spi_write(u8 *txbuf, size_t len) +static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len) { - int status; - - status = spi_write(g_spi, txbuf, len); - - if (status) - dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); - - return status; + u8 cmd; + + if (align == 2 || align == 6 || remain == 2) { + cmd = RT5677_SPI_READ_16; + *len = 2; + } else if (align == 4 || remain <= 6) { + cmd = RT5677_SPI_READ_32; + *len = 4; + } else { + cmd = RT5677_SPI_READ_BURST; + *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); + } + return read ? cmd : cmd + 1; } -EXPORT_SYMBOL_GPL(rt5677_spi_write); -/** - * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. - * @addr: Start address. - * @txbuf: Data Buffer for writng. - * @len: Data length, it must be a multiple of 8. - * - * - * Returns true for success. +/* Copy dstlen bytes from src to dst, while reversing byte order for each word. + * If srclen < dstlen, zeros are padded. */ -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) +static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) { - u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; - u8 *write_buf; - unsigned int i, end, offset = 0; - - write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); - - if (write_buf == NULL) - return -ENOMEM; - - while (offset < fw->size) { - if (offset + RT5677_SPI_BUF_LEN <= fw->size) - end = RT5677_SPI_BUF_LEN; - else - end = fw->size % RT5677_SPI_BUF_LEN; - - write_buf[0] = spi_cmd; - write_buf[1] = ((addr + offset) & 0xff000000) >> 24; - write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; - write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; - write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; - - for (i = 0; i < end; i += 8) { - write_buf[i + 12] = fw->data[offset + i + 0]; - write_buf[i + 11] = fw->data[offset + i + 1]; - write_buf[i + 10] = fw->data[offset + i + 2]; - write_buf[i + 9] = fw->data[offset + i + 3]; - write_buf[i + 8] = fw->data[offset + i + 4]; - write_buf[i + 7] = fw->data[offset + i + 5]; - write_buf[i + 6] = fw->data[offset + i + 6]; - write_buf[i + 5] = fw->data[offset + i + 7]; + u32 w, i, si; + u32 word_size = min_t(u32, dstlen, 8); + + for (w = 0; w < dstlen; w += word_size) { + for (i = 0; i < word_size; i++) { + si = w + word_size - i - 1; + dst[w + i] = si < srclen ? src[si] : 0; } + } +} - write_buf[end + 5] = spi_cmd; +/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) +{ + u32 offset; + int status = 0; + struct spi_transfer t[2]; + struct spi_message m; + /* +4 bytes is for the DummyPhase following the AddressPhase */ + u8 header[RT5677_SPI_HEADER + 4]; + u8 body[RT5677_SPI_BURST_LEN]; + u8 spi_cmd; + u8 *cb = rxbuf; + + if (!g_spi) + return -ENODEV; + + if ((addr & 1) || (len & 1)) { + dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); + return -EACCES; + } - rt5677_spi_write(write_buf, end + 6); + memset(t, 0, sizeof(t)); + t[0].tx_buf = header; + t[0].len = sizeof(header); + t[0].speed_hz = RT5677_SPI_FREQ; + t[1].rx_buf = body; + t[1].speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); + + for (offset = 0; offset < len; offset += t[1].len) { + spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7, + len - offset, &t[1].len); + + /* Construct SPI message header */ + header[0] = spi_cmd; + header[1] = ((addr + offset) & 0xff000000) >> 24; + header[2] = ((addr + offset) & 0x00ff0000) >> 16; + header[3] = ((addr + offset) & 0x0000ff00) >> 8; + header[4] = ((addr + offset) & 0x000000ff) >> 0; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + + /* Copy data back to caller buffer */ + rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_read); - offset += RT5677_SPI_BUF_LEN; +/* Write DSP address space using SPI. addr has to be 2-byte aligned. + * If len is not 2-byte aligned, an extra byte of zero is written at the end + * as padding. + */ +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) +{ + u32 offset, len_with_pad = len; + int status = 0; + struct spi_transfer t; + struct spi_message m; + /* +1 byte is for the DummyPhase following the DataPhase */ + u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1]; + u8 *body = buf + RT5677_SPI_HEADER; + u8 spi_cmd; + const u8 *cb = txbuf; + + if (!g_spi) + return -ENODEV; + + if (addr & 1) { + dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); + return -EACCES; } - kfree(write_buf); + if (len & 1) + len_with_pad = len + 1; + + memset(&t, 0, sizeof(t)); + t.tx_buf = buf; + t.speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, &t, 1); + + for (offset = 0; offset < len_with_pad;) { + spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, + len_with_pad - offset, &t.len); + + /* Construct SPI message header */ + buf[0] = spi_cmd; + buf[1] = ((addr + offset) & 0xff000000) >> 24; + buf[2] = ((addr + offset) & 0x00ff0000) >> 16; + buf[3] = ((addr + offset) & 0x0000ff00) >> 8; + buf[4] = ((addr + offset) & 0x000000ff) >> 0; + + /* Fetch data from caller buffer */ + rt5677_spi_reverse(body, t.len, cb + offset, len - offset); + offset += t.len; + t.len += RT5677_SPI_HEADER + 1; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_write); - return 0; +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) +{ + return rt5677_spi_write(addr, fw->data, fw->size); } -EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); +EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); static int rt5677_spi_probe(struct spi_device *spi) { diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h index ec41b2b..662db16 100644 --- a/sound/soc/codecs/rt5677-spi.h +++ b/sound/soc/codecs/rt5677-spi.h @@ -12,10 +12,8 @@ #ifndef __RT5677_SPI_H__ #define __RT5677_SPI_H__ -#define RT5677_SPI_BUF_LEN 240 -#define RT5677_SPI_CMD_BURST_WRITE 0x05 - -int rt5677_spi_write(u8 *txbuf, size_t len); -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); #endif /* __RT5677_SPI_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 3f890a6..d916d0c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -745,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x50000000, rt5677->fw1); + rt5677_spi_write_firmware(0x50000000, rt5677->fw1); release_firmware(rt5677->fw1); } ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x60000000, rt5677->fw2); + rt5677_spi_write_firmware(0x60000000, rt5677->fw2); release_firmware(rt5677->fw2); } -- cgit v0.10.2 From 588cd850f5089cb63e031e8d70e9c081b0d97ab2 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:56 +0800 Subject: ASoC: rt5645: Modify the headphone depop and calibration function to prevent the pop sound in the booting time Remove the original calibration function and modify the depop and calibration function to prevent the pop sound in the booting time. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 2ee4278..ac2f42f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -254,6 +254,7 @@ struct rt5645_priv { int jack_type; bool en_button_func; + bool hp_on; }; static int rt5645_reset(struct snd_soc_codec *codec) @@ -1364,15 +1365,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) if (on) { if (hp_amp_power_count <= 0) { if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M2, 0x3100); snd_soc_write(codec, RT5645_CHARGE_PUMP, 0x0e06); - snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); + regmap_write(rt5645->regmap, RT5645_PR_BASE + + RT5645_HP_DCC_INT1, 0x9f01); + msleep(20); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_CO_MASK, RT5645_HP_CO_EN); regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400); snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); + mdelay(5); + rt5645->hp_on = true; } else { /* depop parameters */ snd_soc_update_bits(codec, RT5645_DEPOP_M2, @@ -1586,6 +1595,27 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5650_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (rt5645->hp_on) { + msleep(100); + rt5645->hp_on = false; + } + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER, RT5645_PWR_LDO2_BIT, 0, NULL, 0), @@ -1870,6 +1900,7 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PDM1R"), SND_SOC_DAPM_OUTPUT("SPOL"), SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event), }; static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = { @@ -2721,77 +2752,6 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int rt5650_calibration(struct rt5645_priv *rt5645) -{ - int val, i; - int ret = -1; - - regcache_cache_bypass(rt5645->regmap, true); - regmap_write(rt5645->regmap, RT5645_RESET, 0); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800); - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC, - 0x3600); - regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000); - regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008); - /* headset type */ - regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061); - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012); - regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002); - regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020); - regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827); - msleep(400); - /* Inline command */ - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); - /* Calbration */ - regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); - regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04); - regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100); - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); - regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d); - /* Power on and Calbration */ - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1, - 0x9f01); - msleep(200); - for (i = 0; i < 5; i++) { - regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val); - if (val != 0 && val != 0x3f3f) { - ret = 0; - break; - } - msleep(50); - } - pr_debug("%s: PR-7A = 0x%x\n", __func__, val); - - /* mute */ - regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400); - regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737); - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, - 0xfc00); - regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006); - regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000); - msleep(350); - - regcache_cache_bypass(rt5645->regmap, false); - - return ret; -} - static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { @@ -3319,13 +3279,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, goto err_enable; } - if (rt5645->codec_type == CODEC_TYPE_RT5650) { - ret = rt5650_calibration(rt5645); - - if (ret < 0) - pr_err("calibration failed!\n"); - } - regmap_write(rt5645->regmap, RT5645_RESET, 0); ret = regmap_register_patch(rt5645->regmap, init_list, -- cgit v0.10.2 From 8db7f56ddf2c4571e33756b70a1a8f492c050449 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:57 +0800 Subject: ASoC: rt5645: Modify the jack detection function to prevent the pop sound while the jack plug in The patch corrects the sequence of the jack detection. It will prevent the pop sound while the jack plug in. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index ac2f42f..bcb44de 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2805,14 +2805,15 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, 0x1000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, + 0x0004); msleep(100); regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, 0x0000); - msleep(450); + msleep(600); regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); val &= 0x7; dev_dbg(codec->dev, "val = %d\n", val); @@ -2828,9 +2829,17 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) rt5645->jack_type = SND_JACK_HEADPHONE; } + snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001); } else { /* jack out */ rt5645->jack_type = 0; + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, + 0x1000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, + 0x0000); + if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); -- cgit v0.10.2 From 4aed4c9efb30253483869c58236ab00bdfa45630 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:58 +0800 Subject: ASoC: rt5645: Remove the incorrect setting of the JD mode The patch removes the incorrect setting of the JD mode. It will cause pop sound in the booting time. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index bcb44de..d9f3442 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3373,8 +3373,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, RT5645_IRQ_CLK_GATE_CTRL, RT5645_IRQ_CLK_GATE_CTRL); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, - RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, -- cgit v0.10.2 From b1d42598cb654ce63b55ccf27da09dcd914781f3 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:59 +0800 Subject: ASoC: rt5645: Add the register RT5645_CHARGE_PUMP to readable check function Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d9f3442..0a4cb6b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -394,6 +394,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_DEPOP_M1: case RT5645_DEPOP_M2: case RT5645_DEPOP_M3: + case RT5645_CHARGE_PUMP: case RT5645_MICBIAS: case RT5645_A_JD_CTRL1: case RT5645_VAD_CTRL4: -- cgit v0.10.2 From c1713485f9fc06e1f4de9800b43f6486f2527379 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 25 Aug 2015 16:03:48 +0800 Subject: ASoC: rt5645: Add struct dmi_system_id "Google Celes" for chrome platform Signed-off-by: Oder Chiou Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e..610eacd 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3229,6 +3229,13 @@ static struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), }, }, + { + .ident = "Google Celes", + .callback = strago_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), + }, + }, { } }; -- cgit v0.10.2 From 0e7659712836ca59b4735bc5cc94de38698a5e01 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 25 Aug 2015 12:43:48 +0100 Subject: ASoC: arizona: Poll for FLL clock OK rather than use interrupts The extcon driver takes the DAPM mutex from within the interrupt thread in several places, which makes it possible to get into a situation where the interrupt thread is blocked waiting on the DAPM mutex whilst a DAPM sequence is running which is attempting to configure the FLL. In this case the FLL completion can't be completed as as the IRQ handler is ONE_SHOT, which cause the FLL lock to use the full time out (250mS) and report that the process timed out. It is not really practical to make the extcon driver not take the DAPM mutex from within the interrupt thread, at least not without extensive modification. So this patch fixes the issue by switching the wait for the FLL lock to polling. A few fast polls are done first as the FLL should lock quickly for a good quality reference clock, (indeed it hits on the first poll on my system) and it will poll every 20mS after that until it times out. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 4e5d0a9..4180827 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1756,17 +1756,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id) } EXPORT_SYMBOL_GPL(arizona_init_dai); -static irqreturn_t arizona_fll_clock_ok(int irq, void *data) -{ - struct arizona_fll *fll = data; - - arizona_fll_dbg(fll, "clock OK\n"); - - complete(&fll->ok); - - return IRQ_HANDLED; -} - static struct { unsigned int min; unsigned int max; @@ -2048,10 +2037,11 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll) static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - unsigned long time_left; bool use_sync = false; int already_enabled = arizona_is_enabled_fll(fll); struct arizona_fll_cfg cfg; + int i; + unsigned int val; if (already_enabled < 0) return already_enabled; @@ -2110,9 +2100,6 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (!already_enabled) pm_runtime_get(arizona->dev); - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) @@ -2124,10 +2111,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - time_left = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (time_left == 0) + arizona_fll_dbg(fll, "Waiting for FLL lock...\n"); + val = 0; + for (i = 0; i < 15; i++) { + if (i < 5) + usleep_range(200, 400); + else + msleep(20); + + regmap_read(arizona->regmap, + ARIZONA_INTERRUPT_RAW_STATUS_5, + &val); + if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1))) + break; + } + if (i == 15) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + else + arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i); return 0; } @@ -2212,11 +2213,8 @@ EXPORT_SYMBOL_GPL(arizona_set_fll); int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll) { - int ret; unsigned int val; - init_completion(&fll->ok); - fll->id = id; fll->base = base; fll->arizona = arizona; @@ -2238,13 +2236,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), "FLL%d clock OK", id); - ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, - arizona_fll_clock_ok, fll); - if (ret != 0) { - dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n", - id, ret); - } - regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 43deb04..36867d0 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -242,7 +242,6 @@ struct arizona_fll { int id; unsigned int base; unsigned int vco_mult; - struct completion ok; unsigned int fout; int sync_src; -- cgit v0.10.2 From f8ce20005d1694584448cd544be5fb32416a277c Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 25 Aug 2015 15:52:42 +0800 Subject: ASoC: rockchip: fix a misjudgement by return Being careless, judge the return value of snd_soc_card_jack_new is opposite, so it should be fixed. Signed-off-by: Xing Zheng Reviewed-by: Dylan Reid Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 3c6bb1e..adfe98c 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -118,7 +118,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &headset_jack, NULL, 0); - if (!ret) { + if (ret) { dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); return ret; } -- cgit v0.10.2 From 0137d5ff8488f1d17a83508578976d3a67ba8e81 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 26 Aug 2015 19:44:10 +0800 Subject: ASoC: rockchip: fix platform_no_drv_owner.cocci warnings sound/soc/rockchip/rockchip_max98090.c:225: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 Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index acace20..562e7ea 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -222,7 +222,6 @@ static struct platform_driver snd_rk_mc_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_max98090_of_match, }, -- cgit v0.10.2 From 1c0beb27443c98257a5bced2978f2556f2ae1709 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 26 Aug 2015 19:48:13 +0800 Subject: ASoC: rockchip: fix platform_no_drv_owner.cocci warnings sound/soc/rockchip/rockchip_rt5645.c:214: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 Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index adfe98c..274b9b3 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -211,7 +211,6 @@ static struct platform_driver snd_rk_mc_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_rt5645_of_match, }, -- cgit v0.10.2 From 7d40acc38be55abb095f517e4e3a634818bc5253 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 26 Aug 2015 16:11:40 +0300 Subject: ASoC: omap-hdmi-audio: Set buffer bytes step constraint to 128 Set buffer bytes step constraint to 128. A matching constraint has already been set to period size. This helps PCM setup to tolerate ALSA clients that set the PCM hw params in unusual order. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index aeef25c..584b237 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -81,7 +81,15 @@ static int hdmi_dai_startup(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (ret < 0) { - dev_err(dai->dev, "could not apply constraint\n"); + dev_err(dai->dev, "Could not apply period constraint: %d\n", + ret); + return ret; + } + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); + if (ret < 0) { + dev_err(dai->dev, "Could not apply buffer constraint: %d\n", + ret); return ret; } -- cgit v0.10.2 From f57ddcdfa146636dbdcd6ac0a6d22c15d47b08c8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Aug 2015 23:32:14 +0800 Subject: ASoC: tegra: Use devm_ioremap_resource instead of open code Use devm_ioremap_resource() to simplify the code. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index f52600b..89add13 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -133,7 +133,7 @@ static const struct regmap_config tegra20_das_regmap_config = { static int tegra20_das_probe(struct platform_device *pdev) { - struct resource *res, *region; + struct resource *res; void __iomem *regs; int ret = 0; @@ -149,24 +149,9 @@ static int tegra20_das_probe(struct platform_device *pdev) das->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err; - } - - region = devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name); - if (!region) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err; - } - - regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err; } diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 05f1c6e..14106fa 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -339,7 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = { static int tegra20_i2s_platform_probe(struct platform_device *pdev) { struct tegra20_i2s *i2s; - struct resource *mem, *memregion; + struct resource *mem; void __iomem *regs; int ret; @@ -362,24 +362,9 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err_clk_put; } diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 0809b1e..a0c3640 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -265,7 +265,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = { static int tegra20_spdif_platform_probe(struct platform_device *pdev) { struct tegra20_spdif *spdif; - struct resource *mem, *memregion, *dmareq; + struct resource *mem, *dmareq; void __iomem *regs; int ret; @@ -285,10 +285,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - return -ENODEV; - } + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) + return PTR_ERR(regs); dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { @@ -296,19 +295,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) return -ENODEV; } - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - return -EBUSY; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &tegra20_spdif_regmap_config); if (IS_ERR(spdif->regmap)) { diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 989b1e8..fef3b9a 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -521,7 +521,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) const struct tegra30_ahub_soc_data *soc_data; struct reset_control *rst; int i; - struct resource *res0, *res1, *region; + struct resource *res0, *res1; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -584,26 +584,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev) } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res0) { - dev_err(&pdev->dev, "No apbif memory resource\n"); - return -ENODEV; - } + regs_apbif = devm_ioremap_resource(&pdev->dev, res0); + if (IS_ERR(regs_apbif)) + return PTR_ERR(regs_apbif); - region = devm_request_mem_region(&pdev->dev, res0->start, - resource_size(res0), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "request region apbif failed\n"); - return -EBUSY; - } ahub->apbif_addr = res0->start; - regs_apbif = devm_ioremap(&pdev->dev, res0->start, - resource_size(res0)); - if (!regs_apbif) { - dev_err(&pdev->dev, "ioremap apbif failed\n"); - return -ENOMEM; - } - ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, &tegra30_ahub_apbif_regmap_config); if (IS_ERR(ahub->regmap_apbif)) { @@ -614,24 +600,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev) regcache_cache_only(ahub->regmap_apbif, true); res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res1) { - dev_err(&pdev->dev, "No ahub memory resource\n"); - return -ENODEV; - } - - region = devm_request_mem_region(&pdev->dev, res1->start, - resource_size(res1), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "request region ahub failed\n"); - return -EBUSY; - } - - regs_ahub = devm_ioremap(&pdev->dev, res1->start, - resource_size(res1)); - if (!regs_ahub) { - dev_err(&pdev->dev, "ioremap ahub failed\n"); - return -ENOMEM; - } + regs_ahub = devm_ioremap_resource(&pdev->dev, res1); + if (IS_ERR(regs_ahub)) + return PTR_ERR(regs_ahub); ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, &tegra30_ahub_ahub_regmap_config); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index fe36375..8e55583 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -379,7 +379,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) struct tegra30_i2s *i2s; const struct of_device_id *match; u32 cif_ids[2]; - struct resource *mem, *memregion; + struct resource *mem; void __iomem *regs; int ret; @@ -419,24 +419,9 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err_clk_put; } -- cgit v0.10.2 From 3b7ce99748f0d006f9d1aa85709872e7b46787f7 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Thu, 27 Aug 2015 11:35:20 +0200 Subject: ASoC: ics43432: Add codec driver for InvenSense ICS-43432 Add support for the InvenSense ICS-43432 I2S MEMS microphone. This is a non-software-configurable MEMS microphone with I2S output. Tested on a setup with a single ICS-43432 (the device itself supports stereo operation using a hardware pin controlling left vs. right channel output). Signed-off-by: Ricard Wanderlof Signed-off-by: Mark Brown diff --git a/Documentation/devicetree/bindings/sound/ics43432.txt b/Documentation/devicetree/bindings/sound/ics43432.txt new file mode 100644 index 0000000..b02e3a6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ics43432.txt @@ -0,0 +1,17 @@ +Invensense ICS-43432 MEMS microphone with I2S output. + +There are no software configuration options for this device, indeed, the only +host connection is the I2S interface. Apart from requirements on clock +frequency (460 kHz to 3.379 MHz according to the data sheet) there must be +64 clock cycles in each stereo output frame; 24 of the 32 available bits +contain audio data. A hardware pin determines if the device outputs data +on the left or right channel of the I2S frame. + +Required properties: + - compatible : Must be "invensense,ics43432" + +Example: + + ics43432: ics43432 { + compatible = "invensense,ics43432"; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757..80bf96d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor innolux Innolux Corporation intel Intel Corporation intercontrol Inter Control Group +invensense InvenSense Inc. isee ISEE 2007 S.L. isil Intersil karo Ka-Ro electronics GmbH diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..1bb6446 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ICS43432 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -446,6 +447,9 @@ config SND_SOC_ES8328_SPI tristate select SND_SOC_ES8328 +config SND_SOC_ICS43432 + tristate + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..5a19a67 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-ics43432-objs := ics43432.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -242,6 +243,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c new file mode 100644 index 0000000..4f202c1 --- /dev/null +++ b/sound/soc/codecs/ics43432.c @@ -0,0 +1,77 @@ +/* + * I2S MEMS microphone driver for InvenSense ICS-43432 + * + * - Non configurable. + * - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data + * + * Copyright (c) 2015 Axis Communications AB + * + * Licensed under GPL2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ICS43432_RATE_MIN 7190 /* Hz, from data sheet */ +#define ICS43432_RATE_MAX 52800 /* Hz, from data sheet */ + +#define ICS43432_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32) + +static struct snd_soc_dai_driver ics43432_dai = { + .name = "ics43432-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rate_min = ICS43432_RATE_MIN, + .rate_max = ICS43432_RATE_MAX, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = ICS43432_FORMATS, + }, +}; + +static struct snd_soc_codec_driver ics43432_codec_driver = { +}; + +static int ics43432_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &ics43432_codec_driver, + &ics43432_dai, 1); +} + +static int ics43432_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id ics43432_ids[] = { + { .compatible = "invensense,ics43432", }, + { } +}; +MODULE_DEVICE_TABLE(of, ics43432_dt_ids); +#endif + +static struct platform_driver ics43432_driver = { + .driver = { + .name = "ics43432", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ics43432_ids), + }, + .probe = ics43432_probe, + .remove = ics43432_remove, +}; + +module_platform_driver(ics43432_driver); + +MODULE_DESCRIPTION("ASoC ICS43432 driver"); +MODULE_AUTHOR("Ricard Wanderlof "); +MODULE_LICENSE("GPLv2"); -- cgit v0.10.2 From f2988afedf2c19880a3c65d79dfc7939e1b53d8a Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 27 Aug 2015 15:14:51 +0800 Subject: ASoC: rt5645: Prevent the pop sound of the headphone while rebooting or shutdowning Add i2c shutdown function to prevent the pop sound of the headphone while the system is rebooting or shutdowning. It de-initials the jack detection function, and it cannot be turned off in _BIAS_OFF. If we don't de-initial it, the pop sound will be heard in the situation of powering off. And replace the related register settings from magic number to meaningful defined name. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 0a4cb6b..db50b03 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2806,13 +2806,13 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_update_bits(rt5645->regmap, - RT5645_IN1_CTRL2, 0x1000, 0x1000); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, - 0x0004); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, + RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); msleep(100); - regmap_update_bits(rt5645->regmap, - RT5645_IN1_CTRL2, 0x1000, 0x0000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, 0); msleep(600); regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); @@ -2836,10 +2836,10 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } else { /* jack out */ rt5645->jack_type = 0; - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, - 0x1000); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, - 0x0000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, + RT5645_CBJ_BST1_EN, 0); if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); @@ -3449,6 +3449,18 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) return 0; } +static void rt5645_i2c_shutdown(struct i2c_client *i2c) +{ + struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); + + regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, + RT5645_RING2_SLEEVE_GND, RT5645_RING2_SLEEVE_GND); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, RT5645_CBJ_MN_JD, + RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, RT5645_CBJ_BST1_EN, + 0); +} + static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", @@ -3456,7 +3468,8 @@ static struct i2c_driver rt5645_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, .probe = rt5645_i2c_probe, - .remove = rt5645_i2c_remove, + .remove = rt5645_i2c_remove, + .shutdown = rt5645_i2c_shutdown, .id_table = rt5645_i2c_id, }; module_i2c_driver(rt5645_i2c_driver); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 199b22f..1987eb8 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2111,6 +2111,7 @@ enum { #define RT5645_JD_PSV_MODE (0x1 << 12) #define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) #define RT5645_MICINDET_MANU (0x1 << 7) +#define RT5645_RING2_SLEEVE_GND (0x1 << 5) /* Vendor ID (0xfd) */ #define RT5645_VER_C 0x2 -- cgit v0.10.2 From 054bc835d27b558393541c32a209c01d89cda75a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 27 Aug 2015 17:04:01 +0200 Subject: ASoC: bcm2835-i2s: Fix module autoload for OF platform drivers These platform drivers have a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Mark Brown diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 03fa1cb..8c435be 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -862,6 +862,8 @@ static const struct of_device_id bcm2835_i2s_of_match[] = { {}, }; +MODULE_DEVICE_TABLE(of, bcm2835_i2s_of_match); + static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, .driver = { -- cgit v0.10.2 From 11d932416ecada27ca7576dca7e74e23477df7ef Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 28 Aug 2015 10:04:03 +0800 Subject: ASoC: ics43432: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/ics43432.c:66: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: Ricard Wanderlof Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index 4f202c1..d217fed 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -63,7 +63,6 @@ MODULE_DEVICE_TABLE(of, ics43432_dt_ids); static struct platform_driver ics43432_driver = { .driver = { .name = "ics43432", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ics43432_ids), }, .probe = ics43432_probe, -- cgit v0.10.2 From 2f38bc8829b83aed3e2c5e6d43a430d39f1b0e1d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 11:23:05 +0800 Subject: ASoC: ics43432: Fix module license Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index d217fed..7c35c98 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -6,7 +6,7 @@ * * Copyright (c) 2015 Axis Communications AB * - * Licensed under GPL2. + * Licensed under GPL v2. */ #include @@ -73,4 +73,4 @@ module_platform_driver(ics43432_driver); MODULE_DESCRIPTION("ASoC ICS43432 driver"); MODULE_AUTHOR("Ricard Wanderlof "); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From b37bfdaac914f4886b8be803703b12177eb873f6 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Fri, 28 Aug 2015 12:11:48 +0200 Subject: ASoC: ics43432: Fix build errors Fix build errors Signed-off-by: Ricard Wanderlof Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index 7c35c98..dd850b9 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -57,7 +57,7 @@ static const struct of_device_id ics43432_ids[] = { { .compatible = "invensense,ics43432", }, { } }; -MODULE_DEVICE_TABLE(of, ics43432_dt_ids); +MODULE_DEVICE_TABLE(of, ics43432_ids); #endif static struct platform_driver ics43432_driver = { -- cgit v0.10.2 From 637ce53a1b1c489ff0e92aa00b8376464f697dc5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:48:35 +0800 Subject: ASoC: pxa-ssp: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index fbe2e93..3da485e 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -813,14 +813,8 @@ static const struct of_device_id pxa_ssp_of_ids[] = { static int asoc_ssp_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, - &pxa_ssp_dai, 1); -} - -static int asoc_ssp_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &pxa_ssp_component, + &pxa_ssp_dai, 1); } static struct platform_driver asoc_ssp_driver = { @@ -830,7 +824,6 @@ static struct platform_driver asoc_ssp_driver = { }, .probe = asoc_ssp_probe, - .remove = asoc_ssp_remove, }; module_platform_driver(asoc_ssp_driver); -- cgit v0.10.2 From 2cf32b7b338086e9b85bb9fdd8aa398e89d83e9e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:49:44 +0800 Subject: ASoC: pxa2xx-i2s: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index e68290c..6b4e400 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -367,19 +367,12 @@ static const struct snd_soc_component_driver pxa_i2s_component = { static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &pxa_i2s_component, - &pxa_i2s_dai, 1); -} - -static int pxa2xx_i2s_drv_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component, + &pxa_i2s_dai, 1); } static struct platform_driver pxa2xx_i2s_driver = { .probe = pxa2xx_i2s_drv_probe, - .remove = pxa2xx_i2s_drv_remove, .driver = { .name = "pxa2xx-i2s", -- cgit v0.10.2 From 92eca20bbeaa4ec1908bad8aeefcaa2d98e302ff Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:50:53 +0800 Subject: ASoC: sh: ssi: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index ab13146..89ed1b1 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -385,14 +385,9 @@ static const struct snd_soc_component_driver sh4_ssi_component = { static int sh4_soc_dai_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, - sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} - -static int sh4_soc_dai_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, + ARRAY_SIZE(sh4_ssi_dai)); } static struct platform_driver sh4_ssi_driver = { @@ -401,7 +396,6 @@ static struct platform_driver sh4_ssi_driver = { }, .probe = sh4_soc_dai_probe, - .remove = sh4_soc_dai_remove, }; module_platform_driver(sh4_ssi_driver); -- cgit v0.10.2 From 618718dc56a49321a12f231b34f6c43f44c3c374 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:53:31 +0800 Subject: ASoC: qcom: Constify asoc_qcom_lpass_cpu_dai_ops asoc_qcom_lpass_cpu_dai_ops is exported and used by multiple drivers, make it const to prevent modifying it at run time. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 23f3d59..97bc202 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -235,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, return ret; } -struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { .set_sysclk = lpass_cpu_daiops_set_sysclk, .startup = lpass_cpu_daiops_startup, .shutdown = lpass_cpu_daiops_shutdown, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index d6e86c1..0b63e2e 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -93,6 +93,6 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); -extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; #endif /* __LPASS_H__ */ -- cgit v0.10.2 From edd98a1a2d163cef6d91226bf42ca002ced6ff16 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:09:29 +0800 Subject: ASoC: au1x: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index dd94fea..5741c0a 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -344,14 +344,8 @@ static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, dmadata); - return snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); -} - -static int au1xpsc_pcm_drvremove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &au1xpsc_soc_platform); } static struct platform_driver au1xpsc_pcm_driver = { @@ -359,7 +353,6 @@ static struct platform_driver au1xpsc_pcm_driver = { .name = "au1xpsc-pcm", }, .probe = au1xpsc_pcm_drvprobe, - .remove = au1xpsc_pcm_drvremove, }; module_platform_driver(au1xpsc_pcm_driver); diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 24cc7f4..fcf5a9a 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -312,14 +312,8 @@ static int alchemy_pcm_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform); -} - -static int alchemy_pcm_drvremove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &alchemy_pcm_soc_platform); } static struct platform_driver alchemy_pcmdma_driver = { @@ -327,7 +321,6 @@ static struct platform_driver alchemy_pcmdma_driver = { .name = "alchemy-pcm-dma", }, .probe = alchemy_pcm_drvprobe, - .remove = alchemy_pcm_drvremove, }; module_platform_driver(alchemy_pcmdma_driver); -- cgit v0.10.2 From c4d2ab0d59f53a1534e6817b5dbd28719f667c39 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:11:13 +0800 Subject: ASoC: blackfin: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 238913e..02ad260 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -450,13 +450,8 @@ static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = { static int bf5xx_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform); -} - -static int bf5xx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &bf5xx_ac97_soc_platform); } static struct platform_driver bf5xx_pcm_driver = { @@ -465,7 +460,6 @@ static struct platform_driver bf5xx_pcm_driver = { }, .probe = bf5xx_soc_platform_probe, - .remove = bf5xx_soc_platform_remove, }; module_platform_driver(bf5xx_pcm_driver); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index d95477a..6cba211d 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -342,13 +342,8 @@ static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = { static int bfin_i2s_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform); -} - -static int bfin_i2s_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &bf5xx_i2s_soc_platform); } static struct platform_driver bfin_i2s_pcm_driver = { @@ -357,7 +352,6 @@ static struct platform_driver bfin_i2s_pcm_driver = { }, .probe = bfin_i2s_soc_platform_probe, - .remove = bfin_i2s_soc_platform_remove, }; module_platform_driver(bfin_i2s_pcm_driver); -- cgit v0.10.2 From d5f1117ff60d1e314b15e3a85b7705db3421d7d4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:12:17 +0800 Subject: ASoC: nuc900: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 5ae5ca1..e093261 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -308,13 +308,7 @@ static struct snd_soc_platform_driver nuc900_soc_platform = { static int nuc900_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform); -} - -static int nuc900_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform); } static struct platform_driver nuc900_pcm_driver = { @@ -323,7 +317,6 @@ static struct platform_driver nuc900_pcm_driver = { }, .probe = nuc900_soc_platform_probe, - .remove = nuc900_soc_platform_remove, }; module_platform_driver(nuc900_pcm_driver); -- cgit v0.10.2 From 637c4497bbf0c9a4e00d6be2731bd560bf609f6b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:13:46 +0800 Subject: ASoC: pxa: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 1eb45dc..51e790d 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -232,13 +232,7 @@ static int mmp_pcm_probe(struct platform_device *pdev) mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max = pdata->period_max_capture; } - return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); -} - -static int mmp_pcm_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); } static struct platform_driver mmp_pcm_driver = { @@ -247,7 +241,6 @@ static struct platform_driver mmp_pcm_driver = { }, .probe = mmp_pcm_probe, - .remove = mmp_pcm_remove, }; module_platform_driver(mmp_pcm_driver); diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index a51c9da..831ee37 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -124,13 +124,7 @@ static struct snd_soc_platform_driver pxa2xx_soc_platform = { static int pxa2xx_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform); -} - -static int pxa2xx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform); } #ifdef CONFIG_OF @@ -147,7 +141,6 @@ static struct platform_driver pxa_pcm_driver = { }, .probe = pxa2xx_soc_platform_probe, - .remove = pxa2xx_soc_platform_remove, }; module_platform_driver(pxa_pcm_driver); -- cgit v0.10.2 From 95e3c2305b79e9c0e5f2cb0090efca397249b51f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:14:50 +0800 Subject: ASoC: txx9: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 88eacfd..a8f705b 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -411,13 +411,8 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = { static int txx9aclc_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform); -} - -static int txx9aclc_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &txx9aclc_soc_platform); } static struct platform_driver txx9aclc_pcm_driver = { @@ -426,7 +421,6 @@ static struct platform_driver txx9aclc_pcm_driver = { }, .probe = txx9aclc_soc_platform_probe, - .remove = txx9aclc_soc_platform_remove, }; module_platform_driver(txx9aclc_pcm_driver); -- cgit v0.10.2 From 628536ea0627e71da654bd34b1942c85832dbdba Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 25 Aug 2015 01:14:48 -0600 Subject: ASoC: Clean up docbook warnings A number of functions and structures in the sound subsystem had incomplete and/or obsolete DocBook comments, leading to warnings when the docs were built. Correct those comments so that we can enjoy our audio in the absence of warning noise. Signed-off-by: Jonathan Corbet Signed-off-by: Mark Brown diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index 71f9246..e94a10b 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -108,7 +108,7 @@ ASoC Core API !Iinclude/sound/soc.h !Esound/soc/soc-core.c -!Esound/soc/soc-cache.c + !Esound/soc/soc-devres.c !Esound/soc/soc-io.c !Esound/soc/soc-pcm.c diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf..4537e81 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -619,6 +619,7 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, * @pin: name of the pin to update * @mask: bits to check for in reported jack status * @invert: if non-zero then pin is enabled when status is not reported + * @list: internal list entry */ struct snd_soc_jack_pin { struct list_head list; @@ -635,7 +636,7 @@ struct snd_soc_jack_pin { * @jack_type: type of jack that is expected for this voltage * @debounce_time: debounce_time for jack, codec driver should wait for this * duration before reading the adc for voltages - * @:list: list container + * @list: internal list entry */ struct snd_soc_jack_zone { unsigned int min_mv; @@ -651,12 +652,12 @@ struct snd_soc_jack_zone { * @gpio: legacy gpio number * @idx: gpio descriptor index within the function of the GPIO * consumer device - * @gpiod_dev GPIO consumer device + * @gpiod_dev: GPIO consumer device * @name: gpio name. Also as connection ID for the GPIO consumer * device function name lookup * @report: value to report when jack detected * @invert: report presence in low state - * @debouce_time: debouce time in ms + * @debounce_time: debounce time in ms * @wake: enable as wake source * @jack_status_check: callback function which overrides the detection * to provide more complex checks (eg, reading an @@ -672,11 +673,13 @@ struct snd_soc_jack_gpio { int debounce_time; bool wake; + /* private: */ struct snd_soc_jack *jack; struct delayed_work work; struct gpio_desc *desc; void *data; + /* public: */ int (*jack_status_check)(void *data); }; @@ -1319,7 +1322,7 @@ static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm( /** * snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level - * @dapm: The CODEC for which to initialize the DAPM bias level + * @codec: The CODEC for which to initialize the DAPM bias level * @level: The DAPM level to initialize to * * Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level(). diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 90d6335..3224251 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2798,6 +2798,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component); /** * snd_soc_unregister_component - Unregister a component from the ASoC core * + * @dev: The device to unregister */ void snd_soc_unregister_component(struct device *dev) { @@ -2877,7 +2878,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_platform); /** * snd_soc_register_platform - Register a platform with the ASoC core * - * @platform: platform to register + * @dev: The device for the platform + * @platform_drv: The driver for the platform */ int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv) @@ -2938,7 +2940,7 @@ EXPORT_SYMBOL_GPL(snd_soc_lookup_platform); /** * snd_soc_unregister_platform - Unregister a platform from the ASoC core * - * @platform: platform to unregister + * @dev: platform to unregister */ void snd_soc_unregister_platform(struct device *dev) { @@ -3029,7 +3031,10 @@ static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm, /** * snd_soc_register_codec - Register a codec with the ASoC core * - * @codec: codec to register + * @dev: The parent device for this codec + * @codec_drv: Codec driver + * @dai_drv: The associated DAI driver + * @num_dai: Number of DAIs */ int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, @@ -3128,7 +3133,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec); /** * snd_soc_unregister_codec - Unregister a codec from the ASoC core * - * @codec: codec to unregister + * @dev: codec to unregister */ void snd_soc_unregister_codec(struct device *dev) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c9..c4e3720 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2911,7 +2911,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); /** * snd_soc_dapm_new_widgets - add new dapm widgets - * @dapm: DAPM context + * @card: card to be checked for new dapm widgets * * Checks the codec for any new dapm widgets and creates them if found. * -- cgit v0.10.2 From 2c3f4b97eea5ce405baf2591715445da6ed05851 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 08:08:15 +0800 Subject: ASoC: spear_pcm: Use devm_snd_dmaengine_pcm_register to fix resource leak All the callers assume devm_spear_pcm_platform_register is a devm_ API, so use devm_snd_dmaengine_pcm_register in devm_spear_pcm_platform_register. Fixes: e1771bcf99b0 ("ASoC: SPEAr: remove custom DMA alloc compat function") Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index a7dc3c5..e8476da 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -44,7 +44,7 @@ int devm_spear_pcm_platform_register(struct device *dev, *config = spear_dmaengine_pcm_config; config->compat_filter_fn = filter; - return snd_dmaengine_pcm_register(dev, config, + return devm_snd_dmaengine_pcm_register(dev, config, SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_COMPAT); } -- cgit v0.10.2 From e8de871e19668257972b167aabd56bb5faae784c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 11:07:33 +0800 Subject: ASoC: sh: dma-sh7760: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Acked-by: Manuel Lauss Signed-off-by: Mark Brown diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index fd11404..8fad444 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -327,13 +327,7 @@ static struct snd_soc_platform_driver sh7760_soc_platform = { static int sh7760_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); -} - -static int sh7760_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); } static struct platform_driver sh7760_pcm_driver = { @@ -342,7 +336,6 @@ static struct platform_driver sh7760_pcm_driver = { }, .probe = sh7760_soc_platform_probe, - .remove = sh7760_soc_platform_remove, }; module_platform_driver(sh7760_pcm_driver); -- cgit v0.10.2 From fd63542fc5492b86158dbd53ce5de764f171b1b6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 11:09:49 +0800 Subject: ASoC: au1x: psc-i2s: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Manuel Lauss Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index e742ef6..38e853a 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -305,19 +305,9 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) return -ENOMEM; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -ENODEV; - - ret = -EBUSY; - if (!devm_request_mem_region(&pdev->dev, iores->start, - resource_size(iores), - pdev->name)) - return -EBUSY; - - wd->mmio = devm_ioremap(&pdev->dev, iores->start, - resource_size(iores)); - if (!wd->mmio) - return -EBUSY; + wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(wd->mmio)) + return PTR_ERR(wd->mmio); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmares) -- cgit v0.10.2 From e12909107c30efccf570ac67802df5d2eec4cabd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Aug 2015 23:06:32 +0800 Subject: ASoC: sti_uniperif: Ensure component is unregistered when unload module Use devm_snd_soc_register_component to ensure component is unregistered when unload the module. Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index dffabf3..39bcefe 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -224,9 +224,9 @@ static int sti_uniperiph_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); - ret = snd_soc_register_component(&pdev->dev, - &sti_uniperiph_dai_component, - priv->dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &sti_uniperiph_dai_component, + priv->dai, 1); if (ret < 0) return ret; -- cgit v0.10.2 From 534dcd7ea60cebc41816eff0c290700acb2cc43e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Aug 2015 23:09:30 +0800 Subject: ASoC: zx296702-i2s: Fix resource leak when unload module Use devm_* API to fix leaks in current code. 1. Use devm_kzalloc to fix memory leak for zx_i2s when unload the module. 2. Use devm_snd_soc_register_component to ensure component is unregistered when unload the module. Signed-off-by: Axel Lin Reviewed-by: Jun Nie Signed-off-by: Mark Brown diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c index 98d96e1..f4b681d 100644 --- a/sound/soc/zte/zx296702-i2s.c +++ b/sound/soc/zte/zx296702-i2s.c @@ -380,7 +380,7 @@ static int zx_i2s_probe(struct platform_device *pdev) struct zx_i2s_info *zx_i2s; int ret; - zx_i2s = kzalloc(sizeof(*zx_i2s), GFP_KERNEL); + zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL); if (!zx_i2s) return -ENOMEM; @@ -401,8 +401,8 @@ static int zx_i2s_probe(struct platform_device *pdev) writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); platform_set_drvdata(pdev, zx_i2s); - ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component, - &zx_i2s_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component, + &zx_i2s_dai, 1); if (ret) { dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); return ret; -- cgit v0.10.2