From 6ca22700eb45397c16fd4c962333963b2d6b0923 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 18 Sep 2015 13:41:21 +0800 Subject: ARM: OMAP2+: PM: Denote the cpuidle tracepoints as _rcuidle() The cpuidle tracepoints are called within a rcu_idle_exit() section, and must be denoted with the _rcuidle() version of the tracepoint. Signed-off-by: Jisheng Zhang Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 87b98bf9..2dbd378 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -301,11 +301,11 @@ static void omap3_pm_idle(void) if (omap_irq_pending()) return; - trace_cpu_idle(1, smp_processor_id()); + trace_cpu_idle_rcuidle(1, smp_processor_id()); omap_sram_idle(); - trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); + trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); } #ifdef CONFIG_SUSPEND -- cgit v0.10.2 From 7ef71b70e18a82bb363905f72672317d0e1e8810 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Sep 2015 08:51:42 +0800 Subject: bus: omap-ocp2scp: Fix module alias Remove extra space between platform prefix and driver name in MODULE_ALIAS. Signed-off-by: Axel Lin Signed-off-by: Tony Lindgren diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index 9f18569..bf500e0 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -117,7 +117,7 @@ static struct platform_driver omap_ocp2scp_driver = { module_platform_driver(omap_ocp2scp_driver); -MODULE_ALIAS("platform: omap-ocp2scp"); +MODULE_ALIAS("platform:omap-ocp2scp"); MODULE_AUTHOR("Texas Instruments Inc."); MODULE_DESCRIPTION("OMAP OCP2SCP driver"); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 3cc7780b6fc04318ab08d84f739503989200cf55 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 19 Oct 2015 17:42:23 -0700 Subject: ASoC: fsl_sai: fix Rx synchrounous mode When using the Rx clock for both, transmitter and receiver, the transmitter needs to be set to synchronous with receiver. This reverts 855675f6e6a6 ("ASoC: fsl_sai: Set SYNC bit of TCR2 to Asynchronous Mode"), which, judiging from the commit log, seems to mixed up between the two synchronous modes: The boolean sai->synchronous[TX] is indicating wheather the SAI should work in Rx synchronous mode (sync Tx with Rx), hence if the value is true, the SYNC field of TCR2 needs to be set to 0x1 ("Synchronous with receiver"). Signed-off-by: Stefan Agner Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a18fd92..1f0e552 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -454,7 +454,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); -- cgit v0.10.2 From 341604ad839d10314af51669fd454dc0aa2ef288 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 3 Nov 2015 14:24:12 +0000 Subject: ASoC: arizona: fix range of OPCLK_REF The code was able to generate illegal OPCLK_REF values because the reference frequency tables listed all values of SYSCLK instead of valid values for OPCLK_REF clock. The maximum OPCLK_REF clock is 49.152MHz or 45.1584MHz. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 8a2221a..5867895 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -979,24 +979,18 @@ void arizona_init_dvfs(struct arizona_priv *priv) } EXPORT_SYMBOL_GPL(arizona_init_dvfs); -static unsigned int arizona_sysclk_48k_rates[] = { +static unsigned int arizona_opclk_ref_48k_rates[] = { 6144000, 12288000, 24576000, 49152000, - 73728000, - 98304000, - 147456000, }; -static unsigned int arizona_sysclk_44k1_rates[] = { +static unsigned int arizona_opclk_ref_44k1_rates[] = { 5644800, 11289600, 22579200, 45158400, - 67737600, - 90316800, - 135475200, }; static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, @@ -1021,11 +1015,11 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, } if (refclk % 8000) - rates = arizona_sysclk_44k1_rates; + rates = arizona_opclk_ref_44k1_rates; else - rates = arizona_sysclk_48k_rates; + rates = arizona_opclk_ref_48k_rates; - for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) && + for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) && rates[ref] <= refclk; ref++) { div = 1; while (rates[ref] / div >= freq && div < 32) { -- cgit v0.10.2 From 41a59cae585678136c28cdcbba9cb2faf27685f5 Mon Sep 17 00:00:00 2001 From: JongHo Kim Date: Tue, 3 Nov 2015 11:06:32 +0900 Subject: ASoC: wm8960: Fix the Input PGA Mute switch Change the xinvert value from 0 to 1 on the "Capture Switch" control WM8960 datasheet is shown as follows: Bit 7 at 00h and 01h register address 1 : Enable Mute, 0 : Disable Mute Signed-off-by: JongHo Kim Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index e3b7d0c..bbe2427 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -223,7 +223,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, 6, 1, 0), SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, - 7, 1, 0), + 7, 1, 1), SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume", WM8960_INBMIX1, 4, 7, 0, boost_tlv), -- cgit v0.10.2 From 7099ee85e6af56828c46255f43adb15ed47e67df Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 5 Nov 2015 19:55:51 +0800 Subject: ASoC: rt5645: Power up the RC clock to make sure the speaker volume adjust properly 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 2813237..672fafd 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -245,7 +245,7 @@ struct rt5645_priv { 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 delayed_work jack_detect_work, rcclock_work; struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)]; struct rt5645_eq_param_s *eq_param; @@ -565,12 +565,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol, .put = rt5645_hweq_put \ } +static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); + int ret; + + cancel_delayed_work_sync(&rt5645->rcclock_work); + + regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, + RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU); + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work, + msecs_to_jiffies(200)); + + return ret; +} + static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* Speaker Output Volume */ SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1), - SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL, - RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv), + SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT5645_SPK_VOL, + RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, snd_soc_get_volsw, + rt5645_spk_put_volsw, out_vol_tlv), /* ClassD modulator Speaker Gain Ratio */ SOC_SINGLE_TLV("Speaker ClassD Playback Volume", RT5645_SPO_CLSD_RATIO, @@ -3122,6 +3143,15 @@ static void rt5645_jack_detect_work(struct work_struct *work) SND_JACK_BTN_2 | SND_JACK_BTN_3); } +static void rt5645_rcclock_work(struct work_struct *work) +{ + struct rt5645_priv *rt5645 = + container_of(work, struct rt5645_priv, rcclock_work.work); + + regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, + RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PD); +} + static irqreturn_t rt5645_irq(int irq, void *data) { struct rt5645_priv *rt5645 = data; @@ -3587,6 +3617,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); + INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); if (rt5645->i2c->irq) { ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, @@ -3621,6 +3652,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) free_irq(i2c->irq, rt5645); cancel_delayed_work_sync(&rt5645->jack_detect_work); + cancel_delayed_work_sync(&rt5645->rcclock_work); snd_soc_unregister_codec(&i2c->dev); regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); -- cgit v0.10.2 From 474d147ad1ecc98e50a65c9f350fadfcc37a8bb4 Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Tue, 27 Oct 2015 21:00:45 +0000 Subject: ASoC: sun4i-codec: use consistent names for PA controls The power amplifier for the headphone output is called "the PA" and "the headphone amplifier" in Allwinner's documentation for the A10 and A20. sun4i-codec calls it "PA" in some places and "Pre-Amplifier" (which isn't really accurate) in others, leading to user-visible controls with different names referring to the same device. When this driver implements audio input, it'll also need to expose controls for the line and mic input preamps, so just referring to "the Pre-Amplifier" will be ambiguous. Change it to use "Power Amplifier" consistently for the power amplifier's controls. Signed-off-by: Adam Sampson Acked-by: Maxime Ripard Signed-off-by: Mark Brown diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index bcbf4da..1bb896d 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -2,6 +2,7 @@ * Copyright 2014 Emilio López * Copyright 2014 Jon Smirl * Copyright 2015 Maxime Ripard + * Copyright 2015 Adam Sampson * * Based on the Allwinner SDK driver, released under the GPL. * @@ -404,7 +405,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); static const struct snd_kcontrol_new sun4i_codec_widgets[] = { - SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL, + SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), }; @@ -452,12 +453,12 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0), - /* Pre-Amplifier */ - SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, + /* Power Amplifier */ + SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL, SUN4I_CODEC_ADC_ACTL_PA_EN, 0, sun4i_codec_pa_mixer_controls, ARRAY_SIZE(sun4i_codec_pa_mixer_controls)), - SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), SND_SOC_DAPM_OUTPUT("HP Right"), @@ -480,16 +481,16 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left DAC Playback Switch", "Left DAC" }, - /* Pre-Amplifier Mixer Routes */ - { "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" }, - { "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" }, - { "Pre-Amplifier", "DAC Playback Switch", "Left DAC" }, - { "Pre-Amplifier", "DAC Playback Switch", "Right DAC" }, + /* Power Amplifier Routes */ + { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, + { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" }, + { "Power Amplifier", "DAC Playback Switch", "Left DAC" }, + { "Power Amplifier", "DAC Playback Switch", "Right DAC" }, - /* PA -> HP path */ - { "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" }, - { "HP Right", NULL, "Pre-Amplifier Mute" }, - { "HP Left", NULL, "Pre-Amplifier Mute" }, + /* Headphone Output Routes */ + { "Power Amplifier Mute", "Switch", "Power Amplifier" }, + { "HP Right", NULL, "Power Amplifier Mute" }, + { "HP Left", NULL, "Power Amplifier Mute" }, }; static struct snd_soc_codec_driver sun4i_codec_codec = { -- cgit v0.10.2 From 021c5d9469960b8c68aa1d1825f7bfd8d61e157d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 5 Nov 2015 23:53:03 +0000 Subject: ASoC: rsnd: fixup SCU_SYS_INT_EN1 address cfcefe0126 ("ASoC: rsnd: add recovery support for under/over flow error on SRC") added SCU_SYS_INT_EN1 address, but it should be 0x1d4, not 0x1c4. This patch fixup it. Fixes: cfcefe0126 ("ASoC: rsnd: add recovery support for under/over flow error on SRC") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index f04d17b..916b38d 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -231,7 +231,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc), RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0), - RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4), + RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4), RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), -- cgit v0.10.2 From 2c5816b4beccc8ba709144539f6fdd764f8fa49c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 10 Nov 2015 10:32:36 +0100 Subject: cuse: fix memory leak The problem is that fuse_dev_alloc() acquires an extra reference to cc.fc, and the original ref count is never dropped. Reported-by: Colin Ian King Signed-off-by: Miklos Szeredi Fixes: cc080e9e9be1 ("fuse: introduce per-instance fuse_dev structure") Cc: # v4.2+ diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index eae2c11..8e3ee19 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -549,6 +549,8 @@ static int cuse_channel_release(struct inode *inode, struct file *file) unregister_chrdev_region(cc->cdev->dev, 1); cdev_del(cc->cdev); } + /* Base reference is now owned by "fud" */ + fuse_conn_put(&cc->fc); rc = fuse_dev_release(inode, file); /* puts the base reference */ -- cgit v0.10.2 From 3ca8138f014a913f98e6ef40e939868e1e9ea876 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Mon, 12 Oct 2015 16:33:44 +0300 Subject: fuse: break infinite loop in fuse_fill_write_pages() I got a report about unkillable task eating CPU. Further investigation shows, that the problem is in the fuse_fill_write_pages() function. If iov's first segment has zero length, we get an infinite loop, because we never reach iov_iter_advance() call. Fix this by calling iov_iter_advance() before repeating an attempt to copy data from userspace. A similar problem is described in 124d3b7041f ("fix writev regression: pan hanging unkillable and un-straceable"). If zero-length segmend is followed by segment with invalid address, iov_iter_fault_in_readable() checks only first segment (zero-length), iov_iter_copy_from_user_atomic() skips it, fails at second and returns zero -> goto again without skipping zero-length segment. Patch calls iov_iter_advance() before goto again: we'll skip zero-length segment at second iteraction and iov_iter_fault_in_readable() will detect invalid address. Special thanks to Konstantin Khlebnikov, who helped a lot with the commit description. Cc: Andrew Morton Cc: Maxim Patlasov Cc: Konstantin Khlebnikov Signed-off-by: Roman Gushchin Signed-off-by: Miklos Szeredi Fixes: ea9b9907b82a ("fuse: implement perform_write") Cc: diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f523f2f..195476a 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1049,6 +1049,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes); flush_dcache_page(page); + iov_iter_advance(ii, tmp); if (!tmp) { unlock_page(page); page_cache_release(page); @@ -1061,7 +1062,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, req->page_descs[req->num_pages].length = tmp; req->num_pages++; - iov_iter_advance(ii, tmp); count += tmp; pos += tmp; offset += tmp; -- cgit v0.10.2 From f680f70adbeab28b35f849016b964dd645db6237 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 3 Nov 2015 11:51:33 +0530 Subject: ath10k: fix invalid NSS for 4x4 devices The number of spatial streams that are derived from chain mask for 4x4 devices is using wrong bitmask and conditional check. This is affecting downlink throughput for QCA99x0 devices. Earlier cfg_tx_chainmask is not filled by default until user configured it and so get_nss_from_chainmask never be called. This issue is exposed by recent commit 166de3f1895d ("ath10k: remove supported chain mask"). By default maximum supported chain mask is filled in cfg_tx_chainmask. Cc: stable@vger.kernel.org Fixes: 5572a95b4b ("ath10k: apply chainmask settings to vdev on creation") Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a7411fe..95a55405 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4225,7 +4225,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) static u32 get_nss_from_chainmask(u16 chain_mask) { - if ((chain_mask & 0x15) == 0x15) + if ((chain_mask & 0xf) == 0xf) return 4; else if ((chain_mask & 0x7) == 0x7) return 3; -- cgit v0.10.2 From 88c9321d1ddb9c9539f1ef5da86a35604eb153d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 10 Nov 2015 13:03:04 +0100 Subject: spi: Add missing kerneldoc description for parameter Commit ca5d24854210 ("spi: Add THIS_MODULE to spi_driver in SPI core") adds the new __spi_register_driver() function, but keeps the kerneldoc for the spi_register_driver() function in place and forgets to add the description for the new owner parameter. Signed-off-by: Thierry Reding Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e2415be..20ef469 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -376,6 +376,7 @@ static void spi_drv_shutdown(struct device *dev) /** * __spi_register_driver - register a SPI driver + * @owner: owner module of the driver to register * @sdrv: the driver to register * Context: can sleep * -- cgit v0.10.2 From 1bdd593247ee5a74eb58828a4cf18bdc8a5f1baa Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Mon, 9 Nov 2015 12:19:19 -0600 Subject: ASoC: davinci-mcasp: Fix TDM slot rx/tx mask associations Fixes the associations between the tx_mask and rx_mask and the associated playback / capture streams during setting of the TDM slot. With this patch in place it is now possible for example to only populate tx_mask (leaving rx_mask as 0) for output-only codecs to control the TDM slot(s) the McASP serial port uses for transmit. Before that, this scenario would incorrectly rely on the rx_mask for this. Signed-off-by: Andreas Dannenberg Reviewed-by: Jyri Sarha Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4495a40..caa0beb 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -681,8 +681,8 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, } mcasp->tdm_slots = slots; - mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask; - mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask; + mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; mcasp->slot_width = slot_width; return davinci_mcasp_set_ch_constraints(mcasp); -- cgit v0.10.2 From fd589a1be20fdd76ef97700dd0185e7a060546dc Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 10 Nov 2015 18:12:42 +0200 Subject: ASoC: dapm: Reset dapm wcache after freeing damp widgets If there is anything in damp->path_source_cache or damp->path_sink_cache, it can not be valid after the widgets have been freed. Without this patch a repeated remove and load of a machine driver may cause NULL pointer reference in dapm_wcache_lookup() when a freed widget, not belonging to any list, is haunting in the wcache. Signed-off-by: Jyri Sarha Reported-by: Felipe Balbi Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7855cfe..95a937e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -398,6 +398,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, 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); +void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm); /* 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 016eba1..7d00942 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2293,6 +2293,12 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w); } +void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm) +{ + dapm->path_sink_cache.widget = NULL; + dapm->path_source_cache.widget = NULL; +} + /* free all dapm widgets and resources */ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) { @@ -2303,6 +2309,7 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) continue; snd_soc_dapm_free_widget(w); } + snd_soc_dapm_reset_cache(dapm); } static struct snd_soc_dapm_widget *dapm_find_widget( diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8d7ec80..cce63fe 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1805,6 +1805,7 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, snd_soc_tplg_widget_remove(w); snd_soc_dapm_free_widget(w); } + snd_soc_dapm_reset_cache(dapm); } EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all); -- cgit v0.10.2 From 2f64b6ed44c26eeb3d1bf5428936629cf552eda7 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 10 Nov 2015 14:40:55 +0800 Subject: ASoC: rl6231: avoid using divisible by 3 for DMIC clk Few codecs will meet no DMIC clock output issue when select a divided number which is divisible by 3. To prevent this issue, the patch ignore the numbers when calculating the DMIC clock divider. 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 aca479f..18b4292 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -80,6 +80,8 @@ int rl6231_calc_dmic_clk(int rate) } for (i = 0; i < ARRAY_SIZE(div); i++) { + if ((div[i] % 3) == 0) + continue; /* find divider that gives DMIC frequency below 3MHz */ if (3000000 * div[i] >= rate) return i; -- cgit v0.10.2 From c22d7666c5c4473cfffe8c40fcf86bd6e16317df Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 9 Nov 2015 18:01:04 +0800 Subject: ASoC: rt5677: Avoid the pop sound that comes from the filter power The patch changes the type of DACs mixer to AUTODISABLE and add the delay time after power up to avoid the pop sound that comes from the filter power. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index b4cd7e3..69d987a 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1386,90 +1386,90 @@ static const struct snd_kcontrol_new rt5677_dac_r_mix[] = { }; static const struct snd_kcontrol_new rt5677_sto1_dac_l_mix[] = { - SOC_DAPM_SINGLE("ST L Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_STO1_DAC_MIXER, RT5677_M_ST_DAC1_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC1_L_STO_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC2_L_STO_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC1_R_STO_L_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_sto1_dac_r_mix[] = { - SOC_DAPM_SINGLE("ST R Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_STO1_DAC_MIXER, RT5677_M_ST_DAC1_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC1_R_STO_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC2_R_STO_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER, RT5677_M_DAC1_L_STO_R_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_mono_dac_l_mix[] = { - SOC_DAPM_SINGLE("ST L Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_MONO_DAC_MIXER, RT5677_M_ST_DAC2_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC1_L_MONO_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC2_L_MONO_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC2_R_MONO_L_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_mono_dac_r_mix[] = { - SOC_DAPM_SINGLE("ST R Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_MONO_DAC_MIXER, RT5677_M_ST_DAC2_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC1_R_MONO_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC2_R_MONO_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER, RT5677_M_DAC2_L_MONO_R_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_dd1_l_mix[] = { - SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER, RT5677_M_STO_L_DD1_L_SFT, 1, 1), - SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER, RT5677_M_MONO_L_DD1_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER, RT5677_M_DAC3_L_DD1_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER, RT5677_M_DAC3_R_DD1_L_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_dd1_r_mix[] = { - SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER, RT5677_M_STO_R_DD1_R_SFT, 1, 1), - SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER, RT5677_M_MONO_R_DD1_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER, RT5677_M_DAC3_R_DD1_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER, RT5677_M_DAC3_L_DD1_R_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_dd2_l_mix[] = { - SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER, RT5677_M_STO_L_DD2_L_SFT, 1, 1), - SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER, RT5677_M_MONO_L_DD2_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER, RT5677_M_DAC4_L_DD2_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER, RT5677_M_DAC4_R_DD2_L_SFT, 1, 1), }; static const struct snd_kcontrol_new rt5677_dd2_r_mix[] = { - SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER, RT5677_M_STO_R_DD2_R_SFT, 1, 1), - SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER, RT5677_M_MONO_R_DD2_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER, RT5677_M_DAC4_R_DD2_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER, + SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER, RT5677_M_DAC4_L_DD2_R_SFT, 1, 1), }; @@ -2596,6 +2596,21 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5677_filter_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(50); + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, 0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU | @@ -3072,19 +3087,26 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { /* DAC Mixer */ SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0), + RT5677_PWR_DAC_S1F_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M2F_L_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M2F_R_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M3F_L_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M3F_R_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M4F_L_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2, - RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0), + RT5677_PWR_DAC_M4F_R_BIT, 0, rt5677_filter_power_event, + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)), -- cgit v0.10.2 From 7115cb913d9e2d68583cf76578b32568bc8ea83f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 07:39:17 +0000 Subject: ASoC: rsnd: make sure SRC In Rate feature enablement SRC In Rate convert feature cannot be used if data path is using DVC. This patch judges it, and not allowed to use it in such case. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 261b502..68b439e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -923,6 +923,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, struct snd_soc_pcm_runtime *rtd) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_src *src = rsnd_mod_to_src(mod); int ret; @@ -937,6 +938,12 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, return 0; /* + * SRC In doesn't work if DVC was enabled + */ + if (dvc && !rsnd_io_is_play(io)) + return 0; + + /* * enable sync convert */ ret = rsnd_kctrl_new_s(mod, io, rtd, -- cgit v0.10.2 From 7883746bc663150e8acd7a57397fc889698b0b33 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 11 Nov 2015 21:47:12 +0200 Subject: Bluetooth: Fix l2cap_chan leak in SMP The L2CAP core expects channel implementations to manage the reference returned by the new_connection callback. With sockets this is already handled with each channel being tied to the corresponding socket. With SMP however there's no context to tie the pointer to in the smp_new_conn_cb function. The function can also not just drop the reference since it's the only one at that point. For fixed channels (like SMP) the code path inside the L2CAP core from new_connection() to ready() is short and straight-forwards. The crucial difference is that in ready() the implementation has access to the l2cap_conn that SMP needs associate its l2cap_chan. Instead of taking a new reference in smp_ready_cb() we can simply assume to already own the reference created in smp_new_conn_cb(), i.e. there is no need to call l2cap_chan_hold(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.19+ diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c913538..ffed8a1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3027,8 +3027,13 @@ static void smp_ready_cb(struct l2cap_chan *chan) BT_DBG("chan %p", chan); + /* No need to call l2cap_chan_hold() here since we already own + * the reference taken in smp_new_conn_cb(). This is just the + * first time that we tie it to a specific pointer. The code in + * l2cap_core.c ensures that there's no risk this function wont + * get called if smp_new_conn_cb was previously called. + */ conn->smp = chan; - l2cap_chan_hold(chan); if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) bredr_pairing(chan); -- cgit v0.10.2 From bf05c2c2c5586242509660d146a5bb5f73dd06c5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Nov 2015 09:32:57 +0200 Subject: ARM: dts: dra7: Fix McASP3 node regarding to clocks McASP node needs to list all mandatory clocks: gfclk and ahclkx Signed-off-by: Peter Ujfalusi Tested-by: Felipe Balbi Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index bc672fb..fe99231 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1459,8 +1459,8 @@ interrupt-names = "tx", "rx"; dmas = <&sdma_xbar 133>, <&sdma_xbar 132>; dma-names = "tx", "rx"; - clocks = <&mcasp3_ahclkx_mux>; - clock-names = "fck"; + clocks = <&mcasp3_aux_gfclk_mux>, <&mcasp3_ahclkx_mux>; + clock-names = "fck", "ahclkx"; status = "disabled"; }; -- cgit v0.10.2 From c12ba8ce2335389ce5416f88391cd67c7325c963 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Nov 2015 09:32:58 +0200 Subject: ARM: OMAP2+: hwmod: Add hwmod flag for HWMOD_OPT_CLKS_NEEDED Some module needs more than one functional clock in order to be accessible, like the McASPs found in DRA7xx family. This flag will indicate that the opt_clks need to be handled at the same time as the main_clk for the given hwmod, ensuring that all needed clocks are enabled before we try to access the module's address space. Signed-off-by: Peter Ujfalusi Acked-by: Paul Walmsley Tested-by: Felipe Balbi Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cc8a987..48495ad 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -890,6 +890,36 @@ static int _init_opt_clks(struct omap_hwmod *oh) return ret; } +static void _enable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: enable %s:%s\n", oc->role, + __clk_get_name(oc->_clk)); + clk_enable(oc->_clk); + } +} + +static void _disable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: disable %s:%s\n", oc->role, + __clk_get_name(oc->_clk)); + clk_disable(oc->_clk); + } +} + /** * _enable_clocks - enable hwmod main clock and interface clocks * @oh: struct omap_hwmod * @@ -917,6 +947,9 @@ static int _enable_clocks(struct omap_hwmod *oh) clk_enable(os->_clk); } + if (oh->flags & HWMOD_OPT_CLKS_NEEDED) + _enable_optional_clocks(oh); + /* The opt clocks are controlled by the device driver. */ return 0; @@ -948,41 +981,14 @@ static int _disable_clocks(struct omap_hwmod *oh) clk_disable(os->_clk); } + if (oh->flags & HWMOD_OPT_CLKS_NEEDED) + _disable_optional_clocks(oh); + /* The opt clocks are controlled by the device driver. */ return 0; } -static void _enable_optional_clocks(struct omap_hwmod *oh) -{ - struct omap_hwmod_opt_clk *oc; - int i; - - pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); - - for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) - if (oc->_clk) { - pr_debug("omap_hwmod: enable %s:%s\n", oc->role, - __clk_get_name(oc->_clk)); - clk_enable(oc->_clk); - } -} - -static void _disable_optional_clocks(struct omap_hwmod *oh) -{ - struct omap_hwmod_opt_clk *oc; - int i; - - pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); - - for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) - if (oc->_clk) { - pr_debug("omap_hwmod: disable %s:%s\n", oc->role, - __clk_get_name(oc->_clk)); - clk_disable(oc->_clk); - } -} - /** * _omap4_enable_module - enable CLKCTRL modulemode on OMAP4 * @oh: struct omap_hwmod * diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index ca6df1a..76bce11 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -523,6 +523,8 @@ struct omap_hwmod_omap4_prcm { * HWMOD_RECONFIG_IO_CHAIN: omap_hwmod code needs to reconfigure wake-up * events by calling _reconfigure_io_chain() when a device is enabled * or idled. + * HWMOD_OPT_CLKS_NEEDED: The optional clocks are needed for the module to + * operate and they need to be handled at the same time as the main_clk. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -538,6 +540,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_FORCE_MSTANDBY (1 << 11) #define HWMOD_SWSUP_SIDLE_ACT (1 << 12) #define HWMOD_RECONFIG_IO_CHAIN (1 << 13) +#define HWMOD_OPT_CLKS_NEEDED (1 << 14) /* * omap_hwmod._int_flags definitions -- cgit v0.10.2 From 469689a45f78505d864210b3a5d75404eb7f24ee Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Nov 2015 09:32:59 +0200 Subject: ARM: OMAP: DRA7: hwmod: Add data for McASP3 McASP3 is used by default on DRA7x based boards for audio. Signed-off-by: Peter Ujfalusi Acked-by: Paul Walmsley Tested-by: Felipe Balbi Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 51d1ecb..ee4e044 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -1298,6 +1298,44 @@ static struct omap_hwmod dra7xx_mcspi4_hwmod = { }; /* + * 'mcasp' class + * + */ +static struct omap_hwmod_class_sysconfig dra7xx_mcasp_sysc = { + .sysc_offs = 0x0004, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type3, +}; + +static struct omap_hwmod_class dra7xx_mcasp_hwmod_class = { + .name = "mcasp", + .sysc = &dra7xx_mcasp_sysc, +}; + +/* mcasp3 */ +static struct omap_hwmod_opt_clk mcasp3_opt_clks[] = { + { .role = "ahclkx", .clk = "mcasp3_ahclkx_mux" }, +}; + +static struct omap_hwmod dra7xx_mcasp3_hwmod = { + .name = "mcasp3", + .class = &dra7xx_mcasp_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "mcasp3_aux_gfclk_mux", + .flags = HWMOD_OPT_CLKS_NEEDED, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_MCASP3_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_MCASP3_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, + .opt_clks = mcasp3_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(mcasp3_opt_clks), +}; + +/* * 'mmc' class * */ @@ -2566,6 +2604,22 @@ static struct omap_hwmod_ocp_if dra7xx_l3_main_1__hdmi = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_per2 -> mcasp3 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__mcasp3 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_mcasp3_hwmod, + .clk = "l4_root_clk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l3_main_1 -> mcasp3 */ +static struct omap_hwmod_ocp_if dra7xx_l3_main_1__mcasp3 = { + .master = &dra7xx_l3_main_1_hwmod, + .slave = &dra7xx_mcasp3_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* l4_per1 -> elm */ static struct omap_hwmod_ocp_if dra7xx_l4_per1__elm = { .master = &dra7xx_l4_per1_hwmod, @@ -3308,6 +3362,8 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = { &dra7xx_l4_wkup__dcan1, &dra7xx_l4_per2__dcan2, &dra7xx_l4_per2__cpgmac0, + &dra7xx_l4_per2__mcasp3, + &dra7xx_l3_main_1__mcasp3, &dra7xx_gmac__mdio, &dra7xx_l4_cfg__dma_system, &dra7xx_l3_main_1__dss, -- cgit v0.10.2 From a519c27da6e8a4e74df2fde5654ea9a42dda9fcb Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 5 Nov 2015 13:17:57 +0800 Subject: dt-bindings: rockchip-thermal: Support the RK3368 SoCs compatible This patchset attempts to new compatible for thermal founding on RK3368 SoCs. Signed-off-by: Caesar Wang Acked-by: Rob Herring Signed-off-by: Eduardo Valentin diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt index b38200d..0dfa60d 100644 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt @@ -1,7 +1,9 @@ * Temperature Sensor ADC (TSADC) on rockchip SoCs Required properties: -- compatible : "rockchip,rk3288-tsadc" +- compatible : should be "rockchip,-tsadc" + "rockchip,rk3288-tsadc": found on RK3288 SoCs + "rockchip,rk3368-tsadc": found on RK3368 SoCs - reg : physical base address of the controller and length of memory mapped region. - interrupts : The interrupt number to the cpu. The interrupt specifier format -- cgit v0.10.2 From 1d98b618cc0d8d65650ac0de88c93c98013b1166 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 5 Nov 2015 13:17:58 +0800 Subject: thermal: rockchip: better to compatible the driver for different SoCs The current driver is default to register the two thermal sensors in probe since some SoCs maybe only have one sensor for thermal. In some cases, the channel 0 is not always the cpu or gpu sensor. So add the channel can be configured for sensors. Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 9787e8a..e72a69d 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -45,15 +45,25 @@ enum tshut_polarity { }; /** - * The system has three Temperature Sensors. channel 0 is reserved, - * channel 1 is for CPU, and channel 2 is for GPU. + * The system has two Temperature Sensors. + * sensor0 is for CPU, and sensor1 is for GPU. */ enum sensor_id { - SENSOR_CPU = 1, + SENSOR_CPU = 0, SENSOR_GPU, }; +/** + * The max sensors is two in rockchip SoCs. + * Two sensors: CPU and GPU sensor. + */ +#define SOC_MAX_SENSORS 2 + struct rockchip_tsadc_chip { + /* The sensor id of chip correspond to the ADC channel */ + int chn_id[SOC_MAX_SENSORS]; + int chn_num; + /* The hardware-controlled tshut property */ long tshut_temp; enum tshut_mode tshut_mode; @@ -73,17 +83,15 @@ struct rockchip_tsadc_chip { struct rockchip_thermal_sensor { struct rockchip_thermal_data *thermal; struct thermal_zone_device *tzd; - enum sensor_id id; + int id; }; -#define NUM_SENSORS 2 /* Ignore unused sensor 0 */ - struct rockchip_thermal_data { const struct rockchip_tsadc_chip *chip; struct platform_device *pdev; struct reset_control *reset; - struct rockchip_thermal_sensor sensors[NUM_SENSORS]; + struct rockchip_thermal_sensor sensors[SOC_MAX_SENSORS]; struct clk *clk; struct clk *pclk; @@ -95,7 +103,7 @@ struct rockchip_thermal_data { enum tshut_polarity tshut_polarity; }; -/* TSADC V2 Sensor info define: */ +/* TSADC Sensor info define: */ #define TSADCV2_AUTO_CON 0x04 #define TSADCV2_INT_EN 0x08 #define TSADCV2_INT_PD 0x0c @@ -318,6 +326,10 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, } static const struct rockchip_tsadc_chip rk3288_tsadc_data = { + .chn_id[SENSOR_CPU] = 1, /* cpu sensor is channel 1 */ + .chn_id[SENSOR_GPU] = 2, /* gpu sensor is channel 2 */ + .chn_num = 2, /* two channels for tsadc */ + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ .tshut_temp = 95000, @@ -357,7 +369,7 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) thermal->chip->irq_ack(thermal->regs); - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) + for (i = 0; i < thermal->chip->chn_num; i++) thermal_zone_device_update(thermal->sensors[i].tzd); return IRQ_HANDLED; @@ -442,7 +454,7 @@ static int rockchip_thermal_register_sensor(struct platform_device *pdev, struct rockchip_thermal_data *thermal, struct rockchip_thermal_sensor *sensor, - enum sensor_id id) + int id) { const struct rockchip_tsadc_chip *tsadc = thermal->chip; int error; @@ -481,7 +493,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) const struct of_device_id *match; struct resource *res; int irq; - int i; + int i, j; int error; match = of_match_node(of_rockchip_thermal_match, np); @@ -556,22 +568,19 @@ static int rockchip_thermal_probe(struct platform_device *pdev) thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); - error = rockchip_thermal_register_sensor(pdev, thermal, - &thermal->sensors[0], - SENSOR_CPU); - if (error) { - dev_err(&pdev->dev, - "failed to register CPU thermal sensor: %d\n", error); - goto err_disable_pclk; - } - - error = rockchip_thermal_register_sensor(pdev, thermal, - &thermal->sensors[1], - SENSOR_GPU); - if (error) { - dev_err(&pdev->dev, - "failed to register GPU thermal sensor: %d\n", error); - goto err_unregister_cpu_sensor; + for (i = 0; i < thermal->chip->chn_num; i++) { + error = rockchip_thermal_register_sensor(pdev, thermal, + &thermal->sensors[i], + thermal->chip->chn_id[i]); + if (error) { + dev_err(&pdev->dev, + "failed to register sensor[%d] : error = %d\n", + i, error); + for (j = 0; j < i; j++) + thermal_zone_of_sensor_unregister(&pdev->dev, + thermal->sensors[j].tzd); + goto err_disable_pclk; + } } error = devm_request_threaded_irq(&pdev->dev, irq, NULL, @@ -581,22 +590,23 @@ static int rockchip_thermal_probe(struct platform_device *pdev) if (error) { dev_err(&pdev->dev, "failed to request tsadc irq: %d\n", error); - goto err_unregister_gpu_sensor; + goto err_unregister_sensor; } thermal->chip->control(thermal->regs, true); - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) + for (i = 0; i < thermal->chip->chn_num; i++) rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); platform_set_drvdata(pdev, thermal); return 0; -err_unregister_gpu_sensor: - thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd); -err_unregister_cpu_sensor: - thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd); +err_unregister_sensor: + while (i--) + thermal_zone_of_sensor_unregister(&pdev->dev, + thermal->sensors[i].tzd); + err_disable_pclk: clk_disable_unprepare(thermal->pclk); err_disable_clk: @@ -610,7 +620,7 @@ static int rockchip_thermal_remove(struct platform_device *pdev) struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); int i; - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) { + for (i = 0; i < thermal->chip->chn_num; i++) { struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; rockchip_thermal_toggle_sensor(sensor, false); @@ -631,7 +641,7 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); int i; - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) + for (i = 0; i < thermal->chip->chn_num; i++) rockchip_thermal_toggle_sensor(&thermal->sensors[i], false); thermal->chip->control(thermal->regs, false); @@ -663,8 +673,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) { - enum sensor_id id = thermal->sensors[i].id; + for (i = 0; i < thermal->chip->chn_num; i++) { + int id = thermal->sensors[i].id; thermal->chip->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); @@ -674,7 +684,7 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) thermal->chip->control(thermal->regs, true); - for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) + for (i = 0; i < thermal->chip->chn_num; i++) rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); pinctrl_pm_select_default_state(dev); -- cgit v0.10.2 From 144c5565c22a392cf2917b40754fc88109765f07 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 5 Nov 2015 13:17:59 +0800 Subject: thermal: rockchip: trivial: fix typo in commit Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index e72a69d..907a317 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -237,15 +237,19 @@ static int rk_tsadcv2_code_to_temp(u32 code, int *temp) } /** - * rk_tsadcv2_initialize - initialize TASDC Controller - * (1) Set TSADCV2_AUTO_PERIOD, configure the interleave between - * every two accessing of TSADC in normal operation. - * (2) Set TSADCV2_AUTO_PERIOD_HT, configure the interleave between - * every two accessing of TSADC after the temperature is higher - * than COM_SHUT or COM_INT. - * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE, - * if the temperature is higher than COMP_INT or COMP_SHUT for - * "debounce" times, TSADC controller will generate interrupt or TSHUT. + * rk_tsadcv2_initialize - initialize TASDC Controller. + * + * (1) Set TSADC_V2_AUTO_PERIOD: + * Configure the interleave between every two accessing of + * TSADC in normal operation. + * + * (2) Set TSADCV2_AUTO_PERIOD_HT: + * Configure the interleave between every two accessing of + * TSADC after the temperature is higher than COM_SHUT or COM_INT. + * + * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: + * If the temperature is higher than COMP_INT or COMP_SHUT for + * "debounce" times, TSADC controller will generate interrupt or TSHUT. */ static void rk_tsadcv2_initialize(void __iomem *regs, enum tshut_polarity tshut_polarity) -- cgit v0.10.2 From 9b1b61cd8e31d9beba871333d7a798b3adb89288 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 15 Oct 2015 12:32:21 +0200 Subject: ARM: OMAP2+: remove custom abort handler for t410 This is not needed anymore. Handling a potentially pending imprecise external abort left behind by the bootloader is now done in a slightly safer way inside the common ARM startup code. With the recent changes to abort handling, this issue got fixed by 57df53808534 ("ARM: OMAP2+: Fix imprecise external abort caused by bogus SRAM init"). Signed-off-by: Lucas Stach [tony@atomide.com: updated comments to describe what fixed the issue] Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 1dfe346..5814477 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -24,9 +24,6 @@ #include #include -#include -#include - #include "common.h" #include "common-board-devices.h" #include "dss-common.h" @@ -385,29 +382,6 @@ static void __init omap3_pandora_legacy_init(void) } #endif /* CONFIG_ARCH_OMAP3 */ -#ifdef CONFIG_SOC_TI81XX -static int fault_fixed_up; - -static int t410_abort_handler(unsigned long addr, unsigned int fsr, - struct pt_regs *regs) -{ - if ((fsr == 0x406 || fsr == 0xc06) && !fault_fixed_up) { - pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n", - addr, fsr); - fault_fixed_up = 1; - return 0; - } - - return 1; -} - -static void __init t410_abort_init(void) -{ - hook_fault_code(16 + 6, t410_abort_handler, SIGBUS, BUS_OBJERR, - "imprecise external abort"); -} -#endif - #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) static struct iommu_platform_data omap4_iommu_pdata = { .reset_name = "mmu_cache", @@ -536,9 +510,6 @@ static struct pdata_init pdata_quirks[] __initdata = { { "openpandora,omap3-pandora-600mhz", omap3_pandora_legacy_init, }, { "openpandora,omap3-pandora-1ghz", omap3_pandora_legacy_init, }, #endif -#ifdef CONFIG_SOC_TI81XX - { "hp,t410", t410_abort_init, }, -#endif #ifdef CONFIG_SOC_OMAP5 { "ti,omap5-uevm", omap5_uevm_legacy_init, }, #endif -- cgit v0.10.2 From ce74110d5ed513b1b4f6e2eb4b7703f4163852bc Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 9 Nov 2015 12:48:56 +0800 Subject: thermal: rockchip: improve the conversion function We should make the conversion table in as a parameter since the different SoCs have the different conversionion table. Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 907a317..bbf082c 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -59,6 +59,16 @@ enum sensor_id { */ #define SOC_MAX_SENSORS 2 +struct chip_tsadc_table { + const struct tsadc_table *id; + + /* the array table size*/ + unsigned int length; + + /* that analogic mask data */ + u32 data_mask; +}; + struct rockchip_tsadc_chip { /* The sensor id of chip correspond to the ADC channel */ int chn_id[SOC_MAX_SENSORS]; @@ -75,9 +85,14 @@ struct rockchip_tsadc_chip { void (*control)(void __iomem *reg, bool on); /* Per-sensor methods */ - int (*get_temp)(int chn, void __iomem *reg, int *temp); - void (*set_tshut_temp)(int chn, void __iomem *reg, long temp); + int (*get_temp)(struct chip_tsadc_table table, + int chn, void __iomem *reg, int *temp); + void (*set_tshut_temp)(struct chip_tsadc_table table, + int chn, void __iomem *reg, long temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); + + /* Per-table methods */ + struct chip_tsadc_table table; }; struct rockchip_thermal_sensor { @@ -173,21 +188,22 @@ static const struct tsadc_table v2_code_table[] = { {3421, 125000}, }; -static u32 rk_tsadcv2_temp_to_code(long temp) +static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, + long temp) { int high, low, mid; low = 0; - high = ARRAY_SIZE(v2_code_table) - 1; + high = table.length - 1; mid = (high + low) / 2; - if (temp < v2_code_table[low].temp || temp > v2_code_table[high].temp) + if (temp < table.id[low].temp || temp > table.id[high].temp) return 0; while (low <= high) { - if (temp == v2_code_table[mid].temp) - return v2_code_table[mid].code; - else if (temp < v2_code_table[mid].temp) + if (temp == table.id[mid].temp) + return table.id[mid].code; + else if (temp < table.id[mid].temp) high = mid - 1; else low = mid + 1; @@ -197,25 +213,26 @@ static u32 rk_tsadcv2_temp_to_code(long temp) return 0; } -static int rk_tsadcv2_code_to_temp(u32 code, int *temp) +static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, + int *temp) { unsigned int low = 1; - unsigned int high = ARRAY_SIZE(v2_code_table) - 1; + unsigned int high = table.length - 1; unsigned int mid = (low + high) / 2; unsigned int num; unsigned long denom; - BUILD_BUG_ON(ARRAY_SIZE(v2_code_table) < 2); + WARN_ON(table.length < 2); - code &= TSADCV2_DATA_MASK; - if (code < v2_code_table[high].code) + code &= table.data_mask; + if (code < table.id[high].code) return -EAGAIN; /* Incorrect reading */ while (low <= high) { - if (code >= v2_code_table[mid].code && - code < v2_code_table[mid - 1].code) + if (code >= table.id[mid].code && + code < table.id[mid - 1].code) break; - else if (code < v2_code_table[mid].code) + else if (code < table.id[mid].code) low = mid + 1; else high = mid - 1; @@ -228,10 +245,10 @@ static int rk_tsadcv2_code_to_temp(u32 code, int *temp) * temperature between 2 table entries is linear and interpolate * to produce less granular result. */ - num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp; - num *= v2_code_table[mid - 1].code - code; - denom = v2_code_table[mid - 1].code - v2_code_table[mid].code; - *temp = v2_code_table[mid - 1].temp + (num / denom); + num = table.id[mid].temp - v2_code_table[mid - 1].temp; + num *= table.id[mid - 1].code - code; + denom = table.id[mid - 1].code - table.id[mid].code; + *temp = table.id[mid - 1].temp + (num / denom); return 0; } @@ -291,20 +308,22 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable) writel_relaxed(val, regs + TSADCV2_AUTO_CON); } -static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp) +static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, + int chn, void __iomem *regs, int *temp) { u32 val; val = readl_relaxed(regs + TSADCV2_DATA(chn)); - return rk_tsadcv2_code_to_temp(val, temp); + return rk_tsadcv2_code_to_temp(table, val, temp); } -static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp) +static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, + int chn, void __iomem *regs, long temp) { u32 tshut_value, val; - tshut_value = rk_tsadcv2_temp_to_code(temp); + tshut_value = rk_tsadcv2_temp_to_code(table, temp); writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); /* TSHUT will be valid */ @@ -344,6 +363,12 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { .get_temp = rk_tsadcv2_get_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = v2_code_table, + .length = ARRAY_SIZE(v2_code_table), + .data_mask = TSADCV2_DATA_MASK, + }, }; static const struct of_device_id of_rockchip_thermal_match[] = { @@ -386,7 +411,8 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip; int retval; - retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp); + retval = tsadc->get_temp(tsadc->table, + sensor->id, thermal->regs, out_temp); dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n", sensor->id, *out_temp, retval); @@ -464,7 +490,8 @@ rockchip_thermal_register_sensor(struct platform_device *pdev, int error; tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); - tsadc->set_tshut_temp(id, thermal->regs, thermal->tshut_temp); + tsadc->set_tshut_temp(tsadc->table, id, thermal->regs, + thermal->tshut_temp); sensor->thermal = thermal; sensor->id = id; @@ -682,7 +709,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) thermal->chip->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); - thermal->chip->set_tshut_temp(id, thermal->regs, + thermal->chip->set_tshut_temp(thermal->chip->table, + id, thermal->regs, thermal->tshut_temp); } -- cgit v0.10.2 From 020ba95dbbbe83073a9728e046b4512b40896197 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 9 Nov 2015 12:48:57 +0800 Subject: thermal: rockchip: Add the sort mode for adc value increment or decrement The conversion table has the adc value and temperature. In fact, the adc value only has the increment or decrement mode in conversion table. Moment, we can add the sort mode to be better support the *code_to_temp* for differenr SoCs. Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index bbf082c..7c5b784 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -54,6 +54,16 @@ enum sensor_id { }; /** +* The conversion table has the adc value and temperature. +* ADC_DECREMENT is the adc value decremnet.(e.g. v2_code_table) +* ADC_INCREMNET is the adc value incremnet.(e.g. v3_code_table) +*/ +enum adc_sort_mode { + ADC_DECREMENT = 0, + ADC_INCREMENT, +}; + +/** * The max sensors is two in rockchip SoCs. * Two sensors: CPU and GPU sensor. */ @@ -67,6 +77,9 @@ struct chip_tsadc_table { /* that analogic mask data */ u32 data_mask; + + /* the sort mode is adc value that increment or decrement in table */ + enum adc_sort_mode mode; }; struct rockchip_tsadc_chip { @@ -224,19 +237,43 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, WARN_ON(table.length < 2); - code &= table.data_mask; - if (code < table.id[high].code) - return -EAGAIN; /* Incorrect reading */ - - while (low <= high) { - if (code >= table.id[mid].code && - code < table.id[mid - 1].code) - break; - else if (code < table.id[mid].code) - low = mid + 1; - else - high = mid - 1; - mid = (low + high) / 2; + switch (table.mode) { + case ADC_DECREMENT: + code &= table.data_mask; + if (code < table.id[high].code) + return -EAGAIN; /* Incorrect reading */ + + while (low <= high) { + if (code >= table.id[mid].code && + code < table.id[mid - 1].code) + break; + else if (code < table.id[mid].code) + low = mid + 1; + else + high = mid - 1; + + mid = (low + high) / 2; + } + break; + case ADC_INCREMENT: + code &= table.data_mask; + if (code < table.id[low].code) + return -EAGAIN; /* Incorrect reading */ + + while (low <= high) { + if (code >= table.id[mid - 1].code && + code < table.id[mid].code) + break; + else if (code > table.id[mid].code) + low = mid + 1; + else + high = mid - 1; + + mid = (low + high) / 2; + } + break; + default: + pr_err("Invalid the conversion table\n"); } /* @@ -246,8 +283,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, * to produce less granular result. */ num = table.id[mid].temp - v2_code_table[mid - 1].temp; - num *= table.id[mid - 1].code - code; - denom = table.id[mid - 1].code - table.id[mid].code; + num *= abs(table.id[mid - 1].code - code); + denom = abs(table.id[mid - 1].code - table.id[mid].code); *temp = table.id[mid - 1].temp + (num / denom); return 0; @@ -368,6 +405,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { .id = v2_code_table, .length = ARRAY_SIZE(v2_code_table), .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_DECREMENT, }, }; -- cgit v0.10.2 From 437df2172e8d63b21b748ba1f3ac574451a51440 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 9 Nov 2015 12:48:58 +0800 Subject: thermal: rockchip: consistently use int for temperatures As Temperature is currently represented as int not long in the thermal framework since use int intead of unsigned long/long to represent temperature to avoid bogus overheat detection when negative temperature reported. Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 7c5b784..73d47f8 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -88,7 +88,7 @@ struct rockchip_tsadc_chip { int chn_num; /* The hardware-controlled tshut property */ - long tshut_temp; + int tshut_temp; enum tshut_mode tshut_mode; enum tshut_polarity tshut_polarity; @@ -101,7 +101,7 @@ struct rockchip_tsadc_chip { int (*get_temp)(struct chip_tsadc_table table, int chn, void __iomem *reg, int *temp); void (*set_tshut_temp)(struct chip_tsadc_table table, - int chn, void __iomem *reg, long temp); + int chn, void __iomem *reg, int temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); /* Per-table methods */ @@ -126,7 +126,7 @@ struct rockchip_thermal_data { void __iomem *regs; - long tshut_temp; + int tshut_temp; enum tshut_mode tshut_mode; enum tshut_polarity tshut_polarity; }; @@ -160,7 +160,7 @@ struct rockchip_thermal_data { struct tsadc_table { u32 code; - long temp; + int temp; }; static const struct tsadc_table v2_code_table[] = { @@ -202,7 +202,7 @@ static const struct tsadc_table v2_code_table[] = { }; static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, - long temp) + int temp) { int high, low, mid; @@ -356,7 +356,7 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, } static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, - int chn, void __iomem *regs, long temp) + int chn, void __iomem *regs, int temp) { u32 tshut_value, val; @@ -469,7 +469,7 @@ static int rockchip_configure_from_dt(struct device *dev, if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) { dev_warn(dev, - "Missing tshut temp property, using default %ld\n", + "Missing tshut temp property, using default %d\n", thermal->chip->tshut_temp); thermal->tshut_temp = thermal->chip->tshut_temp; } else { @@ -477,7 +477,7 @@ static int rockchip_configure_from_dt(struct device *dev, } if (thermal->tshut_temp > INT_MAX) { - dev_err(dev, "Invalid tshut temperature specified: %ld\n", + dev_err(dev, "Invalid tshut temperature specified: %d\n", thermal->tshut_temp); return -ERANGE; } -- cgit v0.10.2 From 20f0af759d79c53a818da5c953874c9e801f726a Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 9 Nov 2015 12:48:59 +0800 Subject: thermal: rockchip: Support the RK3368 SoCs in thermal driver The RK3368 SoCs support to 2 channel TS-ADC, the temperature criteria of each channel can be configurable. The system has two Temperature Sensors, channel 0 is for CPU, and channel 1 is for GPU. Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 73d47f8..e845841 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * + * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd + * Caesar Wang + * * 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. @@ -153,6 +156,8 @@ struct rockchip_thermal_data { #define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) #define TSADCV2_DATA_MASK 0xfff +#define TSADCV3_DATA_MASK 0x3ff + #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ @@ -201,6 +206,45 @@ static const struct tsadc_table v2_code_table[] = { {3421, 125000}, }; +static const struct tsadc_table v3_code_table[] = { + {0, -40000}, + {106, -40000}, + {108, -35000}, + {110, -30000}, + {112, -25000}, + {114, -20000}, + {116, -15000}, + {118, -10000}, + {120, -5000}, + {122, 0}, + {124, 5000}, + {126, 10000}, + {128, 15000}, + {130, 20000}, + {132, 25000}, + {134, 30000}, + {136, 35000}, + {138, 40000}, + {140, 45000}, + {142, 50000}, + {144, 55000}, + {146, 60000}, + {148, 65000}, + {150, 70000}, + {152, 75000}, + {154, 80000}, + {156, 85000}, + {158, 90000}, + {160, 95000}, + {162, 100000}, + {163, 105000}, + {165, 110000}, + {167, 115000}, + {169, 120000}, + {171, 125000}, + {TSADCV3_DATA_MASK, 125000}, +}; + static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, int temp) { @@ -409,11 +453,39 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { }, }; +static const struct rockchip_tsadc_chip rk3368_tsadc_data = { + .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ + .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ + .chn_num = 2, /* two channels for tsadc */ + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv2_irq_ack, + .control = rk_tsadcv2_control, + .get_temp = rk_tsadcv2_get_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = v3_code_table, + .length = ARRAY_SIZE(v3_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + static const struct of_device_id of_rockchip_thermal_match[] = { { .compatible = "rockchip,rk3288-tsadc", .data = (void *)&rk3288_tsadc_data, }, + { + .compatible = "rockchip,rk3368-tsadc", + .data = (void *)&rk3368_tsadc_data, + }, { /* end */ }, }; MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); -- cgit v0.10.2 From bb404db47b8a4ade8c85d13fb44908b0ee15483c Mon Sep 17 00:00:00 2001 From: Kapileshwar Singh Date: Tue, 13 Oct 2015 12:30:01 +0100 Subject: thermal: power_allocator: Use temperature reading from tz All thermal governors use the temperature value stored in struct thermal_zone_device. thermal_zone_device->temperature power_allocator governor should not deviate from this and use the same. Cc: Javi Merino Cc: Eduardo Valentin Cc: Daniel Kurtz Cc: Zhang Rui Cc: Dmitry Torokhov Cc: Sascha Hauer Cc: Andrea Arcangeli Acked-by: Javi Merino Reported-by: Sugumar Natarajan Signed-off-by: Kapileshwar Singh Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index f0fbea3..1246aa6 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -174,7 +174,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz, /** * pid_controller() - PID controller * @tz: thermal zone we are operating in - * @current_temp: the current temperature in millicelsius * @control_temp: the target temperature in millicelsius * @max_allocatable_power: maximum allocatable power for this thermal zone * @@ -191,7 +190,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz, * Return: The power budget for the next period. */ static u32 pid_controller(struct thermal_zone_device *tz, - int current_temp, int control_temp, u32 max_allocatable_power) { @@ -211,7 +209,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, true); } - err = control_temp - current_temp; + err = control_temp - tz->temperature; err = int_to_frac(err); /* Calculate the proportional term */ @@ -332,7 +330,6 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors, } static int allocate_power(struct thermal_zone_device *tz, - int current_temp, int control_temp) { struct thermal_instance *instance; @@ -418,8 +415,7 @@ static int allocate_power(struct thermal_zone_device *tz, i++; } - power_range = pid_controller(tz, current_temp, control_temp, - max_allocatable_power); + power_range = pid_controller(tz, control_temp, max_allocatable_power); divvy_up_power(weighted_req_power, max_power, num_actors, total_weighted_req_power, power_range, granted_power, @@ -444,8 +440,8 @@ static int allocate_power(struct thermal_zone_device *tz, trace_thermal_power_allocator(tz, req_power, total_req_power, granted_power, total_granted_power, num_actors, power_range, - max_allocatable_power, current_temp, - control_temp - current_temp); + max_allocatable_power, tz->temperature, + control_temp - tz->temperature); kfree(req_power); unlock: @@ -612,7 +608,7 @@ static void power_allocator_unbind(struct thermal_zone_device *tz) static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) { int ret; - int switch_on_temp, control_temp, current_temp; + int switch_on_temp, control_temp; struct power_allocator_params *params = tz->governor_data; /* @@ -622,15 +618,9 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) if (trip != params->trip_max_desired_temperature) return 0; - ret = thermal_zone_get_temp(tz, ¤t_temp); - if (ret) { - dev_warn(&tz->device, "Failed to get temperature: %d\n", ret); - return ret; - } - ret = tz->ops->get_trip_temp(tz, params->trip_switch_on, &switch_on_temp); - if (!ret && (current_temp < switch_on_temp)) { + if (!ret && (tz->temperature < switch_on_temp)) { tz->passive = 0; reset_pid_controller(params); allow_maximum_power(tz); @@ -648,7 +638,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) return ret; } - return allocate_power(tz, current_temp, control_temp); + return allocate_power(tz, control_temp); } static struct thermal_governor thermal_gov_power_allocator = { -- cgit v0.10.2 From 12551ced30bb4658496ba76b7998dc6930b45722 Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Thu, 5 Nov 2015 09:50:40 +0100 Subject: ath10k: fix the currently supported QCA9377 target version name When introducing the original QCA9377 support, the chip target version was wrongly picked. The chip advertising itself with bmi target value equal to 0x05020001 is in fact a 1.1 revision. I realized this once I got a real 1.1 hw to play with. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index aa9bd92..c8f6ca2 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -138,8 +138,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }, { - .id = QCA9377_HW_1_0_DEV_VERSION, - .name = "qca9377 hw1.0", + .id = QCA9377_HW_1_1_DEV_VERSION, + .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 39966a0..01bf224 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -42,6 +42,8 @@ #define QCA6174_HW_3_0_VERSION 0x05020000 #define QCA6174_HW_3_2_VERSION 0x05030000 +#define QCA9377_HW_1_1_DEV_VERSION 0x05020001 + enum qca6174_pci_rev { QCA6174_PCI_REV_1_1 = 0x11, QCA6174_PCI_REV_1_3 = 0x13, @@ -60,6 +62,10 @@ enum qca6174_chip_id_rev { QCA6174_HW_3_2_CHIP_ID_REV = 10, }; +enum qca9377_chip_id_rev { + QCA9377_HW_1_1_CHIP_ID_REV = 0x1, +}; + #define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" #define QCA6174_HW_2_1_FW_FILE "firmware.bin" #define QCA6174_HW_2_1_OTP_FILE "otp.bin" @@ -85,8 +91,6 @@ enum qca6174_chip_id_rev { #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 /* QCA9377 1.0 definitions */ -#define QCA9377_HW_1_0_DEV_VERSION 0x05020001 -#define QCA9377_HW_1_0_CHIP_ID_REV 0x1 #define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0" #define QCA9377_HW_1_0_FW_FILE "firmware.bin" #define QCA9377_HW_1_0_OTP_FILE "otp.bin" diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3fca200..c444b43 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -92,7 +92,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, - { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV }, + { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV }, }; static void ath10k_pci_buffer_cleanup(struct ath10k *ar); -- cgit v0.10.2 From 6cf213958299803c1166e63c1805a8b8cd135be5 Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Thu, 5 Nov 2015 09:50:41 +0100 Subject: ath10k: update missing hw_params of QCA9377 hw1.1 The uart_pin was incorrectly configured for QCA9377 and the recently added hw_params were omitted. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c8f6ca2..a30d415 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -141,8 +141,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .id = QCA9377_HW_1_1_DEV_VERSION, .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, - .uart_pin = 7, + .uart_pin = 6, .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, .fw = { .dir = QCA9377_HW_1_0_FW_DIR, .fw = QCA9377_HW_1_0_FW_FILE, -- cgit v0.10.2 From 079a0490e207c5a88e4b40cefcc331f4bce562f4 Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Thu, 5 Nov 2015 09:50:42 +0100 Subject: ath10k: introduce dev_id to hw_params A follow up patch introducing a QCA9377 hw1.0 support will need this device identification helper for an explicit distinction of HWs, as apparently both QCA6174 hw3.0 and QCA9377 share the same BMI target version (0x0502000x). For the QCA9377 hw1.1 previously added we were just lucky we did not overlap with the same chip_id_rev. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a30d415..b80b8f3 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -51,6 +51,7 @@ MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, + .dev_id = QCA988X_2_0_DEVICE_ID, .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -69,6 +70,25 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, { .id = QCA6174_HW_2_1_VERSION, + .dev_id = QCA6164_2_1_DEVICE_ID, + .name = "qca6164 hw2.1", + .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, + .uart_pin = 6, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .fw = { + .dir = QCA6174_HW_2_1_FW_DIR, + .fw = QCA6174_HW_2_1_FW_FILE, + .otp = QCA6174_HW_2_1_OTP_FILE, + .board = QCA6174_HW_2_1_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA6174_HW_2_1_VERSION, + .dev_id = QCA6174_2_1_DEVICE_ID, .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -86,6 +106,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, { .id = QCA6174_HW_3_0_VERSION, + .dev_id = QCA6174_2_1_DEVICE_ID, .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -103,6 +124,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, { .id = QCA6174_HW_3_2_VERSION, + .dev_id = QCA6174_2_1_DEVICE_ID, .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -121,6 +143,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, { .id = QCA99X0_HW_2_0_DEV_VERSION, + .dev_id = QCA99X0_2_0_DEVICE_ID, .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -139,6 +162,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, { .id = QCA9377_HW_1_1_DEV_VERSION, + .dev_id = QCA9377_1_0_DEVICE_ID, .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -1265,7 +1289,8 @@ static int ath10k_init_hw_params(struct ath10k *ar) for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { hw_params = &ath10k_hw_params_list[i]; - if (hw_params->id == ar->target_version) + if (hw_params->id == ar->target_version && + hw_params->dev_id == ar->dev_id) break; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4a23015..622d381 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -636,6 +636,7 @@ struct ath10k { struct ath10k_hw_params { u32 id; + u16 dev_id; const char *name; u32 patch_load_addr; int uart_pin; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 01bf224..13aacbd 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -22,6 +22,12 @@ #define ATH10K_FW_DIR "ath10k" +#define QCA988X_2_0_DEVICE_ID (0x003c) +#define QCA6164_2_1_DEVICE_ID (0x0041) +#define QCA6174_2_1_DEVICE_ID (0x003e) +#define QCA99X0_2_0_DEVICE_ID (0x0040) +#define QCA9377_1_0_DEVICE_ID (0x0042) + /* QCA988X 1.0 definitions (unsupported) */ #define QCA988X_HW_1_0_CHIP_ID_REV 0x0 diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c444b43..14dce2a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -57,12 +57,6 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_TARGET_WAIT 3000 #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 -#define QCA988X_2_0_DEVICE_ID (0x003c) -#define QCA6164_2_1_DEVICE_ID (0x0041) -#define QCA6174_2_1_DEVICE_ID (0x003e) -#define QCA99X0_2_0_DEVICE_ID (0x0040) -#define QCA9377_1_0_DEVICE_ID (0x0042) - static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ -- cgit v0.10.2 From 034074f3a889b69325326e612b7b37f3492a65ad Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Thu, 5 Nov 2015 09:50:43 +0100 Subject: ath10k: add QCA9377 hw1.0 support Add new BMI target version and chip id revision. Register it on supported chips list. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b80b8f3..0947cc2 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -161,6 +161,24 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }, { + .id = QCA9377_HW_1_0_DEV_VERSION, + .dev_id = QCA9377_1_0_DEVICE_ID, + .name = "qca9377 hw1.0", + .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 6, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .fw = { + .dir = QCA9377_HW_1_0_FW_DIR, + .fw = QCA9377_HW_1_0_FW_FILE, + .otp = QCA9377_HW_1_0_OTP_FILE, + .board = QCA9377_HW_1_0_BOARD_DATA_FILE, + .board_size = QCA9377_BOARD_DATA_SZ, + .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, + }, + }, + { .id = QCA9377_HW_1_1_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, .name = "qca9377 hw1.1", diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 13aacbd..713c2bc 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -48,6 +48,8 @@ #define QCA6174_HW_3_0_VERSION 0x05020000 #define QCA6174_HW_3_2_VERSION 0x05030000 +/* QCA9377 target BMI version signatures */ +#define QCA9377_HW_1_0_DEV_VERSION 0x05020000 #define QCA9377_HW_1_1_DEV_VERSION 0x05020001 enum qca6174_pci_rev { @@ -69,6 +71,7 @@ enum qca6174_chip_id_rev { }; enum qca9377_chip_id_rev { + QCA9377_HW_1_0_CHIP_ID_REV = 0x0, QCA9377_HW_1_1_CHIP_ID_REV = 0x1, }; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 14dce2a..679a3eb 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -86,6 +86,8 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, + + { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV }, { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV }, }; -- cgit v0.10.2 From 2727a743e9eeb3d4063d4077afee3fd2a5e198ca Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Thu, 5 Nov 2015 18:44:27 -0800 Subject: ath10k: override CE5 configuration for QCA6147 device Commit a70587b3389a ("ath10k: configure copy engine 5 for HTT messages") introduced to use the unused CE5 for target to host message. For the device like QCA6174, CE5 already assigned for other feature. So for QCA6174, override the CE5 configuration and use the CE1 instead. This patch is based on Rajkumar's earlier patch. Fixes: a70587b3389a ("ath10k: configure copy engine 5 for HTT messages") Signed-off-by: Ryan Hsu Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 679a3eb..0ad3dd1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -108,7 +108,7 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state); -static const struct ce_attr host_ce_config_wlan[] = { +static struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ { .flags = CE_ATTR_FLAGS, @@ -213,7 +213,7 @@ static const struct ce_attr host_ce_config_wlan[] = { }; /* Target firmware's Copy Engine configuration. */ -static const struct ce_pipe_config target_ce_config_wlan[] = { +static struct ce_pipe_config target_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ { .pipenum = __cpu_to_le32(0), @@ -326,7 +326,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { * This table is derived from the CE_PCI TABLE, above. * It is passed to the Target at startup for use by firmware. */ -static const struct service_to_pipe target_service_to_ce_map_wlan[] = { +static struct service_to_pipe target_service_to_ce_map_wlan[] = { { __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ @@ -2023,6 +2023,29 @@ static int ath10k_pci_init_config(struct ath10k *ar) return 0; } +static void ath10k_pci_override_ce_config(struct ath10k *ar) +{ + struct ce_attr *attr; + struct ce_pipe_config *config; + + /* For QCA6174 we're overriding the Copy Engine 5 configuration, + * since it is currently used for other feature. + */ + + /* Override Host's Copy Engine 5 configuration */ + attr = &host_ce_config_wlan[5]; + attr->src_sz_max = 0; + attr->dest_nentries = 0; + + /* Override Target firmware's Copy Engine configuration */ + config = &target_ce_config_wlan[5]; + config->pipedir = __cpu_to_le32(PIPEDIR_OUT); + config->nbytes_max = __cpu_to_le32(2048); + + /* Map from service/endpoint to Copy Engine */ + target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1); +} + static int ath10k_pci_alloc_pipes(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -3016,6 +3039,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_core_destroy; } + if (QCA_REV_6174(ar)) + ath10k_pci_override_ce_config(ar); + ret = ath10k_pci_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", -- cgit v0.10.2 From 23ba8a66234943e0b41c13ef7ca1088cf8488025 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 8 Nov 2015 14:03:17 +0200 Subject: MAINTAINERS: wil6210: new maintainer - Maya Erez Maya Erez will maintain the wil6210 driver Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo diff --git a/MAINTAINERS b/MAINTAINERS index 5974a0f..a457deb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1814,7 +1814,7 @@ S: Supported F: drivers/net/wireless/ath/ath6kl/ WILOCITY WIL6210 WIRELESS DRIVER -M: Vladimir Kondratiev +M: Maya Erez L: linux-wireless@vger.kernel.org L: wil6210@qca.qualcomm.com S: Supported -- cgit v0.10.2 From 15de0de29f7ba5cce9699a8cc2344ca137beb25a Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Thu, 12 Nov 2015 23:40:37 +0530 Subject: mpt3sas: Fix use sas_is_tlr_enabled API before enabling MPI2_SCSIIO_CONTROL_TLR_ON flag Before enabling MPI2_SCSIIO_CONTROL_TLR_ON flag in MPI SCSI IO request message, check whether TLR is enabled on the drive using 'sas_is_tlr_enabled' API. Actually in the driver code, driver is using below API's 1. sas_enable_tlr() - to enable the TLR 2. sas_disable_tlr() - to disable the TLR 3. sas_is_tlr_enabled() - to check whether TLR is enabled or not. but in scsih_qcmd() we have missed to use sas_is_tlr_enabled() API, instead we checking for TLR bit from flag field of driver's 'struct MPT3SAS_DEVIC' structure. which is corrected with this patch. Signed-off-by: Sreekanth Reddy Reviewed-by: Hannes Reinecke Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index d95206b..9ab77b0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -3905,8 +3905,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) * We do not expose raid functionality to upper layer for warpdrive. */ if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev) - && (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && - scmd->cmd_len != 32) + && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); -- cgit v0.10.2 From 78b7b80cf0abd5ea31d229300b11e9c3a97324ae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Nov 2015 17:23:23 +0300 Subject: mvsas: don't allow negative timeouts There is a static checker warning here because "val" is controlled by the user and we have a upper bound on it but allow negative numbers. "val" appears to be a timeout in usec so this bug probably means we have a longer timeout than we should. Let's fix this by changing "val" to unsigned. Signed-off-by: Dan Carpenter Reviewed-by: Jack Wang Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 1960d956..b39fe64 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -759,7 +759,7 @@ mvs_store_interrupt_coalescing(struct device *cdev, struct device_attribute *attr, const char *buffer, size_t size) { - int val = 0; + unsigned int val = 0; struct mvs_info *mvi = NULL; struct Scsi_Host *shost = class_to_shost(cdev); struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); @@ -767,7 +767,7 @@ mvs_store_interrupt_coalescing(struct device *cdev, if (buffer == NULL) return size; - if (sscanf(buffer, "%d", &val) != 1) + if (sscanf(buffer, "%u", &val) != 1) return -EINVAL; if (val >= 0x10000) { -- cgit v0.10.2 From d8a080c3746c0b60905a88ca56e83a8239c184e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Nov 2015 12:43:38 +0300 Subject: hpsa: logical vs bitwise AND typo HPSA_DIAG_OPTS_DISABLE_RLD_CACHING is a mask and bitwise AND was intended here instead of logical &&. This bug is essentially harmless, it means that sometimes we don't print a warning message which we wanted to print. Fixes: c2adae44e916 ('hpsa: disable report lun data caching') Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Acked-by: Don Brace Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6d44123..bff9509 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8679,7 +8679,7 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) if ((rc != 0) || (c->err_info->CommandStatus != 0)) goto errout; - if (*options && HPSA_DIAG_OPTS_DISABLE_RLD_CACHING) + if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING) goto out; errout: -- cgit v0.10.2 From 86f799b82f5c011404ddef54600bc5e99b7e0cf2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 14 Nov 2015 17:46:31 +0100 Subject: ALSA: hda - Fix noise on Dell Latitude E6440 Dell Latitude E6440 (1028:05bd) needs the same fixup as applied to other Latitude E7xxx models for the click noise due to the recent power-saving changes. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=954876 Cc: # v4.1+ Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2f7b065..081ef9b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5182,6 +5182,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), + SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), -- cgit v0.10.2 From 5d5563b14fe34021b690eb3edc54abcc876e417c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 14 Nov 2015 16:42:04 +0900 Subject: ALSA: dice: fix detection of Loud devices Commit a471fcde8c2c ("ALSA: dice: fix detection of Weiss devices") adds a quirk of Weiss models. According to users' reports, Loud models also have the similar quirk. They have 0x10 in the category field. This commit adds support for Mackie Onyx Blackbird and Onyx-i series. As long as I know, Dice-based models produced by Focusrite/Alesis/PreSonus/M-Audio/TC Electronic have default value (0x04) in their category field, thus it may be reasonable to add a condition statement for Loud models, instead of removing the check of category value. Reported-by: Rouge Etienne Reported-by: Etilem Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 5d99436..0cda05c 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -12,9 +12,11 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); #define OUI_WEISS 0x001c6a +#define OUI_LOUD 0x000ff2 #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 +#define LOUD_CATEGORY_ID 0x10 static int dice_interface_check(struct fw_unit *unit) { @@ -57,6 +59,8 @@ static int dice_interface_check(struct fw_unit *unit) } if (vendor == OUI_WEISS) category = WEISS_CATEGORY_ID; + else if (vendor == OUI_LOUD) + category = LOUD_CATEGORY_ID; else category = DICE_CATEGORY_ID; if (device->config_rom[3] != ((vendor << 8) | category) || -- cgit v0.10.2 From 4ab75944c4b324c1f5f01dbd4c4d122d2b9da187 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 28 Oct 2015 12:32:20 +0200 Subject: iwlwifi: Add new PCI IDs for the 8260 series Add some new PCI IDs for the 8260 series which were missing. The following sub-system IDs were added: 0x0130, 0x1130, 0x0132, 0x1132, 0x1150, 0x8110, 0x9110, 0x8130, 0x9130, 0x8132, 0x9132, 0x8150, 0x9150, 0x0044, 0x0930 CC: [4.1+] Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 644b58b..639761f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -423,14 +423,21 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1132, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x01F0, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0012, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1012, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1150, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)}, @@ -438,18 +445,28 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9130, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8132, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9132, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8150, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9150, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0044, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} -- cgit v0.10.2 From 5fd6705c366f885471b979de95ba14411e812395 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 15 Nov 2015 11:23:39 +0200 Subject: iwlwifi: bump firmware API to 19 This firmware will be the first firmware to support 3168. It hasn't been released yet. Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 1a73c7a..bf88ec3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 17 +#define IWL7260_UCODE_API_MAX 19 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 13 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 0116e5a..9bcc0bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 17 +#define IWL8000_UCODE_API_MAX 19 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 13 -- cgit v0.10.2 From d6ee54a9d7c807cdb8eb77d7f019cce344c2162c Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 10 Nov 2015 22:13:43 +0200 Subject: iwlwifi: mvm: don't overwrite the key indices in D3 entry When entering D3, we need to use hardcoded key indices because the firmware requires that. To do so, we are overwriting the HW key index in the keyconf structure, which makes it impossible to reuse the indices that were used before entering D3. Additionally, we overwrite all the non-PTK keys with index 1, because the firmware only allows one non-PTK key to be set. This is bad, because when we resume, we may try to set more than one key with index 1, which will obviously fail. To fix this, allow the callers to set a pre-defined index to use in iwl_mvm_set_sta_key() instead of relying on the hw_key_idx value from the keyconf struct (which requires overwriting it). In normal cases, the caller can pass STA_KEY_IDX_INVALID, which will cause a new key offset to be chosen. During HW_RESTART, we pass the offset that is in use. And during D3 entry, we pass the hardcoded indices we need to use. Additionally, don't clear the fw_key_table in D3 entry, so that the flags are still set with the pre-D3 values when exiting D3. fixes=I3165c22362483f0152d9ec1d2a987fb5529727c1 Fixes: b546dcd6b742 ("iwlwifi: mvm: don't reset key index on HW restart") Signed-off-by: Luca Coelho Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 85ae902..29ae58e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, * to transmit packets to the AP, i.e. the PTK. */ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - key->hw_key_idx = 0; mvm->ptk_ivlen = key->iv_len; mvm->ptk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0); } else { /* * firmware only supports TSC/RSC for a single key, @@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, * with new ones -- this relies on mac80211 doing * list_add_tail(). */ - key->hw_key_idx = 1; mvm->gtk_ivlen = key->iv_len; mvm->gtk_icvlen = key->icv_len; + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1); } - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); data->error = ret != 0; out_unlock: mutex_unlock(&mvm->mutex); @@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) */ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - /* We reprogram keys and shouldn't allocate new key indices */ - memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - mvm->ptk_ivlen = 0; mvm->ptk_icvlen = 0; mvm->ptk_ivlen = 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 1fb6846..e88afac 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + u8 key_offset; if (iwlwifi_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); @@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, break; } + /* in HW restart reuse the index, otherwise request a new one */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + key_offset = key->hw_key_idx; + else + key_offset = STA_KEY_IDX_INVALID; + IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); - ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, - test_bit(IWL_MVM_STATUS_IN_HW_RESTART, - &mvm->status)); + ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset); if (ret) { IWL_WARN(mvm, "set key failed\n"); /* diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 300a249..4e26008 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1227,7 +1227,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvm_sta, struct ieee80211_key_conf *keyconf, bool mcast, - u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags) + u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, + u8 key_offset) { struct iwl_mvm_add_sta_key_cmd cmd = {}; __le16 key_flags; @@ -1269,7 +1270,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, if (mcast) key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - cmd.key_offset = keyconf->hw_key_idx; + cmd.key_offset = key_offset; cmd.key_flags = key_flags; cmd.sta_id = sta_id; @@ -1360,6 +1361,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *keyconf, + u8 key_offset, bool mcast) { struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -1375,17 +1377,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, - seq.tkip.iv32, p1k, 0); + seq.tkip.iv32, p1k, 0, key_offset); break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, - 0, NULL, 0); + 0, NULL, 0, key_offset); break; default: ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, - 0, NULL, 0); + 0, NULL, 0, key_offset); } return ret; @@ -1433,7 +1435,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *keyconf, - bool have_key_offset) + u8 key_offset) { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); u8 sta_id; @@ -1470,18 +1472,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) return -EINVAL; - if (!have_key_offset) { - /* - * The D3 firmware hardcodes the PTK offset to 0, so we have to - * configure it there. As a result, this workaround exists to - * let the caller set the key offset (hw_key_idx), see d3.c. - */ - keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm); - if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) + /* If the key_offset is not pre-assigned, we need to find a + * new offset to use. In normal cases, the offset is not + * pre-assigned, but during HW_RESTART we want to reuse the + * same indices, so we pass them when this function is called. + * + * In D3 entry, we need to hardcoded the indices (because the + * firmware hardcodes the PTK offset to 0). In this case, we + * need to make sure we don't overwrite the hw_key_idx in the + * keyconf structure, because otherwise we cannot configure + * the original ones back when resuming. + */ + if (key_offset == STA_KEY_IDX_INVALID) { + key_offset = iwl_mvm_set_fw_key_idx(mvm); + if (key_offset == STA_KEY_IDX_INVALID) return -ENOSPC; + keyconf->hw_key_idx = key_offset; } - ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast); + ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast); if (ret) { __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); goto end; @@ -1495,7 +1504,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, */ if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { - ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast); + ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, + key_offset, !mcast); if (ret) { __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table); __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); @@ -1602,7 +1612,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, mvm_sta = iwl_mvm_sta_from_mac80211(sta); iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, - iv32, phase1key, CMD_ASYNC); + iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); rcu_read_unlock(); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index eedb215..0631cc0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - bool have_key_offset); + struct ieee80211_key_conf *keyconf, + u8 key_offset); int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, -- cgit v0.10.2 From 9513c5e18a0dc55a1fc9c890715098ba2315830b Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Mon, 19 Oct 2015 16:29:11 +0200 Subject: iwlwifi: mvm: Avoid dereferencing sta if it was already flushed Be a little bit more careful when dereferencing sta on key removal, As it might already get flushed on other thread. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 4e26008..354acbd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) return max_offs; } -static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, +static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, * station ID, then use AP's station ID. */ if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) - return mvmvif->ap_sta_id; + mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { + u8 sta_id = mvmvif->ap_sta_id; + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + /* + * It is possible that the 'sta' parameter is NULL, + * for example when a GTK is removed - the sta_id will then + * be the AP ID, and no station was passed by mac80211. + */ + if (IS_ERR_OR_NULL(sta)) + return IWL_MVM_STATION_COUNT; + + return sta_id; + } return IWL_MVM_STATION_COUNT; } @@ -1445,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(vif, sta); + sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); if (sta_id == IWL_MVM_STATION_COUNT) { IWL_ERR(mvm, "Failed to find station id\n"); return -EINVAL; @@ -1531,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); /* Get the station id from the mvm local station table */ - sta_id = iwl_mvm_get_key_sta_id(vif, sta); + sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); @@ -1557,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, return 0; } - /* - * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station table, - * for example when a GTK is removed (where the sta_id will then be - * the AP ID, and no station was passed by mac80211.) - */ - if (!sta) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (!sta) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; - } - } - - if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) - return -EINVAL; - ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast); if (ret) return ret; @@ -1594,7 +1590,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, u16 *phase1key) { struct iwl_mvm_sta *mvm_sta; - u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); + u8 sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta); bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) -- cgit v0.10.2 From 17c4fbaf1a1b3360c4b15bbd78a19aa366eb9ced Mon Sep 17 00:00:00 2001 From: sujayraaj Date: Thu, 5 Nov 2015 21:52:48 +0530 Subject: ARC: switch to arc-linux- CROSS_COMPILE prefix across all configs When building kernel with buildroot built toolchain, CROSS_COMPILE currently needs adjustment even if minor. This is because the defconfigs prefer "arc-linux-uclibc-" prefix from hand built (non buildroot) toolchain while buildroot provides "arc-buildroot-linux-uclibc-" To avoid this use the common "arc-linux-" prefix which is provided by buildroot and has also been in hand built tools for quite some time. Signed-off-by: sujayraaj Signed-off-by: Vineet Gupta [vgupta: updated changelog] diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index c92c0ef..f1ac981 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index cfac24e..323486d 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index 9922a11..66191cd 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig index f761a7c..f68838e 100644 --- a/arch/arc/configs/nsim_hs_defconfig +++ b/arch/arc/configs/nsim_hs_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig index dc6f74f..96bd1c2 100644 --- a/arch/arc/configs/nsim_hs_smp_defconfig +++ b/arch/arc/configs/nsim_hs_smp_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig index 3fef0a2..fcae666 100644 --- a/arch/arc/configs/nsimosci_hs_defconfig +++ b/arch/arc/configs/nsimosci_hs_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index 5178483..b01b659 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y diff --git a/arch/arc/configs/vdk_hs38_defconfig b/arch/arc/configs/vdk_hs38_defconfig index ef35ef3..a07f20d 100644 --- a/arch/arc/configs/vdk_hs38_defconfig +++ b/arch/arc/configs/vdk_hs38_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig index 634509e..f36c047 100644 --- a/arch/arc/configs/vdk_hs38_smp_defconfig +++ b/arch/arc/configs/vdk_hs38_smp_defconfig @@ -1,4 +1,4 @@ -CONFIG_CROSS_COMPILE="arc-linux-uclibc-" +CONFIG_CROSS_COMPILE="arc-linux-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_DEFAULT_HOSTNAME="ARCLinux" # CONFIG_CROSS_MEMORY_ATTACH is not set -- cgit v0.10.2 From 61a163481845ec917914d33bdd60b531dacfcf07 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 2 Sep 2015 17:57:58 +0530 Subject: ARC: comments update Signed-off-by: Vineet Gupta diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 0ee7398..daf2bf5 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -619,10 +619,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned, int dirty = !test_and_set_bit(PG_dc_clean, &page->flags); if (dirty) { - /* wback + inv dcache lines */ + /* wback + inv dcache lines (K-mapping) */ __flush_dcache_page(paddr, paddr); - /* invalidate any existing icache lines */ + /* invalidate any existing icache lines (U-mapping) */ if (vma->vm_flags & VM_EXEC) __inv_icache_page(paddr, vaddr); } -- cgit v0.10.2 From 98d362becb6621bebdda7ed0eac7ad7ec6c37898 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 15 Nov 2015 22:37:44 +0100 Subject: ALSA: usb-audio: add packet size quirk for the Medeli DD305 Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 7661616..68e9f9a 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1341,6 +1341,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, * Various chips declare a packet size larger than 4 bytes, but * do not actually work with larger packets: */ + case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */ case USB_ID(0x0a92, 0x1020): /* ESI M4U */ case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */ case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ -- cgit v0.10.2 From 1ca8b201309d842642f221db7f02f71c0af5be2d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 15 Nov 2015 22:38:29 +0100 Subject: ALSA: usb-audio: prevent CH345 multiport output SysEx corruption The CH345 USB MIDI chip has two output ports. However, they are multiplexed through one pin, and the number of ports cannot be reduced even for hardware that implements only one connector, so for those devices, data sent to either port ends up on the same hardware output. This becomes a problem when both ports are used at the same time, as longer MIDI commands (such as SysEx messages) are likely to be interrupted by messages from the other port, and thus to get lost. It would not be possible for the driver to detect how many ports the device actually has, except that in practice, _all_ devices built with the CH345 have only one port. So we can just ignore the device's descriptors, and hardcode one output port. Signed-off-by: Clemens Ladisch Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 68e9f9a..010094a 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2379,6 +2379,9 @@ int snd_usbmidi_create(struct snd_card *card, err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; + case QUIRK_MIDI_CH345: + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; default: dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type); diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 1a1e2e4..c60a776 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2829,6 +2829,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), .idProduct = 0x1020, }, +/* QinHeng devices */ +{ + USB_DEVICE(0x1a86, 0x752d), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "QinHeng", + .product_name = "CH345", + .ifnum = 1, + .type = QUIRK_MIDI_CH345 + } +}, + /* KeithMcMillen Stringport */ { USB_DEVICE(0x1f38, 0x0001), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 5ca80e7..7016ad8 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -538,6 +538,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk, [QUIRK_MIDI_FTDI] = create_any_midi_quirk, + [QUIRK_MIDI_CH345] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 15a1271..b665d85 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -95,6 +95,7 @@ enum quirk_type { QUIRK_MIDI_AKAI, QUIRK_MIDI_US122L, QUIRK_MIDI_FTDI, + QUIRK_MIDI_CH345, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UAXX, -- cgit v0.10.2 From a91e627e3f0ed820b11d86cdc04df38f65f33a70 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 15 Nov 2015 22:39:08 +0100 Subject: ALSA: usb-audio: work around CH345 input SysEx corruption One of the many faults of the QinHeng CH345 USB MIDI interface chip is that it does not handle received SysEx messages correctly -- every second event packet has a wrong code index number, which is the one from the last seen message, instead of 4. For example, the two messages "FE F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E F7" result in the following event packets: correct: CH345: 0F FE 00 00 0F FE 00 00 04 F0 01 02 04 F0 01 02 04 03 04 05 0F 03 04 05 04 06 07 08 04 06 07 08 04 09 0A 0B 0F 09 0A 0B 04 0C 0D 0E 04 0C 0D 0E 05 F7 00 00 05 F7 00 00 A class-compliant driver must interpret an event packet with CIN 15 as having a single data byte, so the other two bytes would be ignored. The message received by the host would then be missing two bytes out of six; in this example, "F0 01 02 03 06 07 08 09 0C 0D 0E F7". These corrupted SysEx event packages contain only data bytes, while the CH345 uses event packets with a correct CIN value only for messages with a status byte, so it is possible to distinguish between these two cases by checking for the presence of this status byte. (Other bugs in the CH345's input handling, such as the corruption resulting from running status, cannot be worked around.) Signed-off-by: Clemens Ladisch Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 010094a..5b4c58c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint { u8 running_status_length; } ports[0x10]; u8 seen_f5; + bool in_sysex; + u8 last_cin; u8 error_resubmit; int current_port; }; @@ -468,6 +470,39 @@ static void snd_usbmidi_maudio_broken_running_status_input( } /* + * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4 + * but the previously seen CIN, but still with three data bytes. + */ +static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + unsigned int i, cin, length; + + for (i = 0; i + 3 < buffer_length; i += 4) { + if (buffer[i] == 0 && i > 0) + break; + cin = buffer[i] & 0x0f; + if (ep->in_sysex && + cin == ep->last_cin && + (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0) + cin = 0x4; +#if 0 + if (buffer[i + 1] == 0x90) { + /* + * Either a corrupted running status or a real note-on + * message; impossible to detect reliably. + */ + } +#endif + length = snd_usbmidi_cin_length[cin]; + snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length); + ep->in_sysex = cin == 0x4; + if (!ep->in_sysex) + ep->last_cin = cin; + } +} + +/* * CME protocol: like the standard protocol, but SysEx commands are sent as a * single USB packet preceded by a 0x0F byte. */ @@ -660,6 +695,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = { .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { + .input = ch345_broken_sysex_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * AKAI MPD16 protocol: * @@ -2380,6 +2421,7 @@ int snd_usbmidi_create(struct snd_card *card, err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_CH345: + umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: -- cgit v0.10.2 From 512b5b89b9ef90e7a6475513fa9402e55b0e831c Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 16 Nov 2015 13:52:07 +0530 Subject: ARC: Abstract out ISA specific SLEEP args No semantical changes, prepares for ARCv2 specific change in next commit Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index ad481c2..f7c8d3c 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -37,6 +37,8 @@ #define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \ (ARCV2_IRQ_DEF_PRIO << 1)) +#define ISA_SLEEP_ARG 0x10 + #ifndef __ASSEMBLY__ /* diff --git a/arch/arc/include/asm/irqflags-compact.h b/arch/arc/include/asm/irqflags-compact.h index d8c6081..c1d3645 100644 --- a/arch/arc/include/asm/irqflags-compact.h +++ b/arch/arc/include/asm/irqflags-compact.h @@ -43,6 +43,8 @@ #define ISA_INIT_STATUS_BITS STATUS_IE_MASK +#define ISA_SLEEP_ARG 0x3 + #ifndef __ASSEMBLY__ /****************************************************************** diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 91d5a0f..a3f750e 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -44,11 +44,10 @@ SYSCALL_DEFINE0(arc_gettls) void arch_cpu_idle(void) { /* sleep, but enable all interrupts before committing */ - if (is_isa_arcompact()) { - __asm__("sleep 0x3"); - } else { - __asm__("sleep 0x10"); - } + __asm__ __volatile__( + "sleep %0 \n" + : + :"I"(ISA_SLEEP_ARG)); /* can't be "r" has to be embedded const */ } asmlinkage void ret_from_fork(void); -- cgit v0.10.2 From b8628f3fe41c999b003c541c078312fcead960d6 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 17 Jun 2015 17:03:18 +0530 Subject: ARCv2: Use the default irq priority for idle sleep Although kernel doesn't support the multiple IRQ priority levels provided by HS38x core intc yet, ensure that the default prio value is used anyways by relevant code. SLEEP insn needs to be provided the IRQ priority level which can interrupt it. This needs to be the default level which maynot necessarily be 0 as assumed by current code. This change allows a kernel with ARCV2_IRQ_DEF_PRIO = 1 to boot fine. Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index f7c8d3c..258b0e5 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -37,7 +37,8 @@ #define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \ (ARCV2_IRQ_DEF_PRIO << 1)) -#define ISA_SLEEP_ARG 0x10 +/* SLEEP needs default irq priority (<=) which can interrupt the doze */ +#define ISA_SLEEP_ARG (0x10 | ARCV2_IRQ_DEF_PRIO) #ifndef __ASSEMBLY__ -- cgit v0.10.2 From 7336dcefac4d8f94fa205a668138a6462841acc4 Mon Sep 17 00:00:00 2001 From: John Lin Date: Mon, 16 Nov 2015 14:41:07 +0800 Subject: ASoC: rl6231: fix range of DMIC clock The maximum DMIC clock rate is 3.072 MHz for most DMIC. And it will get better performance in higher clock rate. If we set maximum to 3 MHz in driver, we will get a clock rate which is not even close to 3 MHz. For example, if DMIC clock source is 24.576 MHz, the DMIC clock will be about 1.5 MHz in current code. But it will be 3.072 MHz with this patch. Signed-off-by: John Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 18b4292..1dc68ab 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -82,8 +82,8 @@ int rl6231_calc_dmic_clk(int rate) for (i = 0; i < ARRAY_SIZE(div); i++) { if ((div[i] % 3) == 0) continue; - /* find divider that gives DMIC frequency below 3MHz */ - if (3000000 * div[i] >= rate) + /* find divider that gives DMIC frequency below 3.072MHz */ + if (3072000 * div[i] >= rate) return i; } -- cgit v0.10.2 From 91ed37e45c485533997e8a7c1efd2ca39b441b60 Mon Sep 17 00:00:00 2001 From: John Lin Date: Mon, 16 Nov 2015 13:55:35 +0800 Subject: ASoC: rt5645: Increase the delay time to imporve the HP pop noise Unmuting headphone has pop noise in particular hardware design. So we extend the delay time in headphone unmuting sequence to avoid pop. Signed-off-by: John Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 672fafd..fa8b5df 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1519,7 +1519,7 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); - msleep(40); + msleep(70); rt5645->hp_on = true; } else { /* depop parameters */ -- cgit v0.10.2 From cb8affb55c7e64816f3effcd9b2fc3268c016fac Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 15 Nov 2015 17:14:41 +0100 Subject: crypto: nx - Fix timing leak in GCM and CCM decryption Using non-constant time memcmp() makes the verification of the authentication tag in the decrypt path vulnerable to timing attacks. Fix this by using crypto_memneq() instead. Cc: stable@vger.kernel.org Signed-off-by: David Gstir Signed-off-by: Herbert Xu diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 73ef499..7038f36 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -409,7 +409,7 @@ static int ccm_nx_decrypt(struct aead_request *req, processed += to_process; } while (processed < nbytes); - rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, + rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag, authsize) ? -EBADMSG : 0; out: spin_unlock_irqrestore(&nx_ctx->lock, irq_flags); diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index eee624f..abd465f 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -418,7 +419,7 @@ mac: itag, req->src, req->assoclen + nbytes, crypto_aead_authsize(crypto_aead_reqtfm(req)), SCATTERWALK_FROM_SG); - rc = memcmp(itag, otag, + rc = crypto_memneq(itag, otag, crypto_aead_authsize(crypto_aead_reqtfm(req))) ? -EBADMSG : 0; } -- cgit v0.10.2 From 79960943fdc114fd4583c9ab164b5c89da7aa601 Mon Sep 17 00:00:00 2001 From: David Gstir Date: Sun, 15 Nov 2015 17:14:42 +0100 Subject: crypto: talitos - Fix timing leak in ESP ICV verification Using non-constant time memcmp() makes the verification of the authentication tag in the decrypt path vulnerable to timing attacks. Fix this by using crypto_memneq() instead. Cc: stable@vger.kernel.org Signed-off-by: David Gstir Signed-off-by: Herbert Xu diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 46f531e..b6f9f42 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -977,7 +977,7 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, } else oicv = (char *)&edesc->link_tbl[0]; - err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0; + err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0; } kfree(edesc); -- cgit v0.10.2 From 0e18d457b31e98e68f6918e41c85ad3b736c4789 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Nov 2015 18:15:56 +0100 Subject: ASoC: fix rockchip 64-bit build warning The rk_spdif_probe uses the device match data as a token to identify a particular device, but accidentally casts a pointer to 'int', which is not portable, as gcc points out in this warning on arm64: rockchip_spdif.c: In function 'rk_spdif_probe': rockchip_spdif.c:283:6: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] This changes the logic to compare two pointer values instead, using the same cast that was used for initializing the value in the first place. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index a38a302..ac72ff5 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -280,7 +280,7 @@ static int rk_spdif_probe(struct platform_device *pdev) int ret; match = of_match_node(rk_spdif_match, np); - if ((int) match->data == RK_SPDIF_RK3288) { + if (match->data == (void *)RK_SPDIF_RK3288) { struct regmap *grf; grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); -- cgit v0.10.2 From 172c238612ebf81cabccc86b788c9209af591f61 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 6 Nov 2015 10:53:01 -0500 Subject: dm thin: restore requested 'error_if_no_space' setting on OODS to WRITE transition A thin-pool that is in out-of-data-space (OODS) mode may transition back to write mode -- without the admin adding more space to the thin-pool -- if/when blocks are released (either by deleting thin devices or discarding provisioned blocks). But as part of the thin-pool's earlier transition to out-of-data-space mode the thin-pool may have set the 'error_if_no_space' flag to true if the no_space_timeout expires without more space having been made available. That implementation detail, of changing the pool's error_if_no_space setting, needs to be reset back to the default that the user specified when the thin-pool's table was loaded. Otherwise we'll drop the user requested behaviour on the floor when this out-of-data-space to write mode transition occurs. Reported-by: Vivek Goyal Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Fixes: 2c43fd26e4 ("dm thin: fix missing out-of-data-space to write mode transition if blocks are released") Cc: stable@vger.kernel.org diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 3897b90..9f0b94f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2432,6 +2432,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) case PM_WRITE: if (old_mode != new_mode) notify_of_pool_mode_change(pool, "write"); + pool->pf.error_if_no_space = pt->requested_pf.error_if_no_space; dm_pool_metadata_read_write(pool->pmd); pool->process_bio = process_bio; pool->process_discard = process_discard_bio; -- cgit v0.10.2 From f14882945d797d81d1f39207ae8e103eaf61b857 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 3 Nov 2015 16:59:24 +0100 Subject: ARM: at91/defconfig: remove CONFIG_SSB from Atmel defconfigs This "Sonics Silicon Backplane" support is not needed on Atmel SoCs: remove it. Signed-off-by: Nicolas Ferre diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 1b1e5ac..e4b1be6 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -125,7 +125,6 @@ CONFIG_POWER_RESET=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y -CONFIG_SSB=m CONFIG_MFD_ATMEL_HLCDC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index a0c57ac..63f7e6c 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -129,7 +129,6 @@ CONFIG_GPIO_SYSFS=y CONFIG_POWER_SUPPLY=y CONFIG_POWER_RESET=y # CONFIG_HWMON is not set -CONFIG_SSB=m CONFIG_MFD_ATMEL_FLEXCOM=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -- cgit v0.10.2 From f67d84690d8c291bc08c4635e17df9a200d2c4d1 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 5 Nov 2015 15:40:48 +0800 Subject: ARM: at91/dt: sama5d4: change watchdog compatible Change the watchdog compatible to "atmel,sama5d4-wdt" to support SAMA5D4 watchdog driver. Signed-off-by: Wenyou Yang Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 15bbaf6..2193637 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1300,7 +1300,7 @@ }; watchdog@fc068640 { - compatible = "atmel,at91sam9260-wdt"; + compatible = "atmel,sama5d4-wdt"; reg = <0xfc068640 0x10>; clocks = <&clk32k>; status = "disabled"; -- cgit v0.10.2 From 67ae8b9b7898b4587922a973f4735e64b7271314 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 21 Oct 2015 11:10:07 +0100 Subject: ARM: at91/dt: replace gpio-key,wakeup with wakeup-source property Though the keyboard driver for GPIO buttons(gpio-keys) will continue to check for/support the legacy "gpio-key,wakeup" boolean property to enable gpio buttons as wakeup source, "wakeup-source" is the new standard binding. This patch replaces the legacy "gpio-key,wakeup" with the unified "wakeup-source" property in order to avoid any futher copy-paste duplication. Cc: Alexandre Belloni Cc: Jean-Christophe Plagniol-Villard Signed-off-by: Sudeep Holla Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts index 4e0ad3b..0962f2f 100644 --- a/arch/arm/boot/dts/animeo_ip.dts +++ b/arch/arm/boot/dts/animeo_ip.dts @@ -155,21 +155,21 @@ label = "keyswitch_in"; gpios = <&pioB 1 GPIO_ACTIVE_HIGH>; linux,code = <28>; - gpio-key,wakeup; + wakeup-source; }; error_in { label = "error_in"; gpios = <&pioB 2 GPIO_ACTIVE_HIGH>; linux,code = <29>; - gpio-key,wakeup; + wakeup-source; }; btn { label = "btn"; gpios = <&pioC 23 GPIO_ACTIVE_HIGH>; linux,code = <31>; - gpio-key,wakeup; + wakeup-source; }; }; }; diff --git a/arch/arm/boot/dts/at91-foxg20.dts b/arch/arm/boot/dts/at91-foxg20.dts index f89598a..6bf873e 100644 --- a/arch/arm/boot/dts/at91-foxg20.dts +++ b/arch/arm/boot/dts/at91-foxg20.dts @@ -159,7 +159,7 @@ label = "Button"; gpios = <&pioC 4 GPIO_ACTIVE_LOW>; linux,code = <0x103>; - gpio-key,wakeup; + wakeup-source; }; }; }; diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts index bf18ece..8afe35f 100644 --- a/arch/arm/boot/dts/at91-kizbox.dts +++ b/arch/arm/boot/dts/at91-kizbox.dts @@ -94,14 +94,14 @@ label = "PB_RST"; gpios = <&pioB 30 GPIO_ACTIVE_HIGH>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; user { label = "PB_USER"; gpios = <&pioB 31 GPIO_ACTIVE_HIGH>; linux,code = <0x101>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts index f0b1563..50a1456 100644 --- a/arch/arm/boot/dts/at91-kizbox2.dts +++ b/arch/arm/boot/dts/at91-kizbox2.dts @@ -171,21 +171,21 @@ label = "PB_PROG"; gpios = <&pioE 27 GPIO_ACTIVE_LOW>; linux,code = <0x102>; - gpio-key,wakeup; + wakeup-source; }; reset { label = "PB_RST"; gpios = <&pioE 29 GPIO_ACTIVE_LOW>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; user { label = "PB_USER"; gpios = <&pioE 31 GPIO_ACTIVE_HIGH>; linux,code = <0x101>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts index 9f72b49..9682d10 100644 --- a/arch/arm/boot/dts/at91-kizboxmini.dts +++ b/arch/arm/boot/dts/at91-kizboxmini.dts @@ -98,14 +98,14 @@ label = "PB_PROG"; gpios = <&pioC 17 GPIO_ACTIVE_LOW>; linux,code = <0x102>; - gpio-key,wakeup; + wakeup-source; }; reset { label = "PB_RST"; gpios = <&pioC 16 GPIO_ACTIVE_LOW>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-qil_a9260.dts b/arch/arm/boot/dts/at91-qil_a9260.dts index a9aef53..4f2eebf 100644 --- a/arch/arm/boot/dts/at91-qil_a9260.dts +++ b/arch/arm/boot/dts/at91-qil_a9260.dts @@ -183,7 +183,7 @@ label = "user_pb"; gpios = <&pioB 10 GPIO_ACTIVE_LOW>; linux,code = <28>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index 8488ac5..ff888d2 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -315,7 +315,7 @@ label = "PB_USER"; gpios = <&pioE 29 GPIO_ACTIVE_LOW>; linux,code = <0x104>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 45371a1..776a877 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -235,7 +235,7 @@ label = "pb_user1"; gpios = <&pioE 8 GPIO_ACTIVE_HIGH>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 6d272c0..b60ce3a 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -304,7 +304,7 @@ label = "pb_user1"; gpios = <&pioE 13 GPIO_ACTIVE_HIGH>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts index 2e92ac0..facce0e 100644 --- a/arch/arm/boot/dts/at91sam9261ek.dts +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -149,7 +149,7 @@ ti,debounce-tol = /bits/ 16 <65535>; ti,debounce-max = /bits/ 16 <1>; - linux,wakeup; + wakeup-source; }; }; @@ -193,28 +193,28 @@ label = "button_0"; gpios = <&pioA 27 GPIO_ACTIVE_LOW>; linux,code = <256>; - gpio-key,wakeup; + wakeup-source; }; button_1 { label = "button_1"; gpios = <&pioA 26 GPIO_ACTIVE_LOW>; linux,code = <257>; - gpio-key,wakeup; + wakeup-source; }; button_2 { label = "button_2"; gpios = <&pioA 25 GPIO_ACTIVE_LOW>; linux,code = <258>; - gpio-key,wakeup; + wakeup-source; }; button_3 { label = "button_3"; gpios = <&pioA 24 GPIO_ACTIVE_LOW>; linux,code = <259>; - gpio-key,wakeup; + wakeup-source; }; }; }; diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts index 2338127..241de04 100644 --- a/arch/arm/boot/dts/at91sam9263ek.dts +++ b/arch/arm/boot/dts/at91sam9263ek.dts @@ -213,14 +213,14 @@ label = "left_click"; gpios = <&pioC 5 GPIO_ACTIVE_LOW>; linux,code = <272>; - gpio-key,wakeup; + wakeup-source; }; right_click { label = "right_click"; gpios = <&pioC 4 GPIO_ACTIVE_LOW>; linux,code = <273>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index 57548a2..e45c744 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -206,14 +206,14 @@ label = "Button 3"; gpios = <&pioA 30 GPIO_ACTIVE_LOW>; linux,code = <0x103>; - gpio-key,wakeup; + wakeup-source; }; btn4 { label = "Button 4"; gpios = <&pioA 31 GPIO_ACTIVE_LOW>; linux,code = <0x104>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index 9d16ef8..021a634 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -323,14 +323,14 @@ label = "left_click"; gpios = <&pioB 6 GPIO_ACTIVE_LOW>; linux,code = <272>; - gpio-key,wakeup; + wakeup-source; }; right_click { label = "right_click"; gpios = <&pioB 7 GPIO_ACTIVE_LOW>; linux,code = <273>; - gpio-key,wakeup; + wakeup-source; }; left { diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index acf3451..6bf4f71 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -219,7 +219,7 @@ label = "Enter"; gpios = <&pioB 3 GPIO_ACTIVE_LOW>; linux,code = <28>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index 558c9f2..8a847c2 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -225,14 +225,14 @@ label = "right_click"; gpios = <&pioB 0 GPIO_ACTIVE_LOW>; linux,code = <273>; - gpio-key,wakeup; + wakeup-source; }; left_click { label = "left_click"; gpios = <&pioB 1 GPIO_ACTIVE_LOW>; linux,code = <272>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/sama5d35ek.dts b/arch/arm/boot/dts/sama5d35ek.dts index d9a9aca..e812f5c 100644 --- a/arch/arm/boot/dts/sama5d35ek.dts +++ b/arch/arm/boot/dts/sama5d35ek.dts @@ -49,7 +49,7 @@ label = "pb_user1"; gpios = <&pioE 27 GPIO_ACTIVE_HIGH>; linux,code = <0x100>; - gpio-key,wakeup; + wakeup-source; }; }; }; diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi index 12edafe..9beea89 100644 --- a/arch/arm/boot/dts/usb_a9260_common.dtsi +++ b/arch/arm/boot/dts/usb_a9260_common.dtsi @@ -115,7 +115,7 @@ label = "user_pb"; gpios = <&pioB 10 GPIO_ACTIVE_LOW>; linux,code = <28>; - gpio-key,wakeup; + wakeup-source; }; }; diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts index 68c0de3..8cc6edb 100644 --- a/arch/arm/boot/dts/usb_a9263.dts +++ b/arch/arm/boot/dts/usb_a9263.dts @@ -143,7 +143,7 @@ label = "user_pb"; gpios = <&pioB 10 GPIO_ACTIVE_LOW>; linux,code = <28>; - gpio-key,wakeup; + wakeup-source; }; }; -- cgit v0.10.2 From 15f7e2537a164a9a19861b67aa4368297f8b00bb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Nov 2015 16:15:48 +0100 Subject: ARM: at91/dt: remove leftovers clock definition The clocks group properties and the clock@0 node are useless, remove them to avoid copy pasting in future device trees. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts index 8afe35f..229e989 100644 --- a/arch/arm/boot/dts/at91-kizbox.dts +++ b/arch/arm/boot/dts/at91-kizbox.dts @@ -24,15 +24,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <18432000>; - }; - main_xtal { clock-frequency = <18432000>; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index e07c2b2..28eaf41 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -59,15 +59,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 776a877..7228fc7 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -59,15 +59,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index b60ce3a..df75c5d 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -59,15 +59,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts index 8dab4b7..f90e1c2 100644 --- a/arch/arm/boot/dts/at91rm9200ek.dts +++ b/arch/arm/boot/dts/at91rm9200ek.dts @@ -21,15 +21,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <18432000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts index facce0e..55bd51f 100644 --- a/arch/arm/boot/dts/at91sam9261ek.dts +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -22,15 +22,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <18432000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts index 241de04..59df9d7 100644 --- a/arch/arm/boot/dts/at91sam9263ek.dts +++ b/arch/arm/boot/dts/at91sam9263ek.dts @@ -22,15 +22,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <16367660>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index e45c744..e9cc99b 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -19,15 +19,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <18432000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index 021a634..2400c99 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -24,15 +24,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index 6bf4f71..ca4ddf8 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -23,15 +23,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <16000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index 8a847c2..f10566f 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -22,15 +22,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - slow_xtal { clock-frequency = <32768>; }; diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi index 26112eb..b098ad8 100644 --- a/arch/arm/boot/dts/at91sam9x5cm.dtsi +++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi @@ -13,17 +13,6 @@ }; clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - }; - - clocks { slow_xtal { clock-frequency = <32768>; }; -- cgit v0.10.2 From 1392f7c905e80361f57977e4c0f37f0a5d44e597 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Nov 2015 16:15:49 +0100 Subject: ARM: at91/dt: remove bootargs Passing earlyprintk in the bootargs may crash the board as it depends on having a sane DEBUG_UART_PHYS configured which is not always the case. Also remove ignore_loglevel Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 7228fc7..131614f 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -50,7 +50,6 @@ compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5"; chosen { - bootargs = "ignore_loglevel earlyprintk"; stdout-path = "serial0:115200n8"; }; diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index df75c5d..2d4a331 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -50,7 +50,6 @@ compatible = "atmel,sama5d4ek", "atmel,sama5d4", "atmel,sama5"; chosen { - bootargs = "ignore_loglevel earlyprintk"; stdout-path = "serial0:115200n8"; }; -- cgit v0.10.2 From 13e2a6fd319b2d07ca8d26b489164154356b5e91 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 16 Oct 2015 15:04:45 +0200 Subject: ARM: at91/dt: sama5d2 Xplained: add several devices Add sdmmc and flexcom devices Signed-off-by: Ludovic Desroches Signed-off-by: Cyrille Pitchen Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 28eaf41..ad6de73 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -45,6 +45,7 @@ /dts-v1/; #include "sama5d2.dtsi" #include "sama5d2-pinfunc.h" +#include / { model = "Atmel SAMA5D2 Xplained"; @@ -82,6 +83,22 @@ status = "okay"; }; + sdmmc0: sdio-host@a0000000 { + bus-width = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + non-removable; + mmc-ddr-1_8v; + status = "okay"; + }; + + sdmmc1: sdio-host@b0000000 { + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc1_default>; + status = "okay"; /* conflict with qspi0 */ + }; + apb { spi0: spi@f8000000 { pinctrl-names = "default"; @@ -172,12 +189,49 @@ }; }; + flx0: flexcom@f8034000 { + atmel,flexcom-mode = ; + status = "disabled"; /* conflict with ISC_D2 & ISC_D3 data pins */ + + uart5: serial@200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&flx0_clk>; + clock-names = "usart"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + atmel,fifo-size = <32>; + status = "okay"; + }; + }; + uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; status = "okay"; }; + flx4: flexcom@fc018000 { + atmel,flexcom-mode = ; + status = "okay"; + + i2c2: i2c@600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0x600 0x200>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <0>, <0>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx4_clk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx4_default>; + atmel,fifo-size = <16>; + status = "okay"; + }; + }; + i2c1: i2c@fc028000 { dmas = <0>, <0>; pinctrl-names = "default"; @@ -192,6 +246,18 @@ }; pinctrl@fc038000 { + pinctrl_flx0_default: flx0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_flx4_default: flx4_default { + pinmux = , + ; + bias-disable; + }; + pinctrl_i2c0_default: i2c0_default { pinmux = , ; @@ -218,6 +284,46 @@ bias-disable; }; + pinctrl_sdmmc0_default: sdmmc0_default { + cmd_data { + pinmux = , + , + , + , + , + , + , + , + ; + bias-pull-up; + }; + + ck_cd_rstn_vddsel { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + pinctrl_sdmmc1_default: sdmmc1_default { + cmd_data { + pinmux = , + , + , + , + ; + bias-pull-up; + }; + + conf-ck_cd { + pinmux = , + ; + bias-disable; + }; + }; + pinctrl_spi0_default: spi0_default { pinmux = , , -- cgit v0.10.2 From 34c06254ff82a815fdccdfae7517a06c9b768cee Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Nov 2015 00:12:24 -0500 Subject: cgroup: fix cftype->file_offset handling 6f60eade2433 ("cgroup: generalize obtaining the handles of and notifying cgroup files") introduced cftype->file_offset so that the handles for per-css file instances can be recorded. These handles then can be used, for example, to generate file modified notifications. Unfortunately, it made the wrong assumption that files are created once for a given css and removed on its destruction. Due to the dependencies among subsystems, a css may be hidden from userland and then later shown again. This is implemented by removing and re-creating the affected files, so the associated kernfs_node for a given cgroup file may change over time. This incorrect assumption led to the corruption of css->files lists. Reimplement cftype->file_offset handling so that cgroup_file->kn is protected by a lock and updated as files are created and destroyed. This also makes keeping them on per-cgroup list unnecessary. Signed-off-by: Tejun Heo Reported-by: James Sedgwick Fixes: 6f60eade2433 ("cgroup: generalize obtaining the handles of and notifying cgroup files") Acked-by: Johannes Weiner Acked-by: Zefan Li diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 60d44b2..869fd4a 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -90,7 +90,6 @@ enum { */ struct cgroup_file { /* do not access any fields from outside cgroup core */ - struct list_head node; /* anchored at css->files */ struct kernfs_node *kn; }; @@ -134,9 +133,6 @@ struct cgroup_subsys_state { */ u64 serial_nr; - /* all cgroup_files associated with this css */ - struct list_head files; - /* percpu_ref killing and RCU release */ struct rcu_head rcu_head; struct work_struct destroy_work; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 22e3754..f640830 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -88,6 +88,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_rm_cftypes(struct cftype *cfts); +void cgroup_file_notify(struct cgroup_file *cfile); char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); @@ -516,19 +517,6 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp) pr_cont_kernfs_path(cgrp->kn); } -/** - * cgroup_file_notify - generate a file modified event for a cgroup_file - * @cfile: target cgroup_file - * - * @cfile must have been obtained by setting cftype->file_offset. - */ -static inline void cgroup_file_notify(struct cgroup_file *cfile) -{ - /* might not have been created due to one of the CFTYPE selector flags */ - if (cfile->kn) - kernfs_notify(cfile->kn); -} - #else /* !CONFIG_CGROUPS */ struct cgroup_subsys_state; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f1603c1..b316deb 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -98,6 +98,12 @@ static DEFINE_SPINLOCK(css_set_lock); static DEFINE_SPINLOCK(cgroup_idr_lock); /* + * Protects cgroup_file->kn for !self csses. It synchronizes notifications + * against file removal/re-creation across css hiding. + */ +static DEFINE_SPINLOCK(cgroup_file_kn_lock); + +/* * Protects cgroup_subsys->release_agent_path. Modifying it also requires * cgroup_mutex. Reading requires either cgroup_mutex or this spinlock. */ @@ -1393,6 +1399,16 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) char name[CGROUP_FILE_NAME_MAX]; lockdep_assert_held(&cgroup_mutex); + + if (cft->file_offset) { + struct cgroup_subsys_state *css = cgroup_css(cgrp, cft->ss); + struct cgroup_file *cfile = (void *)css + cft->file_offset; + + spin_lock_irq(&cgroup_file_kn_lock); + cfile->kn = NULL; + spin_unlock_irq(&cgroup_file_kn_lock); + } + kernfs_remove_by_name(cgrp->kn, cgroup_file_name(cgrp, cft, name)); } @@ -1856,7 +1872,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) INIT_LIST_HEAD(&cgrp->self.sibling); INIT_LIST_HEAD(&cgrp->self.children); - INIT_LIST_HEAD(&cgrp->self.files); INIT_LIST_HEAD(&cgrp->cset_links); INIT_LIST_HEAD(&cgrp->pidlists); mutex_init(&cgrp->pidlist_mutex); @@ -3313,9 +3328,9 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp, if (cft->file_offset) { struct cgroup_file *cfile = (void *)css + cft->file_offset; - kernfs_get(kn); + spin_lock_irq(&cgroup_file_kn_lock); cfile->kn = kn; - list_add(&cfile->node, &css->files); + spin_unlock_irq(&cgroup_file_kn_lock); } return 0; @@ -3553,6 +3568,22 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) } /** + * cgroup_file_notify - generate a file modified event for a cgroup_file + * @cfile: target cgroup_file + * + * @cfile must have been obtained by setting cftype->file_offset. + */ +void cgroup_file_notify(struct cgroup_file *cfile) +{ + unsigned long flags; + + spin_lock_irqsave(&cgroup_file_kn_lock, flags); + if (cfile->kn) + kernfs_notify(cfile->kn); + spin_unlock_irqrestore(&cgroup_file_kn_lock, flags); +} + +/** * cgroup_task_count - count the number of tasks in a cgroup. * @cgrp: the cgroup in question * @@ -4613,13 +4644,9 @@ static void css_free_work_fn(struct work_struct *work) container_of(work, struct cgroup_subsys_state, destroy_work); struct cgroup_subsys *ss = css->ss; struct cgroup *cgrp = css->cgroup; - struct cgroup_file *cfile; percpu_ref_exit(&css->refcnt); - list_for_each_entry(cfile, &css->files, node) - kernfs_put(cfile->kn); - if (ss) { /* css free path */ int id = css->id; @@ -4724,7 +4751,6 @@ static void init_and_link_css(struct cgroup_subsys_state *css, css->ss = ss; INIT_LIST_HEAD(&css->sibling); INIT_LIST_HEAD(&css->children); - INIT_LIST_HEAD(&css->files); css->serial_nr = css_serial_nr_next++; if (cgroup_parent(cgrp)) { -- cgit v0.10.2 From c5967b79ecabe2baca40658d9073e28b30d7f6cf Mon Sep 17 00:00:00 2001 From: "Charles_Rose@Dell.com" Date: Fri, 6 Nov 2015 14:18:56 -0600 Subject: ahci: Add Device ID for Intel Sunrise Point PCH This patch adds missing AHCI RAID SATA Device IDs for the Intel Sunrise Point PCH. Signed-off-by: Nanda Kishore Chinna Signed-off-by: Charles Rose Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ff02bb4..ee3fc84 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -350,8 +350,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */ { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */ { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ -- cgit v0.10.2 From 4d92f0099a06ef0e36c7673f7c090f1a448b2d1b Mon Sep 17 00:00:00 2001 From: Alexandra Yates Date: Mon, 16 Nov 2015 11:22:16 -0500 Subject: ahci: Order SATA device IDs for codename Lewisburg This change was to preserve the ascending order of device IDs. There was an exception with the first two Lewisburg device IDs to keep all device IDs of the same kind grouped by code name. Signed-off-by: Alexandra Yates signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ee3fc84..cdfbcc5 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -314,16 +314,6 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */ - { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ - { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ - { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ - { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ @@ -356,6 +346,16 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ + { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ + { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v0.10.2 From e9f96bc53c1b959859599cb30ce6fd4fbb4448c2 Mon Sep 17 00:00:00 2001 From: Sachin Pandhare Date: Tue, 10 Nov 2015 23:38:02 +0530 Subject: ASoC: wm8962: correct addresses for HPF_C_0/1 From datasheet: R17408 (4400h) HPF_C_1 R17409 (4401h) HPF_C_0 17048 -> 17408 (0x4400) 17049 -> 17409 (0x4401) Signed-off-by: Sachin Pandhare Acked-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 39ebd7b..a7e7978 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -365,8 +365,8 @@ static const struct reg_default wm8962_reg[] = { { 16924, 0x0059 }, /* R16924 - HDBASS_PG_1 */ { 16925, 0x999A }, /* R16925 - HDBASS_PG_0 */ - { 17048, 0x0083 }, /* R17408 - HPF_C_1 */ - { 17049, 0x98AD }, /* R17409 - HPF_C_0 */ + { 17408, 0x0083 }, /* R17408 - HPF_C_1 */ + { 17409, 0x98AD }, /* R17409 - HPF_C_0 */ { 17920, 0x007F }, /* R17920 - ADCL_RETUNE_C1_1 */ { 17921, 0xFFFF }, /* R17921 - ADCL_RETUNE_C1_0 */ -- cgit v0.10.2 From 0580bcc91d0aee7367c001955234d71b0b337b41 Mon Sep 17 00:00:00 2001 From: John Lin Date: Wed, 11 Nov 2015 15:25:28 +0800 Subject: ASoC: rt5645: Add struct dmi_system_id "Google Edgar" for Chrome OS Add platform specific data for Edgar project. Signed-off-by: John Lin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index fa8b5df..647b594 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3378,6 +3378,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Reks"), }, }, + { + .ident = "Google Edgar", + .callback = strago_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"), + }, + }, { } }; -- cgit v0.10.2 From 4454a8378be5809c2b830531bb4c4712b5e46bef Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Mon, 9 Nov 2015 12:56:00 -0800 Subject: ASoC: nau8825: add pm function This patch adds pm function and fixes following issues 1.i2c timeout after resume, after resume we saw interrupt handler is called prior to i2c controller is resumed.This causes i2c timeout 2.no audio after resume Signed-off-by: Fang, Yang A Signed-off-by: Yong Zhi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7fc7b4e..c1b87c5 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1271,6 +1271,36 @@ static int nau8825_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int nau8825_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct nau8825 *nau8825 = dev_get_drvdata(dev); + + disable_irq(client->irq); + regcache_cache_only(nau8825->regmap, true); + regcache_mark_dirty(nau8825->regmap); + + return 0; +} + +static int nau8825_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct nau8825 *nau8825 = dev_get_drvdata(dev); + + regcache_cache_only(nau8825->regmap, false); + regcache_sync(nau8825->regmap); + enable_irq(client->irq); + + return 0; +} +#endif + +static const struct dev_pm_ops nau8825_pm = { + SET_SYSTEM_SLEEP_PM_OPS(nau8825_suspend, nau8825_resume) +}; + static const struct i2c_device_id nau8825_i2c_ids[] = { { "nau8825", 0 }, { } @@ -1297,6 +1327,7 @@ static struct i2c_driver nau8825_driver = { .name = "nau8825", .of_match_table = of_match_ptr(nau8825_of_ids), .acpi_match_table = ACPI_PTR(nau8825_acpi_match), + .pm = &nau8825_pm, }, .probe = nau8825_i2c_probe, .remove = nau8825_i2c_remove, -- cgit v0.10.2 From 98c8dccf2b2771fb622d449b2ec1604fc5d260e5 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 9 Nov 2015 12:14:51 +0800 Subject: spi: mediatek: single device does not require cs_gpios When only one device is present, it is not necessary to specify cs_gpios, as the CS line can be controlled by the hardware module. Without this patch, older device tree bindings used before 37457607 "spi: mediatek: mt8173 spi multiple devices support" would cause a panic on boot. This fixes the crash, and re-introduces backward compatibility. Signed-off-by: Nicolas Boichat Acked-by: Leilk Liu Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 563954a..7840067 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -410,7 +410,7 @@ static int mtk_spi_setup(struct spi_device *spi) if (!spi->controller_data) spi->controller_data = (void *)&mtk_default_chip_info; - if (mdata->dev_comp->need_pad_sel) + if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio)) gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); return 0; @@ -632,13 +632,23 @@ static int mtk_spi_probe(struct platform_device *pdev) goto err_put_master; } - for (i = 0; i < master->num_chipselect; i++) { - ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], - dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, - "can't get CS GPIO %i\n", i); - goto err_put_master; + if (!master->cs_gpios && master->num_chipselect > 1) { + dev_err(&pdev->dev, + "cs_gpios not specified and num_chipselect > 1\n"); + ret = -EINVAL; + goto err_put_master; + } + + if (master->cs_gpios) { + for (i = 0; i < master->num_chipselect; i++) { + ret = devm_gpio_request(&pdev->dev, + master->cs_gpios[i], + dev_name(&pdev->dev)); + if (ret) { + dev_err(&pdev->dev, + "can't get CS GPIO %i\n", i); + goto err_put_master; + } } } } -- cgit v0.10.2 From 0ba2cf70d23437161199e6b627f6948b47be9db4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Nov 2015 17:44:34 +0100 Subject: spi: bcm63xx: use correct format string for printing a resource With a 64-bit resource_size_t, we get a build warning on bcm63xx_spi_probe: drivers/spi/spi-bcm63xx.c:565:16: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=] As we are printing a resource, we can just use the %pr format specifier that pretty-prints the address and avoids the warning. Signed-off-by: Arnd Bergmann Acked-by: Florian Fainelli Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 06858e0..bf9a610 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -562,8 +562,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) goto out_clk_disable; } - dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n", - r->start, irq, bs->fifo_size); + dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n", + r, irq, bs->fifo_size); return 0; -- cgit v0.10.2 From 285249884ec19480f99c011d223760bb1fc865a2 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 16 Nov 2015 17:10:05 +0900 Subject: thermal: of-thermal: Reduce log level for message when can't fine thermal zone Some systems register thermal zone by themself and don't need to have thermal zones node in DT. Therefore reduce the log level from ERROR to DEBUG when thermal zone node can't be find in of_thermal_destroy_zones(). Signed-off-by: Jiada Wang Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 42b7d42..be4eedc 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -964,7 +964,7 @@ void of_thermal_destroy_zones(void) np = of_find_node_by_name(NULL, "thermal-zones"); if (!np) { - pr_err("unable to find thermal zones\n"); + pr_debug("unable to find thermal zones\n"); return; } -- cgit v0.10.2 From 84f0e490bee0684bd00c8ee02b15487d58bcea9f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 10 Nov 2015 02:12:06 +0000 Subject: thermal: rcar_thermal: remove redundant operation Probe error operation and remove operation are same. Let's use same function. Signed-off-by: Kuninori Morimoto Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 5d4ae7d..13d01ed 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -361,6 +361,24 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data) /* * platform functions */ +static int rcar_thermal_remove(struct platform_device *pdev) +{ + struct rcar_thermal_common *common = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct rcar_thermal_priv *priv; + + rcar_thermal_for_each_priv(priv, common) { + if (rcar_has_irq_support(priv)) + rcar_thermal_irq_disable(priv); + thermal_zone_device_unregister(priv->zone); + } + + pm_runtime_put(dev); + pm_runtime_disable(dev); + + return 0; +} + static int rcar_thermal_probe(struct platform_device *pdev) { struct rcar_thermal_common *common; @@ -377,6 +395,8 @@ static int rcar_thermal_probe(struct platform_device *pdev) if (!common) return -ENOMEM; + platform_set_drvdata(pdev, common); + INIT_LIST_HEAD(&common->head); spin_lock_init(&common->lock); common->dev = dev; @@ -454,43 +474,16 @@ static int rcar_thermal_probe(struct platform_device *pdev) rcar_thermal_common_write(common, ENR, enr_bits); } - platform_set_drvdata(pdev, common); - dev_info(dev, "%d sensor probed\n", i); return 0; error_unregister: - rcar_thermal_for_each_priv(priv, common) { - if (rcar_has_irq_support(priv)) - rcar_thermal_irq_disable(priv); - thermal_zone_device_unregister(priv->zone); - } - - pm_runtime_put(dev); - pm_runtime_disable(dev); + rcar_thermal_remove(pdev); return ret; } -static int rcar_thermal_remove(struct platform_device *pdev) -{ - struct rcar_thermal_common *common = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - struct rcar_thermal_priv *priv; - - rcar_thermal_for_each_priv(priv, common) { - if (rcar_has_irq_support(priv)) - rcar_thermal_irq_disable(priv); - thermal_zone_device_unregister(priv->zone); - } - - pm_runtime_put(dev); - pm_runtime_disable(dev); - - return 0; -} - static const struct of_device_id rcar_thermal_dt_ids[] = { { .compatible = "renesas,rcar-thermal", }, {}, -- cgit v0.10.2 From 6419fdbb6f90e147690f8833cba59d289d613da5 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Nov 2015 17:31:26 +0530 Subject: ath10k: poll HTT send completion when CE 5 is unused commit a70587b3389a ("ath10k: configure copy engine 5 for HTT messages") moved send completion polling under HTT Rx (CE 5) service routine. For QCA6174 based devices copy engine 1 (CE 1) is used for HTT Rx instead of CE 5. So send completion never be called. This is causing "failed to transmit packet, dropping: -105" errors. Fix this by processing send completion from CE 1 service routine instead of CE 5. Fixes: a70587b3389a ("ath10k: configure copy engine 5 for HTT messages") Tested-by: Ryan Hsu Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0ad3dd1..930785a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -107,6 +107,7 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -124,7 +125,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = ath10k_pci_htc_rx_cb, + .recv_cb = ath10k_pci_htt_htc_rx_cb, }, /* CE2: target->host WMI */ @@ -1204,6 +1205,16 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state) ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); } +static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + /* CE4 polling needs to be done whenever CE pipe which transports + * HTT Rx (target->host) is processed. + */ + ath10k_ce_per_engine_service(ce_state->ar, 4); + + ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + /* Called by lower (CE) layer when a send to HTT Target completes. */ static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state) { -- cgit v0.10.2 From 4ead1a25ce436f73501d6358450f3ba0c1cb2ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:35 +0100 Subject: MAINTAINERS: Add linux-block list to LightNVM for patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/MAINTAINERS b/MAINTAINERS index e9caa4b..018865e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6371,6 +6371,7 @@ F: arch/*/include/asm/pmem.h LIGHTNVM PLATFORM SUPPORT M: Matias Bjorling W: http://github/OpenChannelSSD +L: linux-block@vger.kernel.org S: Maintained F: drivers/lightnvm/ F: include/linux/lightnvm.h -- cgit v0.10.2 From aedf17f4515b12ba1cd73298e66baa69cf93010e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:36 +0100 Subject: lightnvm: change max_phys_sect to uint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The max_phys_sect variable is defined as a char. We do a boundary check to maximally allow 256 physical page descriptors per command. As we are not indexing from zero. This expression is always false. Bump the max_phys_sect to an unsigned int to support the range check. Signed-off-by: Matias Bjørling Reported-by: Geert Uytterhoeven Signed-off-by: Jens Axboe diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 69c9057..32b5369 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -220,7 +220,7 @@ struct nvm_dev_ops { nvm_dev_dma_alloc_fn *dev_dma_alloc; nvm_dev_dma_free_fn *dev_dma_free; - uint8_t max_phys_sect; + unsigned int max_phys_sect; }; struct nvm_lun { -- cgit v0.10.2 From 11450469830f2481a9e7cb181609288d40f41323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:37 +0100 Subject: lightnvm: update bad block table format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specification was changed to reflect a multi-value bad block table. Instead of bit-based bad block table, the bad block table now allows eight bad block categories. Currently four are defined: * Factory bad blocks * Grown bad blocks * Device-side reserved blocks * Host-side reserved blocks The factory and grown bad blocks are the regular bad blocks. The reserved blocks are either for internal use or external use. In particular, the device-side reserved blocks allows the host to bootstrap from a limited number of flash blocks. Reducing the flash blocks to scan upon super block initialization. Support for both get bad block table and set bad block table is added. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index ae1fb2b..8cfc011 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -64,19 +64,22 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn) return 0; } -static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks, +static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks, void *private) { struct gen_nvm *gn = private; - struct gen_lun *lun = &gn->luns[lun_id]; + struct nvm_dev *dev = gn->dev; + struct gen_lun *lun; struct nvm_block *blk; int i; - if (unlikely(bitmap_empty(bb_bitmap, nr_blocks))) - return 0; + ppa = addr_to_generic_mode(gn->dev, ppa); + lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun]; + + for (i = 0; i < nr_blocks; i++) { + if (blks[i] == 0) + continue; - i = -1; - while ((i = find_next_bit(bb_bitmap, nr_blocks, i + 1)) < nr_blocks) { blk = &lun->vlun.blocks[i]; if (!blk) { pr_err("gennvm: BB data is out of bounds.\n"); @@ -171,8 +174,16 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) } if (dev->ops->get_bb_tbl) { - ret = dev->ops->get_bb_tbl(dev->q, lun->vlun.id, - dev->blks_per_lun, gennvm_block_bb, gn); + struct ppa_addr ppa; + + ppa.ppa = 0; + ppa.g.ch = lun->vlun.chnl_id; + ppa.g.lun = lun->vlun.id; + ppa = generic_to_addr_mode(dev, ppa); + + ret = dev->ops->get_bb_tbl(dev->q, ppa, + dev->blks_per_lun, + gennvm_block_bb, gn); if (ret) pr_err("gennvm: could not read BB table\n"); } @@ -199,6 +210,7 @@ static int gennvm_register(struct nvm_dev *dev) if (!gn) return -ENOMEM; + gn->dev = dev; gn->nr_luns = dev->nr_luns; dev->mp = gn; @@ -354,10 +366,10 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd) { int i; - if (!dev->ops->set_bb) + if (!dev->ops->set_bb_tbl) return; - if (dev->ops->set_bb(dev->q, rqd, 1)) + if (dev->ops->set_bb_tbl(dev->q, rqd, 1)) return; gennvm_addr_to_generic_mode(dev, rqd); diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h index d23bd35..9c24b5b 100644 --- a/drivers/lightnvm/gennvm.h +++ b/drivers/lightnvm/gennvm.h @@ -35,6 +35,8 @@ struct gen_lun { }; struct gen_nvm { + struct nvm_dev *dev; + int nr_luns; struct gen_lun *luns; }; diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index e0b7b95..2c35465 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -93,7 +93,7 @@ struct nvme_nvm_l2ptbl { __le16 cdw14[6]; }; -struct nvme_nvm_bbtbl { +struct nvme_nvm_getbbtbl { __u8 opcode; __u8 flags; __u16 command_id; @@ -101,10 +101,23 @@ struct nvme_nvm_bbtbl { __u64 rsvd[2]; __le64 prp1; __le64 prp2; - __le32 prp1_len; - __le32 prp2_len; - __le32 lbb; - __u32 rsvd11[3]; + __le64 spba; + __u32 rsvd4[4]; +}; + +struct nvme_nvm_setbbtbl { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __le64 rsvd[2]; + __le64 prp1; + __le64 prp2; + __le64 spba; + __le16 nlb; + __u8 value; + __u8 rsvd3; + __u32 rsvd4[3]; }; struct nvme_nvm_erase_blk { @@ -129,8 +142,8 @@ struct nvme_nvm_command { struct nvme_nvm_hb_rw hb_rw; struct nvme_nvm_ph_rw ph_rw; struct nvme_nvm_l2ptbl l2p; - struct nvme_nvm_bbtbl get_bb; - struct nvme_nvm_bbtbl set_bb; + struct nvme_nvm_getbbtbl get_bb; + struct nvme_nvm_setbbtbl set_bb; struct nvme_nvm_erase_blk erase; }; }; @@ -187,6 +200,20 @@ struct nvme_nvm_id { struct nvme_nvm_id_group groups[4]; } __packed; +struct nvme_nvm_bb_tbl { + __u8 tblid[4]; + __le16 verid; + __le16 revid; + __le32 rvsd1; + __le32 tblks; + __le32 tfact; + __le32 tgrown; + __le32 tdresv; + __le32 thresv; + __le32 rsvd2[8]; + __u8 blk[0]; +}; + /* * Check we didn't inadvertently grow the command struct */ @@ -195,12 +222,14 @@ static inline void _nvme_nvm_check_size(void) BUILD_BUG_ON(sizeof(struct nvme_nvm_identity) != 64); BUILD_BUG_ON(sizeof(struct nvme_nvm_hb_rw) != 64); BUILD_BUG_ON(sizeof(struct nvme_nvm_ph_rw) != 64); - BUILD_BUG_ON(sizeof(struct nvme_nvm_bbtbl) != 64); + BUILD_BUG_ON(sizeof(struct nvme_nvm_getbbtbl) != 64); + BUILD_BUG_ON(sizeof(struct nvme_nvm_setbbtbl) != 64); BUILD_BUG_ON(sizeof(struct nvme_nvm_l2ptbl) != 64); BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64); BUILD_BUG_ON(sizeof(struct nvme_nvm_id_group) != 960); BUILD_BUG_ON(sizeof(struct nvme_nvm_addr_format) != 128); BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != 4096); + BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 512); } static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id) @@ -322,43 +351,80 @@ out: return ret; } -static int nvme_nvm_get_bb_tbl(struct request_queue *q, int lunid, - unsigned int nr_blocks, - nvm_bb_update_fn *update_bbtbl, void *priv) +static int nvme_nvm_get_bb_tbl(struct request_queue *q, struct ppa_addr ppa, + int nr_blocks, nvm_bb_update_fn *update_bbtbl, + void *priv) { struct nvme_ns *ns = q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_command c = {}; - void *bb_bitmap; - u16 bb_bitmap_size; + struct nvme_nvm_bb_tbl *bb_tbl; + int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks; int ret = 0; c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl; c.get_bb.nsid = cpu_to_le32(ns->ns_id); - c.get_bb.lbb = cpu_to_le32(lunid); - bb_bitmap_size = ((nr_blocks >> 15) + 1) * PAGE_SIZE; - bb_bitmap = kmalloc(bb_bitmap_size, GFP_KERNEL); - if (!bb_bitmap) - return -ENOMEM; + c.get_bb.spba = cpu_to_le64(ppa.ppa); - bitmap_zero(bb_bitmap, nr_blocks); + bb_tbl = kzalloc(tblsz, GFP_KERNEL); + if (!bb_tbl) + return -ENOMEM; - ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_bitmap, - bb_bitmap_size); + ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_tbl, tblsz); if (ret) { dev_err(dev->dev, "get bad block table failed (%d)\n", ret); ret = -EIO; goto out; } - ret = update_bbtbl(lunid, bb_bitmap, nr_blocks, priv); + if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' || + bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') { + dev_err(dev->dev, "bbt format mismatch\n"); + ret = -EINVAL; + goto out; + } + + if (le16_to_cpu(bb_tbl->verid) != 1) { + ret = -EINVAL; + dev_err(dev->dev, "bbt version not supported\n"); + goto out; + } + + if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) { + ret = -EINVAL; + dev_err(dev->dev, "bbt unsuspected blocks returned (%u!=%u)", + le32_to_cpu(bb_tbl->tblks), nr_blocks); + goto out; + } + + ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv); if (ret) { ret = -EINTR; goto out; } out: - kfree(bb_bitmap); + kfree(bb_tbl); + return ret; +} + +static int nvme_nvm_set_bb_tbl(struct request_queue *q, struct nvm_rq *rqd, + int type) +{ + struct nvme_ns *ns = q->queuedata; + struct nvme_dev *dev = ns->dev; + struct nvme_nvm_command c = {}; + int ret = 0; + + c.set_bb.opcode = nvme_nvm_admin_set_bb_tbl; + c.set_bb.nsid = cpu_to_le32(ns->ns_id); + c.set_bb.spba = cpu_to_le64(rqd->ppa_addr.ppa); + c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1); + c.set_bb.value = type; + + ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0); + if (ret) + dev_err(dev->dev, "set bad block table failed (%d)\n", ret); return ret; } @@ -474,6 +540,7 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = { .get_l2p_tbl = nvme_nvm_get_l2p_tbl, .get_bb_tbl = nvme_nvm_get_bb_tbl, + .set_bb_tbl = nvme_nvm_set_bb_tbl, .submit_io = nvme_nvm_submit_io, .erase_block = nvme_nvm_erase_block, diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 32b5369..9b3dc1b 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -191,11 +191,11 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata) struct nvm_block; typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *); -typedef int (nvm_bb_update_fn)(u32, void *, unsigned int, void *); +typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *); typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *); typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32, nvm_l2p_update_fn *, void *); -typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, int, unsigned int, +typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, struct ppa_addr, int, nvm_bb_update_fn *, void *); typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int); typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *); @@ -210,7 +210,7 @@ struct nvm_dev_ops { nvm_id_fn *identity; nvm_get_l2p_tbl_fn *get_l2p_tbl; nvm_op_bb_tbl_fn *get_bb_tbl; - nvm_op_set_bb_fn *set_bb; + nvm_op_set_bb_fn *set_bb_tbl; nvm_submit_io_fn *submit_io; nvm_erase_blk_fn *erase_block; -- cgit v0.10.2 From 36d5dbc694e0d1b1909506666d7c27b53f7f9674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:38 +0100 Subject: lightnvm: update alignments for identify command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single 8 bit and 16 bit reserve field were inserted in the specification to align fields appropriately. Reflect this in the identify group structure. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 2c35465..60687ed 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -155,11 +155,13 @@ struct nvme_nvm_id_group { __u8 num_ch; __u8 num_lun; __u8 num_pln; + __u8 rsvd1; __le16 num_blk; __le16 num_pg; __le16 fpg_sz; __le16 csecs; __le16 sos; + __le16 rsvd2; __le32 trdt; __le32 trdm; __le32 tprt; @@ -168,7 +170,7 @@ struct nvme_nvm_id_group { __le32 tbem; __le32 mpos; __le16 cpar; - __u8 reserved[913]; + __u8 reserved[910]; } __packed; struct nvme_nvm_addr_format { -- cgit v0.10.2 From 12be5edf68e785dd5dc8665db5a88152b49c1fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:39 +0100 Subject: lightnvm: expose mccap in identify command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mccap field is required for I/O command option support. It defines the following flash access modes: * SLC mode * Erase/Program Suspension * Scramble On/Off * Encryption It is slotted in between mpos and cpar, changing the offset for cpar as well. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 60687ed..52b311c 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -169,8 +169,9 @@ struct nvme_nvm_id_group { __le32 tbet; __le32 tbem; __le32 mpos; + __le32 mccap; __le16 cpar; - __u8 reserved[910]; + __u8 reserved[906]; } __packed; struct nvme_nvm_addr_format { @@ -265,6 +266,7 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id) dst->tbet = le32_to_cpu(src->tbet); dst->tbem = le32_to_cpu(src->tbem); dst->mpos = le32_to_cpu(src->mpos); + dst->mccap = le32_to_cpu(src->mccap); dst->cpar = le16_to_cpu(src->cpar); } diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 9b3dc1b..2572856 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -74,6 +74,7 @@ struct nvm_id_group { u32 tbet; u32 tbem; u32 mpos; + u32 mccap; u16 cpar; u8 res[913]; } __packed; -- cgit v0.10.2 From 73387e7bed260c89628fc6a4e3632b45be9776b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:40 +0100 Subject: lightnvm: remove unused attrs in nvm_id structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nvm_id, nvm_id_group and nvm_addr_format data structures contain reserved attributes. They are unused by media managers and targets. Remove them. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 2572856..e6ef8aa 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -58,7 +58,6 @@ enum { struct nvm_id_group { u8 mtype; u8 fmtype; - u16 res16; u8 num_ch; u8 num_lun; u8 num_pln; @@ -76,8 +75,7 @@ struct nvm_id_group { u32 mpos; u32 mccap; u16 cpar; - u8 res[913]; -} __packed; +}; struct nvm_addr_format { u8 ch_offset; @@ -92,19 +90,16 @@ struct nvm_addr_format { u8 pg_len; u8 sect_offset; u8 sect_len; - u8 res[4]; }; struct nvm_id { u8 ver_id; u8 vmnt; u8 cgrps; - u8 res[5]; u32 cap; u32 dom; struct nvm_addr_format ppaf; u8 ppat; - u8 resv[224]; struct nvm_id_group groups[4]; } __packed; -- cgit v0.10.2 From 4264c980e3e9bb904b7f41dc9c64786cc5466bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:41 +0100 Subject: lightnvm: check for NAND flash and its type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only NAND flash with SLC and MLC is supported. Make sure to not try to initialize TLC memory or other non-volatile memory types. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index f659e60..0985a03 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -185,6 +185,16 @@ static int nvm_core_init(struct nvm_dev *dev) dev->plane_mode = NVM_PLANE_SINGLE; dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; + if (grp->mtype != 0) { + pr_err("nvm: memory type not supported\n"); + return -EINVAL; + } + + if (grp->fmtype != 0 && grp->fmtype != 1) { + pr_err("nvm: flash type not supported\n"); + return -EINVAL; + } + if (grp->mpos & 0x020202) dev->plane_mode = NVM_PLANE_DOUBLE; if (grp->mpos & 0x040404) -- cgit v0.10.2 From edad2e6606ee62dd7dfc5b001fae39c5c8015a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:42 +0100 Subject: lightnvm: prematurely activate nvm_dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We register with nvm_devices when there registration can still fail. Move the final registration at the end of the nvm_register function to make sure we are fully registered when added to the nvm_devices list. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 0985a03..40e6cfa 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -318,10 +318,6 @@ int nvm_register(struct request_queue *q, char *disk_name, if (ret) goto err_init; - down_write(&nvm_lock); - list_add(&dev->devices, &nvm_devices); - up_write(&nvm_lock); - if (dev->ops->max_phys_sect > 1) { dev->ppalist_pool = dev->ops->create_dma_pool(dev->q, "ppalist"); @@ -334,6 +330,10 @@ int nvm_register(struct request_queue *q, char *disk_name, return -EINVAL; } + down_write(&nvm_lock); + list_add(&dev->devices, &nvm_devices); + up_write(&nvm_lock); + return 0; err_init: kfree(dev); -- cgit v0.10.2 From c1480ad5943261e01a62eaa7132eab76f9c490e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:43 +0100 Subject: lightnvm: prevent double free on init error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the nvm_register and nvm_init does a kfree(dev) on error. Make sure to only free it once. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 40e6cfa..899f6b9 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -160,11 +160,6 @@ int nvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk) } EXPORT_SYMBOL(nvm_erase_blk); -static void nvm_core_free(struct nvm_dev *dev) -{ - kfree(dev); -} - static int nvm_core_init(struct nvm_dev *dev) { struct nvm_id *id = &dev->identity; @@ -223,8 +218,6 @@ static void nvm_free(struct nvm_dev *dev) if (dev->mt) dev->mt->unregister_mgr(dev); - - nvm_core_free(dev); } static int nvm_init(struct nvm_dev *dev) @@ -351,11 +344,12 @@ void nvm_unregister(char *disk_name) return; } - nvm_exit(dev); - down_write(&nvm_lock); list_del(&dev->devices); up_write(&nvm_lock); + + nvm_exit(dev); + kfree(dev); } EXPORT_SYMBOL(nvm_unregister); -- cgit v0.10.2 From 7386af270c72be65c7cb2ba4ad0d4e70dc373106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:44 +0100 Subject: lightnvm: remove linear and device addr modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linear and device specific address modes can be replaced with a simple offset and bit length conversion that is generic across all devices. This both simplifies the specification and removes the special case for qemu nvme, that previously relied on the linear address mapping. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 899f6b9..790b1d7 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -174,8 +174,7 @@ static int nvm_core_init(struct nvm_dev *dev) dev->sec_size = grp->csecs; dev->oob_size = grp->sos; dev->sec_per_pg = grp->fpg_sz / grp->csecs; - dev->addr_mode = id->ppat; - dev->addr_format = id->ppaf; + memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format)); dev->plane_mode = NVM_PLANE_SINGLE; dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 8cfc011..c0d0eb2 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -73,7 +73,7 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks, struct nvm_block *blk; int i; - ppa = addr_to_generic_mode(gn->dev, ppa); + ppa = dev_to_generic_addr(gn->dev, ppa); lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun]; for (i = 0; i < nr_blocks; i++) { @@ -179,7 +179,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) ppa.ppa = 0; ppa.g.ch = lun->vlun.chnl_id; ppa.g.lun = lun->vlun.id; - ppa = generic_to_addr_mode(dev, ppa); + ppa = generic_to_dev_addr(dev, ppa); ret = dev->ops->get_bb_tbl(dev->q, ppa, dev->blks_per_lun, @@ -304,10 +304,10 @@ static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd) if (rqd->nr_pages > 1) { for (i = 0; i < rqd->nr_pages; i++) - rqd->ppa_list[i] = addr_to_generic_mode(dev, + rqd->ppa_list[i] = dev_to_generic_addr(dev, rqd->ppa_list[i]); } else { - rqd->ppa_addr = addr_to_generic_mode(dev, rqd->ppa_addr); + rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr); } } @@ -317,10 +317,10 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd) if (rqd->nr_pages > 1) { for (i = 0; i < rqd->nr_pages; i++) - rqd->ppa_list[i] = generic_to_addr_mode(dev, + rqd->ppa_list[i] = generic_to_dev_addr(dev, rqd->ppa_list[i]); } else { - rqd->ppa_addr = generic_to_addr_mode(dev, rqd->ppa_addr); + rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); } } diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 7ba64c8..75e59c3 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -123,12 +123,42 @@ static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk) return blk->id * rrpc->dev->pgs_per_blk; } +static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev, + struct ppa_addr r) +{ + struct ppa_addr l; + int secs, pgs, blks, luns; + sector_t ppa = r.ppa; + + l.ppa = 0; + + div_u64_rem(ppa, dev->sec_per_pg, &secs); + l.g.sec = secs; + + sector_div(ppa, dev->sec_per_pg); + div_u64_rem(ppa, dev->sec_per_blk, &pgs); + l.g.pg = pgs; + + sector_div(ppa, dev->pgs_per_blk); + div_u64_rem(ppa, dev->blks_per_lun, &blks); + l.g.blk = blks; + + sector_div(ppa, dev->blks_per_lun); + div_u64_rem(ppa, dev->luns_per_chnl, &luns); + l.g.lun = luns; + + sector_div(ppa, dev->luns_per_chnl); + l.g.ch = ppa; + + return l; +} + static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr) { struct ppa_addr paddr; paddr.ppa = addr; - return __linear_to_generic_addr(dev, paddr); + return linear_to_generic_addr(dev, paddr); } /* requires lun->lock taken */ diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 52b311c..9069be8 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -198,8 +198,7 @@ struct nvme_nvm_id { __le32 cap; __le32 dom; struct nvme_nvm_addr_format ppaf; - __u8 ppat; - __u8 resv[223]; + __u8 resv[224]; struct nvme_nvm_id_group groups[4]; } __packed; diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index e6ef8aa..cbe288a 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -99,7 +99,6 @@ struct nvm_id { u32 cap; u32 dom; struct nvm_addr_format ppaf; - u8 ppat; struct nvm_id_group groups[4]; } __packed; @@ -119,39 +118,28 @@ struct nvm_tgt_instance { #define NVM_VERSION_MINOR 0 #define NVM_VERSION_PATCH 0 -#define NVM_SEC_BITS (8) -#define NVM_PL_BITS (6) -#define NVM_PG_BITS (16) #define NVM_BLK_BITS (16) -#define NVM_LUN_BITS (10) +#define NVM_PG_BITS (16) +#define NVM_SEC_BITS (8) +#define NVM_PL_BITS (8) +#define NVM_LUN_BITS (8) #define NVM_CH_BITS (8) struct ppa_addr { + /* Generic structure for all addresses */ union { - /* Channel-based PPA format in nand 4x2x2x2x8x10 */ - struct { - u64 ch : 4; - u64 sec : 2; /* 4 sectors per page */ - u64 pl : 2; /* 4 planes per LUN */ - u64 lun : 2; /* 4 LUNs per channel */ - u64 pg : 8; /* 256 pages per block */ - u64 blk : 10;/* 1024 blocks per plane */ - u64 resved : 36; - } chnl; - - /* Generic structure for all addresses */ struct { + u64 blk : NVM_BLK_BITS; + u64 pg : NVM_PG_BITS; u64 sec : NVM_SEC_BITS; u64 pl : NVM_PL_BITS; - u64 pg : NVM_PG_BITS; - u64 blk : NVM_BLK_BITS; u64 lun : NVM_LUN_BITS; u64 ch : NVM_CH_BITS; } g; u64 ppa; }; -} __packed; +}; struct nvm_rq { struct nvm_tgt_instance *ins; @@ -259,8 +247,7 @@ struct nvm_dev { int blks_per_lun; int sec_size; int oob_size; - int addr_mode; - struct nvm_addr_format addr_format; + struct nvm_addr_format ppaf; /* Calculated/Cached values. These do not reflect the actual usable * blocks at run-time. @@ -286,118 +273,45 @@ struct nvm_dev { char name[DISK_NAME_LEN]; }; -/* fallback conversion */ -static struct ppa_addr __generic_to_linear_addr(struct nvm_dev *dev, - struct ppa_addr r) -{ - struct ppa_addr l; - - l.ppa = r.g.sec + - r.g.pg * dev->sec_per_pg + - r.g.blk * (dev->pgs_per_blk * - dev->sec_per_pg) + - r.g.lun * (dev->blks_per_lun * - dev->pgs_per_blk * - dev->sec_per_pg) + - r.g.ch * (dev->blks_per_lun * - dev->pgs_per_blk * - dev->luns_per_chnl * - dev->sec_per_pg); - - return l; -} - -/* fallback conversion */ -static struct ppa_addr __linear_to_generic_addr(struct nvm_dev *dev, - struct ppa_addr r) -{ - struct ppa_addr l; - int secs, pgs, blks, luns; - sector_t ppa = r.ppa; - - l.ppa = 0; - - div_u64_rem(ppa, dev->sec_per_pg, &secs); - l.g.sec = secs; - - sector_div(ppa, dev->sec_per_pg); - div_u64_rem(ppa, dev->sec_per_blk, &pgs); - l.g.pg = pgs; - - sector_div(ppa, dev->pgs_per_blk); - div_u64_rem(ppa, dev->blks_per_lun, &blks); - l.g.blk = blks; - - sector_div(ppa, dev->blks_per_lun); - div_u64_rem(ppa, dev->luns_per_chnl, &luns); - l.g.lun = luns; - - sector_div(ppa, dev->luns_per_chnl); - l.g.ch = ppa; - - return l; -} - -static struct ppa_addr __generic_to_chnl_addr(struct ppa_addr r) +static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, + struct ppa_addr r) { struct ppa_addr l; - l.ppa = 0; - - l.chnl.sec = r.g.sec; - l.chnl.pl = r.g.pl; - l.chnl.pg = r.g.pg; - l.chnl.blk = r.g.blk; - l.chnl.lun = r.g.lun; - l.chnl.ch = r.g.ch; + l.ppa = ((u64)r.g.blk) << dev->ppaf.blk_offset; + l.ppa |= ((u64)r.g.pg) << dev->ppaf.pg_offset; + l.ppa |= ((u64)r.g.sec) << dev->ppaf.sect_offset; + l.ppa |= ((u64)r.g.pl) << dev->ppaf.pln_offset; + l.ppa |= ((u64)r.g.lun) << dev->ppaf.lun_offset; + l.ppa |= ((u64)r.g.ch) << dev->ppaf.ch_offset; return l; } -static struct ppa_addr __chnl_to_generic_addr(struct ppa_addr r) +static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev, + struct ppa_addr r) { struct ppa_addr l; - l.ppa = 0; - - l.g.sec = r.chnl.sec; - l.g.pl = r.chnl.pl; - l.g.pg = r.chnl.pg; - l.g.blk = r.chnl.blk; - l.g.lun = r.chnl.lun; - l.g.ch = r.chnl.ch; + /* + * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc. + */ + l.g.blk = (r.ppa >> dev->ppaf.blk_offset) & + (((1 << dev->ppaf.blk_len) - 1)); + l.g.pg |= (r.ppa >> dev->ppaf.pg_offset) & + (((1 << dev->ppaf.pg_len) - 1)); + l.g.sec |= (r.ppa >> dev->ppaf.sect_offset) & + (((1 << dev->ppaf.sect_len) - 1)); + l.g.pl |= (r.ppa >> dev->ppaf.pln_offset) & + (((1 << dev->ppaf.pln_len) - 1)); + l.g.lun |= (r.ppa >> dev->ppaf.lun_offset) & + (((1 << dev->ppaf.lun_len) - 1)); + l.g.ch |= (r.ppa >> dev->ppaf.ch_offset) & + (((1 << dev->ppaf.ch_len) - 1)); return l; } -static inline struct ppa_addr addr_to_generic_mode(struct nvm_dev *dev, - struct ppa_addr gppa) -{ - switch (dev->addr_mode) { - case NVM_ADDRMODE_LINEAR: - return __linear_to_generic_addr(dev, gppa); - case NVM_ADDRMODE_CHANNEL: - return __chnl_to_generic_addr(gppa); - default: - BUG(); - } - return gppa; -} - -static inline struct ppa_addr generic_to_addr_mode(struct nvm_dev *dev, - struct ppa_addr gppa) -{ - switch (dev->addr_mode) { - case NVM_ADDRMODE_LINEAR: - return __generic_to_linear_addr(dev, gppa); - case NVM_ADDRMODE_CHANNEL: - return __generic_to_chnl_addr(gppa); - default: - BUG(); - } - return gppa; -} - static inline int ppa_empty(struct ppa_addr ppa_addr) { return (ppa_addr.ppa == ADDR_EMPTY); -- cgit v0.10.2 From 2393bd39c77f21488ac7e5337cac1523e9ebd2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:45 +0100 Subject: nvme: missing ppaf copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ppa format was not copied from the NVMe specific ppa format to the lightnvm specific ppa format. This led to the ppa format not being communicated to the layers above. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 9069be8..fd37123 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -300,6 +300,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id) nvm_id->cgrps = nvme_nvm_id->cgrps; nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap); nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom); + memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf, + sizeof(struct nvme_nvm_addr_format)); ret = init_grps(nvm_id, nvme_nvm_id); out: -- cgit v0.10.2 From dad1b00977f9dc8120b48f9711deb4aa6462a3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Mon, 16 Nov 2015 15:34:46 +0100 Subject: nvme: remove reserved double word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specification was updated the remove the double word just after number of configuration groups and capabilities. Update the identify structure to reflect it. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index fd37123..7e82fe3 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -194,11 +194,11 @@ struct nvme_nvm_id { __u8 ver_id; __u8 vmnt; __u8 cgrps; - __u8 res[5]; + __u8 res; __le32 cap; __le32 dom; struct nvme_nvm_addr_format ppaf; - __u8 resv[224]; + __u8 resv[228]; struct nvme_nvm_id_group groups[4]; } __packed; -- cgit v0.10.2 From d09f9581b235a92abbe372531660b468fadabc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Gonz=C3=A1lez?= Date: Mon, 16 Nov 2015 15:34:47 +0100 Subject: lightnvm: cleanup queue before target removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents outstanding IOs to be sent for completion to target after the target has been removed. The flow is now: stop new IOs > cleanup queue > remove target. Signed-off-by: Javier Gonzalez Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 790b1d7..8a556f3 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -460,11 +460,11 @@ static void nvm_remove_target(struct nvm_target *t) lockdep_assert_held(&nvm_lock); del_gendisk(tdisk); + blk_cleanup_queue(q); + if (tt->exit) tt->exit(tdisk->private_data); - blk_cleanup_queue(q); - put_disk(tdisk); list_del(&t->list); -- cgit v0.10.2 From 4736346bb47966254ee6d1fc50267a2609791cba Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 16 Nov 2015 23:30:00 +0800 Subject: elevator: use list_{first,prev,next}_entry To make the intention clearer, use list_{first,prev,next}_entry instead of list_entry. Signed-off-by: Geliang Tang Signed-off-by: Jens Axboe diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 3de89d4..a163c48 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -21,10 +21,10 @@ static void noop_merged_requests(struct request_queue *q, struct request *rq, static int noop_dispatch(struct request_queue *q, int force) { struct noop_data *nd = q->elevator->elevator_data; + struct request *rq; - if (!list_empty(&nd->queue)) { - struct request *rq; - rq = list_entry(nd->queue.next, struct request, queuelist); + rq = list_first_entry_or_null(&nd->queue, struct request, queuelist); + if (rq) { list_del_init(&rq->queuelist); elv_dispatch_sort(q, rq); return 1; @@ -46,7 +46,7 @@ noop_former_request(struct request_queue *q, struct request *rq) if (rq->queuelist.prev == &nd->queue) return NULL; - return list_entry(rq->queuelist.prev, struct request, queuelist); + return list_prev_entry(rq, queuelist); } static struct request * @@ -56,7 +56,7 @@ noop_latter_request(struct request_queue *q, struct request *rq) if (rq->queuelist.next == &nd->queue) return NULL; - return list_entry(rq->queuelist.next, struct request, queuelist); + return list_next_entry(rq, queuelist); } static int noop_init_queue(struct request_queue *q, struct elevator_type *e) -- cgit v0.10.2 From b2b7e00148a203e9934bbd17aebffae3f447ade7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Thu, 12 Nov 2015 20:25:10 +0100 Subject: null_blk: register as a LightNVM device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for registering as a LightNVM device. This allows us to evaluate the performance of the LightNVM subsystem. In /drivers/Makefile, LightNVM is moved above block device drivers to make sure that the LightNVM media managers have been initialized before drivers under /drivers/block are initialized. Signed-off-by: Matias Bjørling Fix by Jens Axboe to remove unneeded slab cache and the following memory leak. Signed-off-by: Jens Axboe diff --git a/Documentation/block/null_blk.txt b/Documentation/block/null_blk.txt index 2f6c6ff..d8880ca 100644 --- a/Documentation/block/null_blk.txt +++ b/Documentation/block/null_blk.txt @@ -70,3 +70,6 @@ use_per_node_hctx=[0/1]: Default: 0 parameter. 1: The multi-queue block layer is instantiated with a hardware dispatch queue for each CPU node in the system. + +use_lightnvm=[0/1]: Default: 0 + Register device with LightNVM. Requires blk-mq to be used. diff --git a/drivers/Makefile b/drivers/Makefile index 73d0391..795d0ca 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_FB_I810) += video/fbdev/i810/ obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ obj-$(CONFIG_PARPORT) += parport/ +obj-$(CONFIG_NVM) += lightnvm/ obj-y += base/ block/ misc/ mfd/ nfc/ obj-$(CONFIG_LIBNVDIMM) += nvdimm/ obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ @@ -70,7 +71,6 @@ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ obj-$(CONFIG_SCSI) += scsi/ -obj-$(CONFIG_NVM) += lightnvm/ obj-y += nvme/ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_TARGET_CORE) += target/ diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 6255d1c..8165251 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -8,6 +8,7 @@ #include #include #include +#include struct nullb_cmd { struct list_head list; @@ -39,6 +40,7 @@ struct nullb { struct nullb_queue *queues; unsigned int nr_queues; + char disk_name[DISK_NAME_LEN]; }; static LIST_HEAD(nullb_list); @@ -119,6 +121,10 @@ static int nr_devices = 2; module_param(nr_devices, int, S_IRUGO); MODULE_PARM_DESC(nr_devices, "Number of devices to register"); +static bool use_lightnvm; +module_param(use_lightnvm, bool, S_IRUGO); +MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device"); + static int irqmode = NULL_IRQ_SOFTIRQ; static int null_set_irqmode(const char *str, const struct kernel_param *kp) @@ -427,6 +433,8 @@ static void null_del_dev(struct nullb *nullb) { list_del_init(&nullb->list); + if (use_lightnvm) + nvm_unregister(nullb->disk->disk_name); del_gendisk(nullb->disk); blk_cleanup_queue(nullb->q); if (queue_mode == NULL_Q_MQ) @@ -436,6 +444,125 @@ static void null_del_dev(struct nullb *nullb) kfree(nullb); } +#ifdef CONFIG_NVM + +static void null_lnvm_end_io(struct request *rq, int error) +{ + struct nvm_rq *rqd = rq->end_io_data; + struct nvm_dev *dev = rqd->dev; + + dev->mt->end_io(rqd, error); + + blk_put_request(rq); +} + +static int null_lnvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) +{ + struct request *rq; + struct bio *bio = rqd->bio; + + rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0); + if (IS_ERR(rq)) + return -ENOMEM; + + rq->cmd_type = REQ_TYPE_DRV_PRIV; + rq->__sector = bio->bi_iter.bi_sector; + rq->ioprio = bio_prio(bio); + + if (bio_has_data(bio)) + rq->nr_phys_segments = bio_phys_segments(q, bio); + + rq->__data_len = bio->bi_iter.bi_size; + rq->bio = rq->biotail = bio; + + rq->end_io_data = rqd; + + blk_execute_rq_nowait(q, NULL, rq, 0, null_lnvm_end_io); + + return 0; +} + +static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) +{ + sector_t size = gb * 1024 * 1024 * 1024ULL; + struct nvm_id_group *grp; + + id->ver_id = 0x1; + id->vmnt = 0; + id->cgrps = 1; + id->cap = 0x3; + id->dom = 0x1; + id->ppat = NVM_ADDRMODE_LINEAR; + + do_div(size, bs); /* convert size to pages */ + grp = &id->groups[0]; + grp->mtype = 0; + grp->fmtype = 1; + grp->num_ch = 1; + grp->num_lun = 1; + grp->num_pln = 1; + grp->num_blk = size / 256; + grp->num_pg = 256; + grp->fpg_sz = bs; + grp->csecs = bs; + grp->trdt = 25000; + grp->trdm = 25000; + grp->tprt = 500000; + grp->tprm = 500000; + grp->tbet = 1500000; + grp->tbem = 1500000; + grp->mpos = 0x010101; /* single plane rwe */ + grp->cpar = hw_queue_depth; + + return 0; +} + +static void *null_lnvm_create_dma_pool(struct request_queue *q, char *name) +{ + mempool_t *virtmem_pool; + + virtmem_pool = mempool_create_page_pool(64, 0); + if (!virtmem_pool) { + pr_err("null_blk: Unable to create virtual memory pool\n"); + return NULL; + } + + return virtmem_pool; +} + +static void null_lnvm_destroy_dma_pool(void *pool) +{ + mempool_destroy(pool); +} + +static void *null_lnvm_dev_dma_alloc(struct request_queue *q, void *pool, + gfp_t mem_flags, dma_addr_t *dma_handler) +{ + return mempool_alloc(pool, mem_flags); +} + +static void null_lnvm_dev_dma_free(void *pool, void *entry, + dma_addr_t dma_handler) +{ + mempool_free(entry, pool); +} + +static struct nvm_dev_ops null_lnvm_dev_ops = { + .identity = null_lnvm_id, + .submit_io = null_lnvm_submit_io, + + .create_dma_pool = null_lnvm_create_dma_pool, + .destroy_dma_pool = null_lnvm_destroy_dma_pool, + .dev_dma_alloc = null_lnvm_dev_dma_alloc, + .dev_dma_free = null_lnvm_dev_dma_free, + + /* Simulate nvme protocol restriction */ + .max_phys_sect = 64, +}; +#else +static struct nvm_dev_ops null_lnvm_dev_ops; +#endif /* CONFIG_NVM */ + static int null_open(struct block_device *bdev, fmode_t mode) { return 0; @@ -575,11 +702,6 @@ static int null_add_dev(void) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q); queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q); - disk = nullb->disk = alloc_disk_node(1, home_node); - if (!disk) { - rv = -ENOMEM; - goto out_cleanup_blk_queue; - } mutex_lock(&lock); list_add_tail(&nullb->list, &nullb_list); @@ -589,6 +711,21 @@ static int null_add_dev(void) blk_queue_logical_block_size(nullb->q, bs); blk_queue_physical_block_size(nullb->q, bs); + sprintf(nullb->disk_name, "nullb%d", nullb->index); + + if (use_lightnvm) { + rv = nvm_register(nullb->q, nullb->disk_name, + &null_lnvm_dev_ops); + if (rv) + goto out_cleanup_blk_queue; + goto done; + } + + disk = nullb->disk = alloc_disk_node(1, home_node); + if (!disk) { + rv = -ENOMEM; + goto out_cleanup_lightnvm; + } size = gb * 1024 * 1024 * 1024ULL; set_capacity(disk, size >> 9); @@ -598,10 +735,15 @@ static int null_add_dev(void) disk->fops = &null_fops; disk->private_data = nullb; disk->queue = nullb->q; - sprintf(disk->disk_name, "nullb%d", nullb->index); + strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN); + add_disk(disk); +done: return 0; +out_cleanup_lightnvm: + if (use_lightnvm) + nvm_unregister(nullb->disk_name); out_cleanup_blk_queue: blk_cleanup_queue(nullb->q); out_cleanup_tags: @@ -625,6 +767,12 @@ static int __init null_init(void) bs = PAGE_SIZE; } + if (use_lightnvm && queue_mode != NULL_Q_MQ) { + pr_warn("null_blk: LightNVM only supported for blk-mq\n"); + pr_warn("null_blk: defaults queue mode to blk-mq\n"); + queue_mode = NULL_Q_MQ; + } + if (queue_mode == NULL_Q_MQ && use_per_node_hctx) { if (submit_queues < nr_online_nodes) { pr_warn("null_blk: submit_queues param is set to %u.", -- cgit v0.10.2 From 1b2ff19e6a957b1ef0f365ad331b608af80e932e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Nov 2015 14:25:52 +0100 Subject: blk-flush: Queue through IO scheduler when flush not required Currently blk_insert_flush() just adds flush request to q->queue_head when flush is not required. That completely bypasses IO scheduler so e.g. CFQ can be idling waiting for new request to arrive and will idle through the whole window unnecessarily. Luckily this only happens in rare cases as usually checks in generic_make_request_checks() clear FLUSH and FUA flags early if they are not needed. When no flushing is actually required, we can easily fix the problem by properly queueing the request through the IO scheduler. Ideally IO scheduler should be also made aware of requests queued via blk_flush_queue_rq(). However inserting flush request through IO scheduler can have unwanted side-effects since due to flush batching delaying the flush request in IO scheduler will delay all flush requests possibly coming from other processes. So we keep adding the request directly to q->queue_head. Signed-off-by: Jan Kara Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe diff --git a/block/blk-flush.c b/block/blk-flush.c index 9c423e5..c81d56e 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -422,7 +422,7 @@ void blk_insert_flush(struct request *rq) if (q->mq_ops) { blk_mq_insert_request(rq, false, false, true); } else - list_add_tail(&rq->queuelist, &q->queue_head); + q->elevator->type->ops.elevator_add_req_fn(q, rq); return; } -- cgit v0.10.2 From 9e5b8a6e53c79e6ccdbe6e62142ed9f317cefd46 Mon Sep 17 00:00:00 2001 From: Wei Jiangang Date: Mon, 9 Nov 2015 14:26:39 +0800 Subject: tools:testing/selftests: fix typo in futex/README Correct typo in tools/testing/selftests/futex/README. Signed-off-by: Wei Jiangang Acked-by: Darren Hart Signed-off-by: Shuah Khan diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README index 3224a04..0558bb9 100644 --- a/tools/testing/selftests/futex/README +++ b/tools/testing/selftests/futex/README @@ -27,7 +27,7 @@ o The build system shall remain as simple as possible, avoiding any archive or o Where possible, any helper functions or other package-wide code shall be implemented in header files, avoiding the need to compile intermediate object files. -o External dependendencies shall remain as minimal as possible. Currently gcc +o External dependencies shall remain as minimal as possible. Currently gcc and glibc are the only dependencies. o Tests return 0 for success and < 0 for failure. -- cgit v0.10.2 From ce36f6ad862fc3bc2466c89de17694e582a778b5 Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Fri, 13 Nov 2015 14:59:36 +0530 Subject: ARM: EXYNOS: Fix potential NULL pointer access in exynos_sys_powerdown_conf If no platform devices binded to the driver but driver itself loaded and exynos_sys_powerdown_conf is called from arch/arm/mach-exynos/{suspend.c, pm.c} it will result in NULL pointer access, to prevent this added check on pmu_context for NULL. Signed-off-by: Pankaj Dubey Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Krzysztof Kozlowski diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index de68938..c21e41d 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -748,8 +748,12 @@ static void exynos5_powerdown_conf(enum sys_powerdown mode) void exynos_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; + const struct exynos_pmu_data *pmu_data; + + if (!pmu_context) + return; - const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data; + pmu_data = pmu_context->pmu_data; if (pmu_data->powerdown_conf) pmu_data->powerdown_conf(mode); -- cgit v0.10.2 From 932cb839628e9b4660672e93280a41da044601e1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 5 Nov 2015 15:46:03 +0900 Subject: pinctrl: remove redundant if conditional from Kconfig The whole menu is guarded by menu "Pin controllers" depends on PINCTRL ... endmenu The if conditional outside of it is redundant. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b422e4e..312c78b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -5,8 +5,6 @@ config PINCTRL bool -if PINCTRL - menu "Pin controllers" depends on PINCTRL @@ -274,5 +272,3 @@ config PINCTRL_TB10X select GPIOLIB endmenu - -endif -- cgit v0.10.2 From 50cb2efaa63bdfd4a68b94acc55a12e68d9c33d4 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 17 Nov 2015 11:14:28 +0100 Subject: MAINTAINERS: Atmel drivers: change NAND and ISI entries Update Josh's entries about NAND and ISI drivers. Thanks for your work with Atmel Josh! Signed-off-by: Nicolas Ferre Acked-by: Wenyou Yang Acked-by: Ludovic Desroches Acked-by: Josh Wu diff --git a/MAINTAINERS b/MAINTAINERS index e9caa4b..3c9d0d0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1931,7 +1931,7 @@ S: Supported F: drivers/i2c/busses/i2c-at91.c ATMEL ISI DRIVER -M: Josh Wu +M: Ludovic Desroches L: linux-media@vger.kernel.org S: Supported F: drivers/media/platform/soc_camera/atmel-isi.c @@ -1950,7 +1950,8 @@ S: Supported F: drivers/net/ethernet/cadence/ ATMEL NAND DRIVER -M: Josh Wu +M: Wenyou Yang +M: Josh Wu L: linux-mtd@lists.infradead.org S: Supported F: drivers/mtd/nand/atmel_nand* -- cgit v0.10.2 From e71bf05554c9015bef8df3ffc386ccb37b153858 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 17 Nov 2015 16:30:17 +0800 Subject: ASoC: rt5670: fix wrong bit def for pll src The bit allocation for PLL source is 0x80 [13:11] instead of [12:11] Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index dc2b462..3f1b0f1 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -973,12 +973,12 @@ #define RT5670_SCLK_SRC_MCLK (0x0 << 14) #define RT5670_SCLK_SRC_PLL1 (0x1 << 14) #define RT5670_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */ -#define RT5670_PLL1_SRC_MASK (0x3 << 12) -#define RT5670_PLL1_SRC_SFT 12 -#define RT5670_PLL1_SRC_MCLK (0x0 << 12) -#define RT5670_PLL1_SRC_BCLK1 (0x1 << 12) -#define RT5670_PLL1_SRC_BCLK2 (0x2 << 12) -#define RT5670_PLL1_SRC_BCLK3 (0x3 << 12) +#define RT5670_PLL1_SRC_MASK (0x7 << 11) +#define RT5670_PLL1_SRC_SFT 11 +#define RT5670_PLL1_SRC_MCLK (0x0 << 11) +#define RT5670_PLL1_SRC_BCLK1 (0x1 << 11) +#define RT5670_PLL1_SRC_BCLK2 (0x2 << 11) +#define RT5670_PLL1_SRC_BCLK3 (0x3 << 11) #define RT5670_PLL1_PD_MASK (0x1 << 3) #define RT5670_PLL1_PD_SFT 3 #define RT5670_PLL1_PD_1 (0x0 << 3) -- cgit v0.10.2 From 56880a243c85668762dfec69b878862f86be6f04 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 11 Nov 2015 21:27:34 +0100 Subject: gpio: 74xx: fix a possible NULL dereference of_match_device could return NULL, and so cause a NULL pointer dereference later at line 132: priv->flags = (uintptr_t) of_id->data; Reported-by: coverity (CID 1324141) Signed-off-by: LABBE Corentin Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 6ed7c0f..6b18682 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -113,13 +113,16 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int mmio_74xx_gpio_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(mmio_74xx_gpio_ids, &pdev->dev); + const struct of_device_id *of_id; struct mmio_74xx_gpio_priv *priv; struct resource *res; void __iomem *dat; int err; + of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev); + if (!of_id) + return -ENODEV; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; -- cgit v0.10.2 From 853f0cb8603486a8ba17d5b728b52a9b4b029698 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 11 Nov 2015 21:27:35 +0100 Subject: gpio: syscon: fix a possible NULL dereference of_match_device could return NULL, and so cause a NULL pointer dereference later at line 199: priv->flags = of_id->data; Reported-by: coverity (CID 1324140) Signed-off-by: LABBE Corentin Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 045a952..7b25fdf 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -187,11 +187,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids); static int syscon_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + const struct of_device_id *of_id; struct syscon_gpio_priv *priv; struct device_node *np = dev->of_node; int ret; + of_id = of_match_device(syscon_gpio_ids, dev); + if (!of_id) + return -ENODEV; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; -- cgit v0.10.2 From 5664de25fa8ad2f06d6d7dd44df61023e1aaaa14 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 11 Nov 2015 21:27:36 +0100 Subject: gpio: palmas: fix a possible NULL dereference of_match_device could return NULL, and so cause a NULL pointer dereference later. Reported-by: coverity (CID 1130700) Signed-off-by: LABBE Corentin Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 171a638..52b447c 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -167,6 +167,8 @@ static int palmas_gpio_probe(struct platform_device *pdev) const struct palmas_device_data *dev_data; match = of_match_device(of_palmas_gpio_match, &pdev->dev); + if (!match) + return -ENODEV; dev_data = match->data; if (!dev_data) dev_data = &palmas_dev_data; -- cgit v0.10.2 From eeec5d0ef7ee54a75e09e861c3cc44177b8752c7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 10 Nov 2015 10:46:11 -0600 Subject: rtlwifi: rtl8821ae: Fix lockups on boot In commit 54328e64047a5 ("rtlwifi: rtl8821ae: Fix system lockups on boot"), an attempt was made to fix a regression introduced in commit 1277fa2ab2f9 ("rtlwifi: Remove the clear interrupt routine from all drivers"). Unfortunately, there were logic errors in that patch that prevented affected boxes from booting even after that patch was applied. The actual cause of the original problem is unknown as none of the developers have systems that are affected. Fixes: 54328e64047a ("rtlwifi: rtl8821ae: Fix system lockups on boot") Signed-off-by: Larry Finger Cc: Stable [V4.1+] Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 6e9418e..bbb789f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -2272,7 +2272,7 @@ void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - if (!rtlpci->int_clear) + if (rtlpci->int_clear) rtl8821ae_clear_interrupt(hw);/*clear it here first*/ rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 8ee141a..142bdff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -448,7 +448,7 @@ MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); -MODULE_PARM_DESC(int_clear, "Set to 1 to disable interrupt clear before set (default 0)\n"); +MODULE_PARM_DESC(int_clear, "Set to 0 to disable interrupt clear before set (default 1)\n"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); -- cgit v0.10.2 From 0563df2ce72b5d21217223e73f56ecfcacffb639 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sun, 15 Nov 2015 09:34:23 +0530 Subject: pinctrl: imx1-core: add missing of_node_put for_each_child_of_node performs an of_node_get on each iteration, so of_node_put is required on break out of the loop. This is done using Coccinelle. And semantic patch used for this is as follows: @@ expression root,e; local idexpression child; @@ for_each_child_of_node(root, child) { ... when != of_node_put(child) when != e = child ( return child; | + of_node_put(child); ? return ...; ) ... } Signed-off-by: Vaishali Thakkar Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 88a7fac..acaf84c 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -538,8 +538,10 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, func->groups[i] = child->name; grp = &info->groups[grp_index++]; ret = imx1_pinctrl_parse_groups(child, grp, info, i++); - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + of_node_put(child); return ret; + } } return 0; @@ -582,8 +584,10 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev, for_each_child_of_node(np, child) { ret = imx1_pinctrl_parse_functions(child, info, ifunc++); - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + of_node_put(child); return -ENOMEM; + } } return 0; -- cgit v0.10.2 From b59d5fb7e9c7b145eae1119af04b7c450efaa11b Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Mon, 16 Nov 2015 16:07:10 +0000 Subject: gpio-tegra: Do not create the debugfs entry by default The tegra gpio driver creates the debugfs entry irrespective of whether the device exists or not. This is enabled on an arm64_defconfig and leaves an entry in debugfs on all platforms where it is not useful. This patch fixes the issue by creating the entry only when a device exists. Signed-off-by: Suzuki K. Poulose Acked-by: Thierry Reding Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 027e5f4..896bf29 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -375,6 +375,60 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) } #endif +#ifdef CONFIG_DEBUG_FS + +#include +#include + +static int dbg_gpio_show(struct seq_file *s, void *unused) +{ + int i; + int j; + + for (i = 0; i < tegra_gpio_bank_count; i++) { + for (j = 0; j < 4; j++) { + int gpio = tegra_gpio_compose(i, j, 0); + seq_printf(s, + "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", + i, j, + tegra_gpio_readl(GPIO_CNF(gpio)), + tegra_gpio_readl(GPIO_OE(gpio)), + tegra_gpio_readl(GPIO_OUT(gpio)), + tegra_gpio_readl(GPIO_IN(gpio)), + tegra_gpio_readl(GPIO_INT_STA(gpio)), + tegra_gpio_readl(GPIO_INT_ENB(gpio)), + tegra_gpio_readl(GPIO_INT_LVL(gpio))); + } + } + return 0; +} + +static int dbg_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_gpio_show, &inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = dbg_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void tegra_gpio_debuginit(void) +{ + (void) debugfs_create_file("tegra_gpio", S_IRUGO, + NULL, NULL, &debug_fops); +} + +#else + +static inline void tegra_gpio_debuginit(void) +{ +} + +#endif + static struct irq_chip tegra_gpio_irq_chip = { .name = "GPIO", .irq_ack = tegra_gpio_irq_ack, @@ -519,6 +573,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) spin_lock_init(&bank->lvl_lock[j]); } + tegra_gpio_debuginit(); + return 0; } @@ -536,52 +592,3 @@ static int __init tegra_gpio_init(void) return platform_driver_register(&tegra_gpio_driver); } postcore_initcall(tegra_gpio_init); - -#ifdef CONFIG_DEBUG_FS - -#include -#include - -static int dbg_gpio_show(struct seq_file *s, void *unused) -{ - int i; - int j; - - for (i = 0; i < tegra_gpio_bank_count; i++) { - for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); - seq_printf(s, - "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", - i, j, - tegra_gpio_readl(GPIO_CNF(gpio)), - tegra_gpio_readl(GPIO_OE(gpio)), - tegra_gpio_readl(GPIO_OUT(gpio)), - tegra_gpio_readl(GPIO_IN(gpio)), - tegra_gpio_readl(GPIO_INT_STA(gpio)), - tegra_gpio_readl(GPIO_INT_ENB(gpio)), - tegra_gpio_readl(GPIO_INT_LVL(gpio))); - } - } - return 0; -} - -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, &inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init tegra_gpio_debuginit(void) -{ - (void) debugfs_create_file("tegra_gpio", S_IRUGO, - NULL, NULL, &debug_fops); - return 0; -} -late_initcall(tegra_gpio_debuginit); -#endif -- cgit v0.10.2 From c3dd25cc78150d4db8c7a1842884553202d1fd43 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 17:41:18 +0100 Subject: pinctrl: fix qcom ssbi drivers for 64-bit compilation When building pinctrl-ssbi-gpio and pinctrl-ssbi-mpp for ARM64, we get a compile warning about invalid types: drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c: In function 'pm8xxx_gpio_probe': drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c:675:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c: In function 'pm8xxx_mpp_probe': drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c:766:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] This changes the code so we cast the pointer to 'unsigned long', which is the right thing to do here. Signed-off-by: Arnd Bergmann Reviewed-by: Bjorn Andersson Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index d809c9e..19a3c3b 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -672,7 +672,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) return -ENOMEM; pctrl->dev = &pdev->dev; - pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev); pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!pctrl->regmap) { diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c index 8982027..b868ef1 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -763,7 +763,7 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev) return -ENOMEM; pctrl->dev = &pdev->dev; - pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + pctrl->npins = (unsigned long)of_device_get_match_data(&pdev->dev); pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!pctrl->regmap) { -- cgit v0.10.2 From 45bb780a2147b9995f3d288c44ecb87ca8a330e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Nov 2015 13:58:46 +0100 Subject: mac80211: don't advertise NL80211_FEATURE_FULL_AP_CLIENT_STATE For now, this feature doesn't actually work. To avoid shipping a kernel that has it enabled but where it can't be used disable it for now - we can re-enable it when it's fixed. This partially reverts 44674d9c2267 ("mac80211: advertise support for full station state in AP mode"). Cc: Ayala Beker Signed-off-by: Johannes Berg diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 858f6b1..175ffcf 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -541,8 +541,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_VIF_TXPOWER | NL80211_FEATURE_MAC_ON_CREATE | - NL80211_FEATURE_USERSPACE_MPM | - NL80211_FEATURE_FULL_AP_CLIENT_STATE; + NL80211_FEATURE_USERSPACE_MPM; if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | -- cgit v0.10.2 From c2e703a55245bfff3db53b1f7cbe59f1ee8a4339 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Nov 2015 14:25:21 +0100 Subject: mac80211: mesh: fix call_rcu() usage When using call_rcu(), the called function may be delayed quite significantly, and without a matching rcu_barrier() there's no way to be sure it has finished. Therefore, global state that could be gone/freed/reused should never be touched in the callback. Fix this in mesh by moving the atomic_dec() into the caller; that's not really a problem since we already unlinked the path and it will be destroyed anyway. This fixes a crash Jouni observed when running certain tests in a certain order, in which the mesh interface was torn down, the memory reused for a function pointer (work struct) and running that then crashed since the pointer had been decremented by 1, resulting in an invalid instruction byte stream. Cc: stable@vger.kernel.org Fixes: eb2b9311fd00 ("mac80211: mesh path table implementation") Reported-by: Jouni Malinen Signed-off-by: Johannes Berg diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index b890e22..b3b44a5 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -779,10 +779,8 @@ void mesh_plink_broken(struct sta_info *sta) static void mesh_path_node_reclaim(struct rcu_head *rp) { struct mpath_node *node = container_of(rp, struct mpath_node, rcu); - struct ieee80211_sub_if_data *sdata = node->mpath->sdata; del_timer_sync(&node->mpath->timer); - atomic_dec(&sdata->u.mesh.mpaths); kfree(node->mpath); kfree(node); } @@ -790,8 +788,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) /* needs to be called with the corresponding hashwlock taken */ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) { - struct mesh_path *mpath; - mpath = node->mpath; + struct mesh_path *mpath = node->mpath; + struct ieee80211_sub_if_data *sdata = node->mpath->sdata; + spin_lock(&mpath->state_lock); mpath->flags |= MESH_PATH_RESOLVING; if (mpath->is_gate) @@ -799,6 +798,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) hlist_del_rcu(&node->list); call_rcu(&node->rcu, mesh_path_node_reclaim); spin_unlock(&mpath->state_lock); + atomic_dec(&sdata->u.mesh.mpaths); atomic_dec(&tbl->entries); } -- cgit v0.10.2 From e81b75f7b206d4c44afd20354a66825239490109 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 17 Nov 2015 17:46:48 +0530 Subject: ARC: remove SYNC from __switch_to() SYNC in __switch_to() is a historic relic and not needed at all. - In UP context it is obviously useless, why would we want to stall the core for all updates to stack memory of t0 to complete before loading kernel mode callee registers from t1 stack's memory. - In SMP, there could be potential race in which outgoing task could be concurrently picked for running on a different core, thus writes to stack here need to be visible before the reads from stack on other core. Peter confirmed that generic schedular already has needed barriers (by way of rq lock) so there is no need for additional arch barrier. This came up when Noam was trying to replace this SYNC with EZChip specific hardware thread scheduling instruction for their platform support. Link: http://lkml.kernel.org/r/20151102092654.GM17308@twins.programming.kicks-ass.net Cc: Peter Zijlstra Cc: linux-kernel@vger.kernel.org Cc: Noam Camus Signed-off-by: Vineet Gupta diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c index c14a5be..5d446df 100644 --- a/arch/arc/kernel/ctx_sw.c +++ b/arch/arc/kernel/ctx_sw.c @@ -58,8 +58,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task) "st sp, [r24] \n\t" #endif - "sync \n\t" - /* * setup _current_task with incoming tsk. * optionally, set r25 to that as well diff --git a/arch/arc/kernel/ctx_sw_asm.S b/arch/arc/kernel/ctx_sw_asm.S index e248594..e6890b1 100644 --- a/arch/arc/kernel/ctx_sw_asm.S +++ b/arch/arc/kernel/ctx_sw_asm.S @@ -44,9 +44,6 @@ __switch_to: * don't need to do anything special to return it */ - /* hardware memory barrier */ - sync - /* * switch to new task, contained in r1 * Temp reg r3 is required to get the ptr to store val -- cgit v0.10.2 From 5bbbfdf685657771fda05b926b28ca0f79163a28 Mon Sep 17 00:00:00 2001 From: Junichi Nomura Date: Tue, 17 Nov 2015 09:39:26 +0000 Subject: dm: fix ioctl retry termination with signal dm-mpath retries ioctl, when no path is readily available and the device is configured to queue I/O in such a case. If you want to stop the retry before multipathd decides to turn off queueing mode, you could send signal for the process to exit from the loop. However the check of fatal signal has not carried along when commit 6c182cd88d17 ("dm mpath: fix ioctl deadlock when no paths") moved the loop from dm-mpath to dm core. As a result, we can't terminate such a process in the retry loop. Easy reproducer of the situation is: # dmsetup create mp --table '0 1024 multipath 0 0 0 0' # dmsetup message mp 0 'queue_if_no_path' # sg_inq /dev/mapper/mp then you should be able to terminate sg_inq by pressing Ctrl+C. Fixes: 6c182cd88d17 ("dm mpath: fix ioctl deadlock when no paths") Signed-off-by: Jun'ichi Nomura Cc: Hannes Reinecke Cc: Mikulas Patocka Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index aaa6caa..3d18292 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1562,7 +1562,7 @@ static int multipath_prepare_ioctl(struct dm_target *ti, spin_unlock_irqrestore(&m->lock, flags); - if (r == -ENOTCONN && !fatal_signal_pending(current)) { + if (r == -ENOTCONN) { spin_lock_irqsave(&m->lock, flags); if (!m->current_pg) { /* Path status changed, redo selection */ diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6e15f35..fabd5d8 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -591,7 +591,7 @@ retry: out: dm_put_live_table(md, *srcu_idx); - if (r == -ENOTCONN) { + if (r == -ENOTCONN && !fatal_signal_pending(current)) { msleep(10); goto retry; } -- cgit v0.10.2 From 647a20d5cad7477033bc021ec9dd75edf4bbf9a0 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 17 Nov 2015 14:11:34 -0500 Subject: dm: do not reuse dm_blk_ioctl block_device input as local variable (Ab)using the @bdev passed to dm_blk_ioctl() opens the potential for targets' .prepare_ioctl to fail if they go on to check the bdev for !NULL. Fixes: e56f81e0b01e ("dm: refactor ioctl handling") Reported-by: Junichi Nomura Signed-off-by: Mike Snitzer diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fabd5d8..5df4048 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -603,9 +603,10 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, { struct mapped_device *md = bdev->bd_disk->private_data; struct dm_target *tgt; + struct block_device *tgt_bdev = NULL; int srcu_idx, r; - r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx); + r = dm_get_live_table_for_ioctl(md, &tgt, &tgt_bdev, &mode, &srcu_idx); if (r < 0) return r; @@ -620,7 +621,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, goto out; } - r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); + r = __blkdev_driver_ioctl(tgt_bdev, mode, cmd, arg); out: dm_put_live_table(md, srcu_idx); return r; -- cgit v0.10.2 From 43e43c9ea60a7a1831ec823773e924d2dadefd44 Mon Sep 17 00:00:00 2001 From: Junichi Nomura Date: Tue, 17 Nov 2015 09:36:56 +0000 Subject: dm mpath: fix infinite recursion in ioctl when no paths and !queue_if_no_path In multipath_prepare_ioctl(), - pgpath is a path selected from available paths - m->queue_io is true if we cannot send a request immediately to paths, either because: * there is no available path * the path group needs activation (pg_init) - pg_init is not started - pg_init is still running - m->queue_if_no_path is true if the device is configured to queue I/O if there are no available paths If !pgpath && !m->queue_if_no_path, the handler should return -EIO. However in the course of refactoring the condition check has broken and returns success in that case. Since bdev points to the dm device itself, dm_blk_ioctl() calls __blk_dev_driver_ioctl() for itself and recurses until crash. You could reproduce the problem like this: # dmsetup create mp --table '0 1024 multipath 0 0 0 0' # sg_inq /dev/mapper/mp [ 172.648615] BUG: unable to handle kernel paging request at fffffffc81b10268 [ 172.662843] PGD 19dd067 PUD 0 [ 172.666269] Thread overran stack, or stack corrupted [ 172.671808] Oops: 0000 [#1] SMP ... Fix the condition check with some clarifications. Fixes: e56f81e0b01e ("dm: refactor ioctl handling") Signed-off-by: Jun'ichi Nomura Cc: Christoph Hellwig Cc: Mike Snitzer Signed-off-by: Mike Snitzer diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 3d18292..cfa29f5 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1537,29 +1537,31 @@ static int multipath_prepare_ioctl(struct dm_target *ti, struct block_device **bdev, fmode_t *mode) { struct multipath *m = ti->private; - struct pgpath *pgpath; unsigned long flags; int r; - r = 0; - spin_lock_irqsave(&m->lock, flags); if (!m->current_pgpath) __choose_pgpath(m, 0); - pgpath = m->current_pgpath; - - if (pgpath) { - *bdev = pgpath->path.dev->bdev; - *mode = pgpath->path.dev->mode; + if (m->current_pgpath) { + if (!m->queue_io) { + *bdev = m->current_pgpath->path.dev->bdev; + *mode = m->current_pgpath->path.dev->mode; + r = 0; + } else { + /* pg_init has not started or completed */ + r = -ENOTCONN; + } + } else { + /* No path is available */ + if (m->queue_if_no_path) + r = -ENOTCONN; + else + r = -EIO; } - if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path)) - r = -ENOTCONN; - else if (!*bdev) - r = -EIO; - spin_unlock_irqrestore(&m->lock, flags); if (r == -ENOTCONN) { -- cgit v0.10.2 From 0874f8ec9b0a462cc8787b7bb4b7824a1690da10 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 16 Nov 2015 15:26:51 -0800 Subject: qla2xxx: Fix rwlock recursion This patch fixes the following kernel bug: kernel:BUG: rwlock recursion on CPU#2, insmod/39333, ffff8803e998cb28 kernel: Call Trace: kernel: [] dump_stack+0x48/0x64 kernel: [] rwlock_bug+0x67/0x70 kernel: [] do_raw_write_lock+0x8a/0xa0 kernel: [] _raw_write_lock_irqsave+0x63/0x80 kernel: [] qla82xx_rd_32+0xe8/0x140 [qla2xxx] kernel: [] qla82xx_crb_win_lock+0x25/0x60 [qla2xxx] kernel: [] qla82xx_wr_32+0xf6/0x150 [qla2xxx] kernel: [] qla82xx_disable_intrs+0x50/0x80 [qla2xxx] kernel: [] qla82xx_reset_chip+0x1a/0x20 [qla2xxx] kernel: [] qla2x00_initialize_adapter+0x132/0x420 [qla2xxx] kernel: [] qla82xx_rd_32+0xe8/0x140 [qla2xxx] kernel: [] qla82xx_crb_win_lock+0x25/0x60 [qla2xxx] kernel: [] qla82xx_wr_32+0xf6/0x150 [qla2xxx] kernel: [] qla82xx_disable_intrs+0x50/0x80 [qla2xxx] kernel: [] qla82xx_reset_chip+0x1a/0x20 [qla2xxx] kernel: [] qla2x00_initialize_adapter+0x132/0x420 [qla2xxx] kernel: [] qla2x00_probe_one+0xefe/0x2130 [qla2xxx] kernel: [] local_pci_probe+0x4c/0xa0 kernel: [] pci_call_probe+0x83/0xa0 kernel: [] pci_device_probe+0x7f/0xb0 kernel: [] really_probe+0x133/0x390 kernel: [] driver_probe_device+0x59/0xd0 kernel: [] __driver_attach+0xa1/0xb0 kernel: [] bus_for_each_dev+0x8d/0xb0 kernel: [] driver_attach+0x1e/0x20 kernel: [] bus_add_driver+0x1d2/0x290 kernel: [] driver_register+0x60/0xe0 kernel: [] __pci_register_driver+0x64/0x70 kernel: [] qla2x00_module_init+0x1cb/0x21b [qla2xxx] kernel: [] do_one_initcall+0xad/0x1c0 kernel: [] do_init_module+0x69/0x210 kernel: [] load_module+0x5cc/0x750 kernel: [] SyS_init_module+0x92/0xc0 kernel: [] entry_SYSCALL_64_fastpath+0x12/0x6f Fixes: 8dfa4b5a9b44 ("qla2xxx: Fix sparse annotation") Signed-off-by: Bart Van Assche Reported-by: Himanshu Madhani Tested-by: Himanshu Madhani Reviewed-by: Himanshu Madhani Reviewed-by: Chad Dupuis Cc: Giridhar Malavali Cc: Xose Vazquez Perez Cc: stable # v4.3+ Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index eb0cc54..b6b4cfd 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -433,7 +433,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in, if (off_in < QLA82XX_PCI_CRBSPACE) return -1; - *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE); + off_in -= QLA82XX_PCI_CRBSPACE; /* Try direct map */ m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)]; @@ -443,6 +443,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in, return 0; } /* Not in direct map, use crb window */ + *off_out = (void __iomem *)off_in; return 1; } -- cgit v0.10.2 From 28fa99b7645a568d7f821e9196e97a3c7b2f8109 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 18 Nov 2015 11:19:36 +0000 Subject: ARM: wire up mlock2 syscall Signed-off-by: Russell King diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index 7a2a32a1..ede692f 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -416,6 +416,7 @@ #define __NR_execveat (__NR_SYSCALL_BASE+387) #define __NR_userfaultfd (__NR_SYSCALL_BASE+388) #define __NR_membarrier (__NR_SYSCALL_BASE+389) +#define __NR_mlock2 (__NR_SYSCALL_BASE+390) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index fde6c88..ac368bb 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -399,6 +399,7 @@ CALL(sys_execveat) CALL(sys_userfaultfd) CALL(sys_membarrier) + CALL(sys_mlock2) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v0.10.2 From 002374f371bd02df864cce1fe85d90dc5b292837 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 11 Nov 2015 14:21:18 +0000 Subject: MIPS: KVM: Fix ASID restoration logic ASID restoration on guest resume should determine the guest execution mode based on the guest Status register rather than bit 30 of the guest PC. Fix the two places in locore.S that do this, loading the guest status from the cop0 area. Note, this assembly is specific to the trap & emulate implementation of KVM, so it doesn't need to check the supervisor bit as that mode is not implemented in the guest. Fixes: b680f70fc111 ("KVM/MIPS32: Entry point for trampolining to...") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: # 3.10.x- Signed-off-by: Paolo Bonzini diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 7bab3a4..7e22108 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S @@ -157,9 +157,11 @@ FEXPORT(__kvm_mips_vcpu_run) FEXPORT(__kvm_mips_load_asid) /* Set the ASID for the Guest Kernel */ - INT_SLL t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ - /* addresses shift to 0x80000000 */ - bltz t0, 1f /* If kernel */ + PTR_L t0, VCPU_COP0(k1) + LONG_L t0, COP0_STATUS(t0) + andi t0, KSU_USER | ST0_ERL | ST0_EXL + xori t0, KSU_USER + bnez t0, 1f /* If kernel */ INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID /* else user */ 1: @@ -474,9 +476,11 @@ __kvm_mips_return_to_guest: mtc0 t0, CP0_EPC /* Set the ASID for the Guest Kernel */ - INT_SLL t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ - /* addresses shift to 0x80000000 */ - bltz t0, 1f /* If kernel */ + PTR_L t0, VCPU_COP0(k1) + LONG_L t0, COP0_STATUS(t0) + andi t0, KSU_USER | ST0_ERL | ST0_EXL + xori t0, KSU_USER + bnez t0, 1f /* If kernel */ INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID /* else user */ 1: -- cgit v0.10.2 From c5c2a3b998f1ff5a586f9d37e154070b8d550d17 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 11 Nov 2015 14:21:19 +0000 Subject: MIPS: KVM: Fix CACHE immediate offset sign extension The immediate field of the CACHE instruction is signed, so ensure that it gets sign extended by casting it to an int16_t rather than just masking the low 16 bits. Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: # 3.10.x- Signed-off-by: Paolo Bonzini diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index d5fa3ea..41b1b09 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -1581,7 +1581,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, base = (inst >> 21) & 0x1f; op_inst = (inst >> 16) & 0x1f; - offset = inst & 0xffff; + offset = (int16_t)inst; cache = (inst >> 16) & 0x3; op = (inst >> 18) & 0x7; -- cgit v0.10.2 From 585bb8f9a5e592f2ce7abbe5ed3112d5438d2754 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 11 Nov 2015 14:21:20 +0000 Subject: MIPS: KVM: Uninit VCPU in vcpu_create error path If either of the memory allocations in kvm_arch_vcpu_create() fail, the vcpu which has been allocated and kvm_vcpu_init'd doesn't get uninit'd in the error handling path. Add a call to kvm_vcpu_uninit() to fix this. Fixes: 669e846e6c4e ("KVM/MIPS32: MIPS arch specific APIs for KVM") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Paolo Bonzini Cc: Gleb Natapov Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: # 3.10.x- Signed-off-by: Paolo Bonzini diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 49ff3bf..b9b803f 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -279,7 +279,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) if (!gebase) { err = -ENOMEM; - goto out_free_cpu; + goto out_uninit_cpu; } kvm_debug("Allocated %d bytes for KVM Exception Handlers @ %p\n", ALIGN(size, PAGE_SIZE), gebase); @@ -343,6 +343,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) out_free_gebase: kfree(gebase); +out_uninit_cpu: + kvm_vcpu_uninit(vcpu); + out_free_cpu: kfree(vcpu); -- cgit v0.10.2 From 127a457acb2131fdb31c68c98cf11eda8ba7b380 Mon Sep 17 00:00:00 2001 From: Matt Gingell Date: Tue, 17 Nov 2015 17:32:05 +0100 Subject: KVM: x86: fix interrupt window handling in split IRQ chip case This patch ensures that dm_request_for_irq_injection and post_kvm_run_save are in sync, avoiding that an endless ping-pong between userspace (who correctly notices that IF=0) and the kernel (who insists that userspace handles its request for the interrupt window). To synchronize them, it also adds checks for kvm_arch_interrupt_allowed and !kvm_event_needs_reinjection. These are always needed, not just for in-kernel LAPIC. Signed-off-by: Matt Gingell [A collage of two patches from Matt. - Paolo] Fixes: 1c1a9ce973a7863dd46767226bce2a5f12d48bc6 Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 00462bd..46ed8ed 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2763,6 +2763,12 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, return 0; } +static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu) +{ + return (!lapic_in_kernel(vcpu) || + kvm_apic_accept_pic_intr(vcpu)); +} + static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { @@ -5921,12 +5927,16 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu) if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm)) return false; + if (!kvm_arch_interrupt_allowed(vcpu)) + return false; + if (kvm_cpu_has_interrupt(vcpu)) return false; - return (irqchip_split(vcpu->kvm) - ? kvm_apic_accept_pic_intr(vcpu) - : kvm_arch_interrupt_allowed(vcpu)); + if (kvm_event_needs_reinjection(vcpu)) + return false; + + return kvm_cpu_accept_dm_intr(vcpu); } static void post_kvm_run_save(struct kvm_vcpu *vcpu) @@ -5937,17 +5947,12 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0; kvm_run->cr8 = kvm_get_cr8(vcpu); kvm_run->apic_base = kvm_get_apic_base(vcpu); - if (!irqchip_in_kernel(vcpu->kvm)) - kvm_run->ready_for_interrupt_injection = - kvm_arch_interrupt_allowed(vcpu) && - !kvm_cpu_has_interrupt(vcpu) && - !kvm_event_needs_reinjection(vcpu); - else if (!pic_in_kernel(vcpu->kvm)) - kvm_run->ready_for_interrupt_injection = - kvm_apic_accept_pic_intr(vcpu) && - !kvm_cpu_has_interrupt(vcpu); - else - kvm_run->ready_for_interrupt_injection = 1; + kvm_run->ready_for_interrupt_injection = + pic_in_kernel(vcpu->kvm) || + (kvm_arch_interrupt_allowed(vcpu) && + !kvm_cpu_has_interrupt(vcpu) && + !kvm_event_needs_reinjection(vcpu) && + kvm_cpu_accept_dm_intr(vcpu)); } static void update_cr8_intercept(struct kvm_vcpu *vcpu) -- cgit v0.10.2 From 782d422bcaee4680c640fbc8ce8c45524fd11790 Mon Sep 17 00:00:00 2001 From: Matt Gingell Date: Mon, 16 Nov 2015 15:26:00 -0800 Subject: KVM: x86: split kvm_vcpu_ready_for_interrupt_injection out of dm_request_for_irq_injection This patch breaks out a new function kvm_vcpu_ready_for_interrupt_injection. This routine encapsulates the logic required to determine whether a vcpu is ready to accept an interrupt injection, which is now required on multiple paths. Reviewed-by: Steve Rutherford Signed-off-by: Matt Gingell Fixes: 1c1a9ce973a7863dd46767226bce2a5f12d48bc6 Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 46ed8ed..32f6b76 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2769,6 +2769,20 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu) kvm_apic_accept_pic_intr(vcpu)); } +/* + * if userspace requested an interrupt window, check that the + * interrupt window is open. + * + * No need to exit to userspace if we already have an interrupt queued. + */ +static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu) +{ + return kvm_arch_interrupt_allowed(vcpu) && + !kvm_cpu_has_interrupt(vcpu) && + !kvm_event_needs_reinjection(vcpu) && + kvm_cpu_accept_dm_intr(vcpu); +} + static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { @@ -5916,27 +5930,10 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) return emulator_write_emulated(ctxt, rip, instruction, 3, NULL); } -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu) { - if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm)) - return false; - - if (!kvm_arch_interrupt_allowed(vcpu)) - return false; - - if (kvm_cpu_has_interrupt(vcpu)) - return false; - - if (kvm_event_needs_reinjection(vcpu)) - return false; - - return kvm_cpu_accept_dm_intr(vcpu); + return vcpu->run->request_interrupt_window && + likely(!pic_in_kernel(vcpu->kvm)); } static void post_kvm_run_save(struct kvm_vcpu *vcpu) @@ -5949,10 +5946,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) kvm_run->apic_base = kvm_get_apic_base(vcpu); kvm_run->ready_for_interrupt_injection = pic_in_kernel(vcpu->kvm) || - (kvm_arch_interrupt_allowed(vcpu) && - !kvm_cpu_has_interrupt(vcpu) && - !kvm_event_needs_reinjection(vcpu) && - kvm_cpu_accept_dm_intr(vcpu)); + kvm_vcpu_ready_for_interrupt_injection(vcpu); } static void update_cr8_intercept(struct kvm_vcpu *vcpu) @@ -6668,7 +6662,8 @@ static int vcpu_run(struct kvm_vcpu *vcpu) if (kvm_cpu_has_pending_timer(vcpu)) kvm_inject_pending_timer_irqs(vcpu); - if (dm_request_for_irq_injection(vcpu)) { + if (dm_request_for_irq_injection(vcpu) && + kvm_vcpu_ready_for_interrupt_injection(vcpu)) { r = 0; vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; ++vcpu->stat.request_irq_exits; -- cgit v0.10.2 From 934bf65354227981df15bbc755d33f4ba3443ff2 Mon Sep 17 00:00:00 2001 From: Matt Gingell Date: Mon, 16 Nov 2015 15:26:05 -0800 Subject: KVM: x86: set KVM_REQ_EVENT on local interrupt request from user space Set KVM_REQ_EVENT when a PIC in user space injects a local interrupt. Currently a request is only made when neither the PIC nor the APIC is in the kernel, which is not sufficient in the split IRQ chip case. This addresses a problem in QEMU where interrupts are delayed until another path invokes the event loop. Reviewed-by: Steve Rutherford Signed-off-by: Matt Gingell Fixes: 1c1a9ce973a7863dd46767226bce2a5f12d48bc6 Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 32f6b76..f254e29 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2806,6 +2806,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, return -EEXIST; vcpu->arch.pending_external_vector = irq->irq; + kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; } -- cgit v0.10.2 From 62a193edaf90df38356e292f47a17f28e0cee3f1 Mon Sep 17 00:00:00 2001 From: Matt Gingell Date: Mon, 16 Nov 2015 15:26:07 -0800 Subject: KVM: x86: request interrupt window when IRQ chip is split Before this patch, we incorrectly enter the guest without requesting an interrupt window if the IRQ chip is split between user space and the kernel. Because lapic_in_kernel no longer implies the PIC is in the kernel, this patch tests pic_in_kernel to determining whether an interrupt window should be requested when entering the guest. If the APIC is in the kernel and we request an interrupt window the guest will return immediately. If the APIC is masked the guest will not not make forward progress and unmask it, leading to a loop when KVM reenters and requests again. This patch adds a check to ensure the APIC is ready to accept an interrupt before requesting a window. Reviewed-by: Steve Rutherford Signed-off-by: Matt Gingell [Use the other newly introduced functions. - Paolo] Fixes: 1c1a9ce973a7863dd46767226bce2a5f12d48bc6 Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f254e29..eed3228 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6360,8 +6360,10 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, static int vcpu_enter_guest(struct kvm_vcpu *vcpu) { int r; - bool req_int_win = !lapic_in_kernel(vcpu) && - vcpu->run->request_interrupt_window; + bool req_int_win = + dm_request_for_irq_injection(vcpu) && + kvm_cpu_accept_dm_intr(vcpu); + bool req_immediate_exit = false; if (vcpu->requests) { -- cgit v0.10.2 From f4be978b9611c94f20cdc8cee540ef1a52f8875c Mon Sep 17 00:00:00 2001 From: Omair M Abdullah Date: Mon, 9 Nov 2015 23:20:01 +0530 Subject: ASoC: topology: fix info callback for TLV byte control topology core used wrong callback for TLV bytes control, it should be snd_soc_bytes_info_ext and not snd_soc_bytes_info Signed-off-by: Omair M Abdullah Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8d7ec80..50f21ed 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -531,7 +531,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, /* TLV bytes controls need standard kcontrol info handler, * TLV callback and extended put/get handlers. */ - k->info = snd_soc_bytes_info; + k->info = snd_soc_bytes_info_ext; k->tlv.c = snd_soc_bytes_tlv_callback; ext_ops = tplg->bytes_ext_ops; -- cgit v0.10.2 From f97c2309667b501c03fcc1c8b3595f5ca0a1ff01 Mon Sep 17 00:00:00 2001 From: Hongzhou Yang Date: Tue, 17 Nov 2015 14:17:13 -0800 Subject: pinctrl: mediatek: Add get_direction support. Since Linux gpio framework return 0 for output, 1 for input. But HW use 0 stands for input, and 1 stands for output. So use negative to correct it. And gpio_chip.get is used to get input value, no need to get output value, so removing it. Signed-off-by: Hongzhou Yang Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index f307f1d..5c71727 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -747,7 +747,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset) reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset; bit = BIT(offset & 0xf); regmap_read(pctl->regmap1, reg_addr, &read_val); - return !!(read_val & bit); + return !(read_val & bit); } static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -757,12 +757,8 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned int read_val = 0; struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); - if (mtk_gpio_get_direction(chip, offset)) - reg_addr = mtk_get_port(pctl, offset) + - pctl->devdata->dout_offset; - else - reg_addr = mtk_get_port(pctl, offset) + - pctl->devdata->din_offset; + reg_addr = mtk_get_port(pctl, offset) + + pctl->devdata->din_offset; bit = BIT(offset & 0xf); regmap_read(pctl->regmap1, reg_addr, &read_val); @@ -997,6 +993,7 @@ static struct gpio_chip mtk_gpio_chip = { .owner = THIS_MODULE, .request = gpiochip_generic_request, .free = gpiochip_generic_free, + .get_direction = mtk_gpio_get_direction, .direction_input = mtk_gpio_direction_input, .direction_output = mtk_gpio_direction_output, .get = mtk_gpio_get, -- cgit v0.10.2 From 757b22f9d56fb4e510782b29da752824daddf3c8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 17:49:23 +0100 Subject: advansys: fix big-endian builds Building the advansys driver in a big-endian configuration such as ARM allmodconfig shows a warning: drivers/scsi/advansys.c: In function 'adv_build_req': include/uapi/linux/byteorder/big_endian.h:32:26: warning: large integer implicitly truncated to unsigned type [-Woverflow] #define __cpu_to_le32(x) ((__force __le32)__swab32((x))) drivers/scsi/advansys.c:7806:22: note: in expansion of macro 'cpu_to_le32' scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); It turns out that the commit that introduced this used the cpu_to_le32() incorrectly on an 8-bit field, which results in the sense_len to always be set to zero, as the SCSI_SENSE_BUFFERSIZE value gets moved to upper byte of the 32-bit intermediate. This removes the cpu_to_le32() call to restore the original version. I found this only by looking at the compiler output and have not done a full review for possible further endianess bugs in the same driver. Signed-off-by: Arnd Bergmann Fixes: 811ddc057aac ("advansys: use DMA-API for mapping sense buffer") Reviewed-by: Hannes Reinecke Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 4305178..1c1cd65 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7803,7 +7803,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, return ASC_BUSY; } scsiqp->sense_addr = cpu_to_le32(sense_addr); - scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); + scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE; /* Build ADV_SCSI_REQ_Q */ -- cgit v0.10.2 From 4b6295b238cf0fe0841675816be0998345d5990a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 18 Nov 2015 19:11:46 +0530 Subject: ASoC: Intel: Skylake: Add I2C depends for SKL machine The i2c is dependency for the i2c codec drivers, so machine should depend on i2c. WIthout this we get build failures if I2C is not selected sound/soc/codecs/rl6347a.c: In function 'rl6347a_hw_write': >> sound/soc/codecs/rl6347a.c:66:8: error: implicit declaration of function >> 'i2c_master_send' [-Werror=implicit-function-declaration] ret = i2c_master_send(client, data, 4); ^ sound/soc/codecs/rl6347a.c: In function 'rl6347a_hw_read': >> sound/soc/codecs/rl6347a.c:114:8: error: implicit declaration of function >> 'i2c_transfer' [-Werror=implicit-function-declaration] ret = i2c_transfer(client->adapter, xfer, 2); Reported-by: kbuild test robot Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 7b778ab..d430ef5 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -144,7 +144,7 @@ config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" - depends on X86 && ACPI + depends on X86 && ACPI && I2C select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 -- cgit v0.10.2 From 945fae44d316a572916f673b2a58cd2d5389e7b6 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 17 Nov 2015 13:46:48 -0800 Subject: udp: remove duplicate include Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 24ec14f9..0c7b0e6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -100,7 +100,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 6f97532ef05e49f1998a09f8359b83d00a7b3229 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 17 Nov 2015 14:24:27 -0800 Subject: fm10k: fix memory leak This was detected by Coverity. The function skb_cow_head leaves skb alone on failure, so caller needs to free. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 639263d..7781e80 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -627,8 +627,10 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* verify the skb head is not shared */ err = skb_cow_head(skb, 0); - if (err) + if (err) { + dev_kfree_skb(skb); return NETDEV_TX_OK; + } /* locate vlan header */ vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); -- cgit v0.10.2 From 52d178516dcf61e7a59363a572458c830af6e520 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 17 Nov 2015 14:26:06 -0800 Subject: hdlc: fix null-deref on allocation failure If alloc_netdev() failed and return NULL, then the next instruction would dereference it. Found by Coverity. Compile tested only. Not sure if anyone still uses this driver (or the whole WAN subsystem). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index e92aaf6..89541cc 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1075,11 +1075,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) used = pvc_is_used(pvc); - if (type == ARPHRD_ETHER) { + if (type == ARPHRD_ETHER) dev = alloc_netdev(0, "pvceth%d", NET_NAME_UNKNOWN, ether_setup); - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - } else + else dev = alloc_netdev(0, "pvc%d", NET_NAME_UNKNOWN, pvc_setup); if (!dev) { @@ -1088,9 +1087,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) return -ENOBUFS; } - if (type == ARPHRD_ETHER) + if (type == ARPHRD_ETHER) { + dev->priv_flags &= ~IFF_TX_SKB_SHARING; eth_hw_addr_random(dev); - else { + } else { *(__be16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); } -- cgit v0.10.2 From 0208e951d55c435137543e12d7ee795c3784713a Mon Sep 17 00:00:00 2001 From: Ben Pope Date: Tue, 17 Nov 2015 18:21:07 -0700 Subject: ethernet/atheros/alx: add Killer E2400 device ID This patch adds the PCI device ID (0xe0a1) and alx_pci_tbl entry for the Killer E2400 Ethernet controller, modeled after the Killer E2200 controller support (0xe091) already present in the alx driver. This patch was originally authored by Ben Pope, but it got held up by issues in the commit message, so I'm resubmitting it on his behalf. I've extensively used a kernel with this patch on a System76 serw9 laptop and am quite confident it works well (at least on the hardware I have available for testing). Note that as a favor to System76, Ubuntu has been carrying this as a sauce patch in their 4.2 based Wily kernel, which presumably has given it real-world testing on other E2400 equipped hardware (I don't know of any Ubuntu kernel bugs filed about it): https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1498633 Signed-off-by: Jason Gerard DeRose Signed-off-by: Ben Pope Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c8af3ce..bd377a6 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1534,6 +1534,8 @@ static const struct pci_device_id alx_pci_tbl[] = { .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, + { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400), + .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h index af006b4..0959e68 100644 --- a/drivers/net/ethernet/atheros/alx/reg.h +++ b/drivers/net/ethernet/atheros/alx/reg.h @@ -37,6 +37,7 @@ #define ALX_DEV_ID_AR8161 0x1091 #define ALX_DEV_ID_E2200 0xe091 +#define ALX_DEV_ID_E2400 0xe0a1 #define ALX_DEV_ID_AR8162 0x1090 #define ALX_DEV_ID_AR8171 0x10A1 #define ALX_DEV_ID_AR8172 0x10A0 -- cgit v0.10.2 From 022be25c2498e1baa82562aba9f3380b1ef70fa6 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Wed, 18 Nov 2015 09:03:50 +0530 Subject: net: macb: Add support for sgmii phy interface This patch adds support for the sgmii phy interface. Signed-off-by: Punnaiah Choudary Kalluri Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 88c1e1a..169059c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1682,6 +1682,8 @@ static void macb_init_hw(struct macb *bp) macb_set_hwaddr(bp); config = macb_mdc_clk_div(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ @@ -2416,6 +2418,8 @@ static int macb_init(struct platform_device *pdev) /* Set MII management clock divider */ val = macb_mdc_clk_div(bp); val |= macb_dbw(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); macb_writel(bp, NCFGR, val); return 0; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 6e1faea..d83b0db 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -215,12 +215,17 @@ /* GEM specific NCFGR bitfields. */ #define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ #define GEM_GBE_SIZE 1 +#define GEM_PCSSEL_OFFSET 11 +#define GEM_PCSSEL_SIZE 1 #define GEM_CLK_OFFSET 18 /* MDC clock division */ #define GEM_CLK_SIZE 3 #define GEM_DBW_OFFSET 21 /* Data bus width */ #define GEM_DBW_SIZE 2 #define GEM_RXCOEN_OFFSET 24 #define GEM_RXCOEN_SIZE 1 +#define GEM_SGMIIEN_OFFSET 27 +#define GEM_SGMIIEN_SIZE 1 + /* Constants for data bus width. */ #define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */ -- cgit v0.10.2 From 183e53e8ddf4165c3763181682189362d6b403f7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Nov 2015 17:18:40 +0100 Subject: usb: musb: USB_TI_CPPI41_DMA requires dmaengine support The CPPI-4.1 driver selects TI_CPPI41, which is a dmaengine driver and that may not be available when CONFIG_DMADEVICES is not set: warning: (USB_TI_CPPI41_DMA) selects TI_CPPI41 which has unmet direct dependencies (DMADEVICES && ARCH_OMAP) This adds an extra dependency to avoid generating warnings in randconfig builds. Ideally we'd remove the 'select' statement, but that has the potential to break defconfig files. Signed-off-by: Arnd Bergmann Fixes: 411dd19c682d ("usb: musb: Kconfig: Select the DMA driver if DMA mode of MUSB is enabled") Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 1f2037b..45c83ba 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -159,7 +159,7 @@ config USB_TI_CPPI_DMA config USB_TI_CPPI41_DMA bool 'TI CPPI 4.1 (AM335x)' - depends on ARCH_OMAP + depends on ARCH_OMAP && DMADEVICES select TI_CPPI41 config USB_TUSB_OMAP_DMA -- cgit v0.10.2 From 7fe9a937d5156761cf79dc354f616c726b5c09e2 Mon Sep 17 00:00:00 2001 From: Daniel Walter Date: Wed, 18 Nov 2015 17:15:49 +0100 Subject: usb: gadget: functionfs: fix missing access_ok checks use safe copy_*_user instead of unsafe __copy_*_user functions when accessing userland memory. Signed-off-by: Daniel Walter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index adc6d52..cf43e9e 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -423,7 +423,7 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, spin_unlock_irq(&ffs->ev.waitq.lock); mutex_unlock(&ffs->mutex); - return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size; + return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size; } static ssize_t ffs_ep0_read(struct file *file, char __user *buf, @@ -513,7 +513,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, /* unlocks spinlock */ ret = __ffs_ep0_queue_wait(ffs, data, len); - if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len))) + if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len))) ret = -EFAULT; goto done_mutex; @@ -3493,7 +3493,7 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) if (unlikely(!data)) return ERR_PTR(-ENOMEM); - if (unlikely(__copy_from_user(data, buf, len))) { + if (unlikely(copy_from_user(data, buf, len))) { kfree(data); return ERR_PTR(-EFAULT); } -- cgit v0.10.2 From 206b49500df558dbc15d8836b09f6397ec5ed8bb Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 18 Nov 2015 16:40:19 +0100 Subject: net/ip6_tunnel: fix dst leak the commit cdf3464e6c6b ("ipv6: Fix dst_entry refcnt bugs in ip6_tunnel") introduced percpu storage for ip6_tunnel dst cache, but while clearing such cache it used raw_cpu_ptr to walk the per cpu entries, so cached dst on non current cpu are not actually reset. This patch replaces raw_cpu_ptr with per_cpu_ptr, properly cleaning such storage. Fixes: cdf3464e6c6b ("ipv6: Fix dst_entry refcnt bugs in ip6_tunnel") Signed-off-by: Paolo Abeni Acked-by: Martin KaFai Lau Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index eabffbb..137fca4 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -177,7 +177,7 @@ void ip6_tnl_dst_reset(struct ip6_tnl *t) int i; for_each_possible_cpu(i) - ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), NULL); + ip6_tnl_per_cpu_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); } EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset); -- cgit v0.10.2 From 451c2b5caf37b526ae34a1081b71115e1de2d063 Mon Sep 17 00:00:00 2001 From: Aya Mahfouz Date: Wed, 18 Nov 2015 08:36:44 +0200 Subject: net: dns_resolver: convert time_t to time64_t Changes the definition of the pointer _expiry from time_t to time64_t. This is to handle the Y2038 problem where time_t will overflow in the year 2038. The change is safe because the kernel subsystems that call dns_query pass NULL. Signed-off-by: Arnd Bergmann Signed-off-by: Aya Mahfouz Signed-off-by: David S. Miller diff --git a/include/linux/dns_resolver.h b/include/linux/dns_resolver.h index cc92268..6ac3cad 100644 --- a/include/linux/dns_resolver.h +++ b/include/linux/dns_resolver.h @@ -27,7 +27,7 @@ #ifdef __KERNEL__ extern int dns_query(const char *type, const char *name, size_t namelen, - const char *options, char **_result, time_t *_expiry); + const char *options, char **_result, time64_t *_expiry); #endif /* KERNEL */ diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 4677b6f..ecc28cf 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -67,7 +67,7 @@ * Returns the size of the result on success, -ve error code otherwise. */ int dns_query(const char *type, const char *name, size_t namelen, - const char *options, char **_result, time_t *_expiry) + const char *options, char **_result, time64_t *_expiry) { struct key *rkey; const struct user_key_payload *upayload; -- cgit v0.10.2 From 2ce47b44b25d8fb0114ff117813742adbefec8ff Mon Sep 17 00:00:00 2001 From: Bamvor Jian Zhang Date: Fri, 13 Nov 2015 11:17:51 +0800 Subject: selftests/seccomp: Get page size from sysconf The commit fd88d16c58c2 ("selftests/seccomp: Be more precise with syscall arguments.") use PAGE_SIZE directly which lead to build failure on arm64. Replace it with generic interface(sysconf(_SC_PAGESIZE)) to fix this failure. Build and test successful on x86_64 and arm64. Signed-off-by: Bamvor Jian Zhang Acked-by: Kees Cook Tested-by: Michael Ellerman Signed-off-by: Shuah Khan diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index e38cc54..882fe83 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -492,6 +492,9 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) pid_t parent = getppid(); int fd; void *map1, *map2; + int page_size = sysconf(_SC_PAGESIZE); + + ASSERT_LT(0, page_size); ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); ASSERT_EQ(0, ret); @@ -504,16 +507,16 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) EXPECT_EQ(parent, syscall(__NR_getppid)); map1 = (void *)syscall(sysno, - NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, PAGE_SIZE); + NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size); EXPECT_NE(MAP_FAILED, map1); /* mmap2() should never return. */ map2 = (void *)syscall(sysno, - NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE); + NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE); EXPECT_EQ(MAP_FAILED, map2); /* The test failed, so clean up the resources. */ - munmap(map1, PAGE_SIZE); - munmap(map2, PAGE_SIZE); + munmap(map1, page_size); + munmap(map2, page_size); close(fd); } -- cgit v0.10.2 From f66541ba02d5cb619b84fa4c5b43b3bcc8764716 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 17 Nov 2015 11:56:44 +0200 Subject: clk: gpio: Get parent clk names in of_gpio_clk_setup() Get parent clk names in of_gpio_clk_setup() and store the names in struct clk_gpio_delayed_register_data instead of doing it from the clk provider's get() callback. of_clk_get_parent_name() can't be called in struct of_clk_provider's get() callback since it may make a call to of_clk_get_from_provider() and this in turn tries to recursively lock of_clk_mutex. Signed-off-by: Jyri Sarha Cc: Sergej Sawazki Fixes: 0a4807c2f9a4 ("clk: Make of_clk_get_parent_name() robust with #clock-cells = 1") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 10819e2..335322d 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -209,6 +209,8 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_mux); struct clk_gpio_delayed_register_data { const char *gpio_name; + int num_parents; + const char **parent_names; struct device_node *node; struct mutex lock; struct clk *clk; @@ -222,8 +224,6 @@ static struct clk *of_clk_gpio_delayed_register_get( { struct clk_gpio_delayed_register_data *data = _data; struct clk *clk; - const char **parent_names; - int i, num_parents; int gpio; enum of_gpio_flags of_flags; @@ -248,26 +248,14 @@ static struct clk *of_clk_gpio_delayed_register_get( return ERR_PTR(gpio); } - num_parents = of_clk_get_parent_count(data->node); - - parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) { - clk = ERR_PTR(-ENOMEM); - goto out; - } - - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(data->node, i); - - clk = data->clk_register_get(data->node->name, parent_names, - num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + clk = data->clk_register_get(data->node->name, data->parent_names, + data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); if (IS_ERR(clk)) goto out; data->clk = clk; out: mutex_unlock(&data->lock); - kfree(parent_names); return clk; } @@ -296,11 +284,24 @@ static void __init of_gpio_clk_setup(struct device_node *node, unsigned gpio, bool active_low)) { struct clk_gpio_delayed_register_data *data; + const char **parent_names; + int i, num_parents; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return; + num_parents = of_clk_get_parent_count(node); + + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + data->num_parents = num_parents; + data->parent_names = parent_names; data->node = node; data->gpio_name = gpio_name; data->clk_register_get = clk_register_get; -- cgit v0.10.2 From 508dc0648ca8a2d305faee472cea5e0be579014f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 19 Nov 2015 01:39:51 +0300 Subject: ravb: fix WARNING in __free_irq() When the R8A7795 support was added to the driver, little attention was paid to the ravb_open() error path: free_irq() for the EMAC interrupt was called uncoditionally, unlike request_irq(), and in a wrong order as well... As a result, on the R-Car gen2 SoCs I started getting the following in case of a device opening error: WARNING: CPU: 0 PID: 1 at kernel/irq/manage.c:1448 __free_irq+0x8c/0x228() Trying to free already-free IRQ 0 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.0-rc1-dirty #1005 Hardware name: Generic R8A7791 (Flattened Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r6:c063cdd6 r5:00000009 r4:00000000 r3:00204140 [] (show_stack) from [] (dump_stack+0x74/0x90) [] (dump_stack) from [] (warn_slowpath_common+0x8c/0xb8) r4:ef04fd38 r3:c0714770 [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x38/0x40) r8:ee8ad800 r7:ef0030a0 r6:00000000 r5:00000000 r4:ef003040 [] (warn_slowpath_fmt) from [] (__free_irq+0x8c/0x228) r3:00000000 r2:c063ce9f [] (__free_irq) from [] (free_irq+0x70/0xa4) r10:0000016b r8:00000000 r7:00000000 r6:ee8ad800 r5:00000000 r4:ef003040 [] (free_irq) from [] (ravb_open+0x224/0x274) r7:fffffffe r6:00000000 r5:fffffffe r4:ee8ad800 [] (ravb_open) from [] (__dev_open+0x84/0x104) r7:ee8ad830 r6:c0566334 r5:00000000 r4:ee8ad800 [] (__dev_open) from [] (__dev_change_flags+0x94/0x13c) r7:00001002 r6:00000001 r5:00001003 r4:ee8ad800 [] (__dev_change_flags) from [] (dev_change_flags+0x20/0x50) r7:c072e6e0 r6:00000138 r5:00001002 r4:ee8ad800 [] (dev_change_flags) from [] (ip_auto_config+0x174/0xfb8) r8:00001002 r7:c072e6e0 r6:c0703344 r5:00000001 r4:ee8ad800 r3:00000101 [] (ip_auto_config) from [] (do_one_initcall+0x100/0x1cc) r10:c06fb83c r9:00000000 r8:c06ebef8 r7:c0736000 r6:c0710918 r5:c0710918 r4:ef2f8f80 [] (do_one_initcall) from [] (kernel_init_freeable+0x11c/0x1 ec) r10:c06fb83c r9:00000000 r8:0000009a r7:c0736000 r6:c0706bf0 r5:c06fb834 r4:00000007 [] (kernel_init_freeable) from [] (kernel_init+0x14/0xec) r10:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0514c40 r4:c0736000 [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) r4:00000000 r3:ef04e000 Fix up the free_irq() call order and add a new label on the error path. Fixes: 22d4df8ff3a3 ("ravb: Add support for r8a7795 SoC") Signed-off-by: Sergei Shtylyov Acked-by: Simon Horman Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index ee8d1ec..ed5da4d 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1225,7 +1225,7 @@ static int ravb_open(struct net_device *ndev) /* Device init */ error = ravb_dmac_init(ndev); if (error) - goto out_free_irq; + goto out_free_irq2; ravb_emac_init(ndev); /* Initialise PTP Clock driver */ @@ -1243,9 +1243,11 @@ static int ravb_open(struct net_device *ndev) out_ptp_stop: /* Stop PTP Clock driver */ ravb_ptp_stop(ndev); +out_free_irq2: + if (priv->chip_id == RCAR_GEN3) + free_irq(priv->emac_irq, ndev); out_free_irq: free_irq(ndev->irq, ndev); - free_irq(priv->emac_irq, ndev); out_napi_off: napi_disable(&priv->napi[RAVB_NC]); napi_disable(&priv->napi[RAVB_BE]); -- cgit v0.10.2 From f4b16fce7a5a1ec8069b1f577476bdc1d2688cd1 Mon Sep 17 00:00:00 2001 From: Zi Shen Lim Date: Wed, 18 Nov 2015 00:56:02 -0800 Subject: arm64: bpf: fix buffer pointer During code review, I noticed we were passing a bad buffer pointer to bpf_load_pointer helper function called by jitted code. Point to the buffer allocated by JIT, so we don't silently corrupt other parts of the stack. Signed-off-by: Zi Shen Lim Acked-by: Yang Shi Signed-off-by: David S. Miller diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index d6a53ef..7cf032b 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -139,6 +139,12 @@ static inline int epilogue_offset(const struct jit_ctx *ctx) /* Stack must be multiples of 16B */ #define STACK_ALIGN(sz) (((sz) + 15) & ~15) +#define _STACK_SIZE \ + (MAX_BPF_STACK \ + + 4 /* extra for skb_copy_bits buffer */) + +#define STACK_SIZE STACK_ALIGN(_STACK_SIZE) + static void build_prologue(struct jit_ctx *ctx) { const u8 r6 = bpf2a64[BPF_REG_6]; @@ -150,10 +156,6 @@ static void build_prologue(struct jit_ctx *ctx) const u8 rx = bpf2a64[BPF_REG_X]; const u8 tmp1 = bpf2a64[TMP_REG_1]; const u8 tmp2 = bpf2a64[TMP_REG_2]; - int stack_size = MAX_BPF_STACK; - - stack_size += 4; /* extra for skb_copy_bits buffer */ - stack_size = STACK_ALIGN(stack_size); /* * BPF prog stack layout @@ -165,12 +167,13 @@ static void build_prologue(struct jit_ctx *ctx) * | ... | callee saved registers * +-----+ * | | x25/x26 - * BPF fp register => -80:+-----+ + * BPF fp register => -80:+-----+ <= (BPF_FP) * | | * | ... | BPF prog stack * | | - * | | - * current A64_SP => +-----+ + * +-----+ <= (BPF_FP - MAX_BPF_STACK) + * |RSVD | JIT scratchpad + * current A64_SP => +-----+ <= (BPF_FP - STACK_SIZE) * | | * | ... | Function call stack * | | @@ -196,7 +199,7 @@ static void build_prologue(struct jit_ctx *ctx) emit(A64_MOV(1, fp, A64_SP), ctx); /* Set up function call stack */ - emit(A64_SUB_I(1, A64_SP, A64_SP, stack_size), ctx); + emit(A64_SUB_I(1, A64_SP, A64_SP, STACK_SIZE), ctx); /* Clear registers A and X */ emit_a64_mov_i64(ra, 0, ctx); @@ -213,13 +216,9 @@ static void build_epilogue(struct jit_ctx *ctx) const u8 fp = bpf2a64[BPF_REG_FP]; const u8 tmp1 = bpf2a64[TMP_REG_1]; const u8 tmp2 = bpf2a64[TMP_REG_2]; - int stack_size = MAX_BPF_STACK; - - stack_size += 4; /* extra for skb_copy_bits buffer */ - stack_size = STACK_ALIGN(stack_size); /* We're done with BPF stack */ - emit(A64_ADD_I(1, A64_SP, A64_SP, stack_size), ctx); + emit(A64_ADD_I(1, A64_SP, A64_SP, STACK_SIZE), ctx); /* Restore fs (x25) and x26 */ emit(A64_POP(fp, A64_R(26), A64_SP), ctx); @@ -658,7 +657,7 @@ emit_cond_jmp: return -EINVAL; } emit_a64_mov_i64(r3, size, ctx); - emit(A64_ADD_I(1, r4, fp, MAX_BPF_STACK), ctx); + emit(A64_SUB_I(1, r4, fp, STACK_SIZE), ctx); emit_a64_mov_i64(r5, (unsigned long)bpf_load_pointer, ctx); emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); emit(A64_MOV(1, A64_FP, A64_SP), ctx); -- cgit v0.10.2 From 68242a5a1e2edce39b069385cbafb82304eac0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 18 Nov 2015 21:13:07 +0100 Subject: net: qmi_wwan: add XS Stick W100-2 from 4G Systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thomas reports " 4gsystems sells two total different LTE-surfsticks under the same name. .. The newer version of XS Stick W100 is from "omega" .. Under windows the driver switches to the same ID, and uses MI03\6 for network and MI01\6 for modem. .. echo "1c9e 9b01" > /sys/bus/usb/drivers/qmi_wwan/new_id echo "1c9e 9b01" > /sys/bus/usb-serial/drivers/option1/new_id T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1c9e ProdID=9b01 Rev=02.32 S: Manufacturer=USB Modem S: Product=USB Modem S: SerialNumber= C: #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#= 4 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage Now all important things are there: wwp0s29f7u2i3 (net), ttyUSB2 (at), cdc-wdm0 (qmi), ttyUSB1 (at) There is also ttyUSB0, but it is not usable, at least not for at. The device works well with qmi and ModemManager-NetworkManager. " Reported-by: Thomas Schäfer Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 34799ea..9a5be8b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -725,6 +725,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ + {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */ {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */ {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */ {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */ -- cgit v0.10.2 From 1b8e6a01e19f001e9f93b39c32387961c91ed3cc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Nov 2015 12:40:13 -0800 Subject: tcp: md5: fix lockdep annotation When a passive TCP is created, we eventually call tcp_md5_do_add() with sk pointing to the child. It is not owner by the user yet (we will add this socket into listener accept queue a bit later anyway) But we do own the spinlock, so amend the lockdep annotation to avoid following splat : [ 8451.090932] net/ipv4/tcp_ipv4.c:923 suspicious rcu_dereference_protected() usage! [ 8451.090932] [ 8451.090932] other info that might help us debug this: [ 8451.090932] [ 8451.090934] [ 8451.090934] rcu_scheduler_active = 1, debug_locks = 1 [ 8451.090936] 3 locks held by socket_sockopt_/214795: [ 8451.090936] #0: (rcu_read_lock){.+.+..}, at: [] __netif_receive_skb_core+0x151/0xe90 [ 8451.090947] #1: (rcu_read_lock){.+.+..}, at: [] ip_local_deliver_finish+0x43/0x2b0 [ 8451.090952] #2: (slock-AF_INET){+.-...}, at: [] sk_clone_lock+0x1c5/0x500 [ 8451.090958] [ 8451.090958] stack backtrace: [ 8451.090960] CPU: 7 PID: 214795 Comm: socket_sockopt_ [ 8451.091215] Call Trace: [ 8451.091216] [] dump_stack+0x55/0x76 [ 8451.091229] [] lockdep_rcu_suspicious+0xeb/0x110 [ 8451.091235] [] tcp_md5_do_add+0x1bf/0x1e0 [ 8451.091239] [] tcp_v4_syn_recv_sock+0x1f1/0x4c0 [ 8451.091242] [] ? tcp_v4_md5_hash_skb+0x167/0x190 [ 8451.091246] [] tcp_check_req+0x3c8/0x500 [ 8451.091249] [] ? tcp_v4_inbound_md5_hash+0x11e/0x190 [ 8451.091253] [] tcp_v4_rcv+0x3c0/0x9f0 [ 8451.091256] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091260] [] ip_local_deliver_finish+0xb6/0x2b0 [ 8451.091263] [] ? ip_local_deliver_finish+0x43/0x2b0 [ 8451.091267] [] ip_local_deliver+0x48/0x80 [ 8451.091270] [] ip_rcv_finish+0x160/0x700 [ 8451.091273] [] ip_rcv+0x29e/0x3d0 [ 8451.091277] [] __netif_receive_skb_core+0xb47/0xe90 Fixes: a8afca0329988 ("tcp: md5: protects md5sig_info with RCU") Signed-off-by: Eric Dumazet Reported-by: Willem de Bruijn Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ba09016..db00343 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -921,7 +921,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, } md5sig = rcu_dereference_protected(tp->md5sig_info, - sock_owned_by_user(sk)); + sock_owned_by_user(sk) || + lockdep_is_held(&sk->sk_lock.slock)); if (!md5sig) { md5sig = kmalloc(sizeof(*md5sig), gfp); if (!md5sig) -- cgit v0.10.2 From 984926781122f034d5bc9962815d135b6c4a8e1d Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 11 Nov 2015 22:08:02 +0100 Subject: ARM: dts: rockchip: temporarily remove emmc hs200 speed from rk3288 minnie The eMMC of the minnie Chromebook doesn't like our current method of tuning and while there are solutions on the horizon, they still need investigating. Other Chromebooks tune just fine with the emmc, so simply disable tuning on Minnie for now. Signed-off-by: Heiko Stuebner diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts index 8fd8ef2..85f0373 100644 --- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts +++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts @@ -86,6 +86,10 @@ }; }; +&emmc { + /delete-property/mmc-hs200-1_8v; +}; + &gpio_keys { pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>; -- cgit v0.10.2 From 784359b824bf2b095b257eefcd9615a3c48f2d8a Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 23 Oct 2015 19:25:28 +0800 Subject: ARM: dts: rockchip: Add OTP gpio pinctrl to rk3288 tsadc node Add the "init" anf "sleep" pinctrl as the OTP gpio state. We need the OTP pin is gpio state before resetting the TSADC controller, since the tshut polarity will generate a high signal. "init" pinctrl property is defined by Doug's Patch[0]. Patch[0]: https://patchwork.kernel.org/patch/7454311/ Signed-off-by: Caesar Wang Reviewed-by: Douglas Anderson Signed-off-by: Heiko Stuebner diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 6a79c9c..04ea209 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -452,8 +452,10 @@ clock-names = "tsadc", "apb_pclk"; resets = <&cru SRST_TSADC>; reset-names = "tsadc-apb"; - pinctrl-names = "default"; - pinctrl-0 = <&otp_out>; + pinctrl-names = "init", "default", "sleep"; + pinctrl-0 = <&otp_gpio>; + pinctrl-1 = <&otp_out>; + pinctrl-2 = <&otp_gpio>; #thermal-sensor-cells = <1>; rockchip,hw-tshut-temp = <95000>; status = "disabled"; @@ -1395,6 +1397,10 @@ }; tsadc { + otp_gpio: otp-gpio { + rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>; + }; + otp_out: otp-out { rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>; }; -- cgit v0.10.2 From 5967c17b118a2bd1dd1d554cc4eee16233e52bec Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 6 Nov 2015 12:08:48 +0100 Subject: KVM: s390: enable SIMD only when no VCPUs were created We should never allow to enable/disable any facilities for the guest when other VCPUs were already created. kvm_arch_vcpu_(load|put) relies on SIMD not changing during runtime. If somebody would create and run VCPUs and then decides to enable SIMD, undefined behaviour could be possible (e.g. vector save area not being set up). Acked-by: Christian Borntraeger Acked-by: Cornelia Huck Signed-off-by: David Hildenbrand Signed-off-by: Christian Borntraeger Cc: stable@vger.kernel.org # 4.1+ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 8fe2f1c..8465892 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -342,12 +342,16 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) r = 0; break; case KVM_CAP_S390_VECTOR_REGISTERS: - if (MACHINE_HAS_VX) { + mutex_lock(&kvm->lock); + if (atomic_read(&kvm->online_vcpus)) { + r = -EBUSY; + } else if (MACHINE_HAS_VX) { set_kvm_facility(kvm->arch.model.fac->mask, 129); set_kvm_facility(kvm->arch.model.fac->list, 129); r = 0; } else r = -EINVAL; + mutex_unlock(&kvm->lock); VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s", r ? "(not available)" : "(success)"); break; -- cgit v0.10.2 From 03c02807e25ef0f44767f28e939efc2c5deb0f3d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 13 Nov 2015 13:31:58 +0100 Subject: KVM: s390: fix pfmf intercept handler The pfmf intercept handler should check if the EDAT 1 facility is installed in the guest, not if it is installed in the host. Signed-off-by: Heiko Carstens Signed-off-by: Christian Borntraeger diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 77191b8..d76b51c 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -660,7 +660,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) kvm_s390_get_regs_rre(vcpu, ®1, ®2); - if (!MACHINE_HAS_PFMF) + if (!test_kvm_facility(vcpu->kvm, 8)) return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) -- cgit v0.10.2 From 5442f0eadf2885453d5b2ed8c8592f32a3744f8e Mon Sep 17 00:00:00 2001 From: Helmut Klein Date: Wed, 11 Nov 2015 15:03:04 +0100 Subject: ARM: dts: Kirkwood: Fix QNAP TS219 power-off The "reg" entry in the "poweroff" section of "kirkwood-ts219.dtsi" addressed the wrong uart (0 = console). This patch changes the address to select uart 1, which is the uart connected to the pic microcontroller, which can switch the device off. Signed-off-by: Helmut Klein Signed-off-by: Andrew Lunn Fixes: 4350a47bbac3 ("ARM: Kirkwood: Make use of the QNAP Power off driver.") Signed-off-by: Gregory CLEMENT diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi index c56ab6b..0e46560 100644 --- a/arch/arm/boot/dts/kirkwood-ts219.dtsi +++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi @@ -40,7 +40,7 @@ }; poweroff@12100 { compatible = "qnap,power-off"; - reg = <0x12000 0x100>; + reg = <0x12100 0x100>; clocks = <&gate_clk 7>; }; spi@10600 { -- cgit v0.10.2 From 4389559980599ad99f39a004d6e9aaf9c2180ab8 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 6 Nov 2015 11:08:02 +0100 Subject: drm/imx: switch to universal planes Use drm_universal_plane_init to create the planes, create the primary plane first and use drm_crtc_init_with_planes to associate it with the crtc. This gets rid of the unused fallback primary plane previously created by drm_crtc_init and fixes a NULL pointer dereference issue that can be triggered by a modeset from userspace when fbdev helpers are enabled [1]. [1] https://lkml.org/lkml/2015/11/4/107 Reported-by: Liu Ying Signed-off-by: Philipp Zabel Acked-by: Liu Ying diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 64f16ea..7b00ab8 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -340,7 +340,7 @@ err_kms: * imx_drm_add_crtc - add a new crtc */ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, - struct imx_drm_crtc **new_crtc, + struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, struct device_node *port) { @@ -379,7 +379,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, drm_crtc_helper_add(crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); - drm_crtc_init(drm, crtc, + drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); return 0; diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 28e776d..83284b4 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -9,6 +9,7 @@ struct drm_display_mode; struct drm_encoder; struct drm_fbdev_cma; struct drm_framebuffer; +struct drm_plane; struct imx_drm_crtc; struct platform_device; @@ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs { }; int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, - struct imx_drm_crtc **new_crtc, + struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, struct device_node *port); int imx_drm_remove_crtc(struct imx_drm_crtc *); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 7bc8301..f11284d 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -349,7 +349,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); int dp = -EINVAL; int ret; - int id; ret = ipu_get_resources(ipu_crtc, pdata); if (ret) { @@ -358,18 +357,19 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, return ret; } + if (pdata->dp >= 0) + dp = IPU_DP_FLOW_SYNC_BG; + ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0, + DRM_PLANE_TYPE_PRIMARY); + ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, - &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); + &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs, + ipu_crtc->dev->of_node); if (ret) { dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); goto err_put_resources; } - if (pdata->dp >= 0) - dp = IPU_DP_FLOW_SYNC_BG; - id = imx_drm_crtc_id(ipu_crtc->imx_crtc); - ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu, - pdata->dma[0], dp, BIT(id), true); ret = ipu_plane_get_resources(ipu_crtc->plane[0]); if (ret) { dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", @@ -379,10 +379,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, /* If this crtc is using the DP, add an overlay plane */ if (pdata->dp >= 0 && pdata->dma[1] > 0) { - ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu, - pdata->dma[1], - IPU_DP_FLOW_SYNC_FG, - BIT(id), false); + ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1], + IPU_DP_FLOW_SYNC_FG, + drm_crtc_mask(&ipu_crtc->base), + DRM_PLANE_TYPE_OVERLAY); if (IS_ERR(ipu_crtc->plane[1])) ipu_crtc->plane[1] = NULL; } diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 575f4c8..e2ff410 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = { struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, int dma, int dp, unsigned int possible_crtcs, - bool priv) + enum drm_plane_type type) { struct ipu_plane *ipu_plane; int ret; @@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs, - &ipu_plane_funcs, ipu_plane_formats, - ARRAY_SIZE(ipu_plane_formats), - priv); + ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs, + &ipu_plane_funcs, ipu_plane_formats, + ARRAY_SIZE(ipu_plane_formats), type); if (ret) { DRM_ERROR("failed to initialize plane\n"); kfree(ipu_plane); diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index 9b5eff1..3a443b4 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h @@ -34,7 +34,7 @@ struct ipu_plane { struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, int dma, int dp, unsigned int possible_crtcs, - bool priv); + enum drm_plane_type type); /* Init IDMAC, DMFC, DP */ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, -- cgit v0.10.2 From a7ed3c2b151e7581ed6022d0fe65903ccb502dc5 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Fri, 6 Nov 2015 22:42:45 +0800 Subject: drm/imx: ipuv3-crtc: Return error if ipu_plane_init() fails for primary plane For primary plane initialization failure cases, ipu_plane_init() may return a pointer encoded by ERR_PTR(). So, we should bailout instead of using that pointer blindly. Signed-off-by: Liu Ying Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index f11284d..4cbc3df 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -361,6 +361,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, dp = IPU_DP_FLOW_SYNC_BG; ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0, DRM_PLANE_TYPE_PRIMARY); + if (IS_ERR(ipu_crtc->plane[0])) { + ret = PTR_ERR(ipu_crtc->plane[0]); + goto err_put_resources; + } ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs, -- cgit v0.10.2 From db27a7a37aa0b1f8b373f8b0fb72a2ccaafb85b7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Nov 2015 09:03:50 +0100 Subject: KVM: Provide function for VCPU lookup by id Let's provide a function to lookup a VCPU by id. Reviewed-by: Christian Borntraeger Reviewed-by: Dominik Dingel Signed-off-by: David Hildenbrand Signed-off-by: Christian Borntraeger [split patch from refactoring patch] diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5706a21..c923350 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -460,6 +460,17 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) (vcpup = kvm_get_vcpu(kvm, idx)) != NULL; \ idx++) +static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) +{ + struct kvm_vcpu *vcpu; + int i; + + kvm_for_each_vcpu(i, vcpu, kvm) + if (vcpu->vcpu_id == id) + return vcpu; + return NULL; +} + #define kvm_for_each_memslot(memslot, slots) \ for (memslot = &slots->memslots[0]; \ memslot < slots->memslots + KVM_MEM_SLOTS_NUM && memslot->npages;\ -- cgit v0.10.2 From b85de33a1a3433487b6a721cfdce25ec8673e622 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Nov 2015 09:38:15 +0100 Subject: KVM: s390: avoid memory overwrites on emergency signal injection Commit 383d0b050106 ("KVM: s390: handle pending local interrupts via bitmap") introduced a possible memory overwrite from user space. User space could pass an invalid emergency signal code (sending VCPU) and therefore exceed the bitmap. Let's take care of this case and check that the id is in the valid range. Reviewed-by: Dominik Dingel Cc: stable@vger.kernel.org # v3.19+ db27a7a KVM: Provide function for VCPU lookup by id Signed-off-by: David Hildenbrand Signed-off-by: Christian Borntraeger diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 373e323..7242c2d 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -1110,6 +1110,10 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY, irq->u.emerg.code, 0); + /* sending vcpu invalid */ + if (kvm_get_vcpu_by_id(vcpu->kvm, irq->u.emerg.code) == NULL) + return -EINVAL; + set_bit(irq->u.emerg.code, li->sigp_emerg_pending); set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); atomic_or(CPUSTAT_EXT_INT, li->cpuflags); -- cgit v0.10.2 From 152e9f65d66f0a3891efc3869440becc0e7ff53f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 5 Nov 2015 09:06:06 +0100 Subject: KVM: s390: fix wrong lookup of VCPUs by array index For now, VCPUs were always created sequentially with incrementing VCPU ids. Therefore, the index in the VCPUs array matched the id. As sequential creation might change with cpu hotplug, let's use the correct lookup function to find a VCPU by id, not array index. Let's also use kvm_lookup_vcpu() for validation of the sending VCPU on external call injection. Reviewed-by: Christian Borntraeger Signed-off-by: David Hildenbrand Signed-off-by: Christian Borntraeger Cc: stable@vger.kernel.org # db27a7a KVM: Provide function for VCPU lookup by id diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 7242c2d..6a75352 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -1030,8 +1030,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) src_id, 0); /* sending vcpu invalid */ - if (src_id >= KVM_MAX_VCPUS || - kvm_get_vcpu(vcpu->kvm, src_id) == NULL) + if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL) return -EINVAL; if (sclp.has_sigpif) diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index da690b6..77c22d6 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -291,12 +291,8 @@ static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code, u16 cpu_addr, u32 parameter, u64 *status_reg) { int rc; - struct kvm_vcpu *dst_vcpu; + struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr); - if (cpu_addr >= KVM_MAX_VCPUS) - return SIGP_CC_NOT_OPERATIONAL; - - dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); if (!dst_vcpu) return SIGP_CC_NOT_OPERATIONAL; @@ -478,7 +474,7 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu) trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr); if (order_code == SIGP_EXTERNAL_CALL) { - dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); + dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr); BUG_ON(dest_vcpu == NULL); kvm_s390_vcpu_wakeup(dest_vcpu); -- cgit v0.10.2 From ca1ef9ceb0d1b2b41586e422c08976f8e7a8714f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 3 Nov 2015 14:05:57 +0100 Subject: ARM: pxa: palm: Fix typos in PWM lookup table code The patches that were applied to add PWM lookup tables for legacy boards were from v1 of the series instead of the revised v2 where the resulting build errors had already been fixed. Reported-by: Arnd Bergmann Signed-off-by: Thierry Reding Signed-off-by: Arnd Bergmann diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c index 13eba2b..8fbfb10 100644 --- a/arch/arm/mach-pxa/palm27x.c +++ b/arch/arm/mach-pxa/palm27x.c @@ -344,7 +344,7 @@ void __init palm27x_pwm_init(int bl, int lcd) { palm_bl_power = bl; palm_lcd_power = lcd; - pwm_add_lookup(palm27x_pwm_lookup, ARRAY_SIZE(palm27x_pwm_lookup)); + pwm_add_table(palm27x_pwm_lookup, ARRAY_SIZE(palm27x_pwm_lookup)); platform_device_register(&palm27x_backlight); } #endif diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index aebf6de..0b5c387 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -169,7 +169,7 @@ static inline void palmtc_keys_init(void) {} #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE) static struct pwm_lookup palmtc_pwm_lookup[] = { PWM_LOOKUP("pxa25x-pwm.1", 0, "pwm-backlight.0", NULL, PALMTC_PERIOD_NS, - PWM_PERIOD_NORMAL), + PWM_POLARITY_NORMAL), }; static struct platform_pwm_backlight_data palmtc_backlight_data = { -- cgit v0.10.2 From a203a2a9ec34936277fa22d6e07ca1f859165205 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 18:01:19 +0100 Subject: ARM: zx: only build power domain code when CONFIG_PM=y The newly added zx power domain code causes build errors in some configurations: warning: (PM_RMOBILE && SOC_ZX296702) selects PM_GENERIC_DOMAINS which has unmet direct dependencies (PM) warning: (ARCH_EXYNOS) selects EXYNOS_THERMAL which has unmet direct dependencies (THERMAL && (ARCH_EXYNOS || COMPILE_TEST) && THERMAL_OF) power/domain.c: In function 'genpd_queue_power_off_work': power/domain.c:192:13: error: 'pm_wq' undeclared (first use in this function) queue_work(pm_wq, &genpd->power_off_work); ^ power/domain.c:192:13: note: each undeclared identifier is reported only once for each function it appears in This ensures we don't try to enable it when CONFIG_PM is disabled, mirroring what we do on most other platforms. Signed-off-by: Arnd Bergmann Fixes: f15107f41282 ("ARM: zx: Add power domains for ZX296702") Reviewed-by: Jun Nie diff --git a/arch/arm/mach-zx/Kconfig b/arch/arm/mach-zx/Kconfig index 7fdc5bf..446334a 100644 --- a/arch/arm/mach-zx/Kconfig +++ b/arch/arm/mach-zx/Kconfig @@ -13,7 +13,7 @@ config SOC_ZX296702 select ARM_GLOBAL_TIMER select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP - select PM_GENERIC_DOMAINS + select PM_GENERIC_DOMAINS if PM help Support for ZTE ZX296702 SoC which is a dual core CortexA9MP endif -- cgit v0.10.2 From 851df3dc11136fde86ebd78ee7527cb43c7cd349 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 22:34:58 +0100 Subject: scpi: hide get_scpi_ops in module from built-in code The scpi_clock driver can be built-in when CONFIG_COMPILE_TEST is set even when ARM_SCPI_PROTOCOL is a loadable module, and that results in a link error: drivers/built-in.o: In function `scpi_clocks_probe': (.text+0x14453c): undefined reference to `get_scpi_ops' Using #if IS_REACHABLE() around the get_scpi_ops() declaration makes it build successfully in this case for compile-testing, but the effect is the same as when ARM_SCPI_PROTOCOL is disabled, as the code will not be used. Signed-off-by: Arnd Bergmann Acked-by: Punit Agrawal diff --git a/include/linux/scpi_protocol.h b/include/linux/scpi_protocol.h index 80af3cd..72ce932 100644 --- a/include/linux/scpi_protocol.h +++ b/include/linux/scpi_protocol.h @@ -71,7 +71,7 @@ struct scpi_ops { int (*sensor_get_value)(u16, u32 *); }; -#if IS_ENABLED(CONFIG_ARM_SCPI_PROTOCOL) +#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL) struct scpi_ops *get_scpi_ops(void); #else static inline struct scpi_ops *get_scpi_ops(void) { return NULL; } -- cgit v0.10.2 From c87693da69f979f8a4370e7bc6115dd0898d8501 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 19 Nov 2015 23:25:12 +0800 Subject: ALSA: hda - add PCI IDs for Intel Broxton Add HD Audio Device PCI ID for the Intel Broxton platform. It is an HDA Intel PCH controller. Signed-off-by: Lu, Han Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4d2cbe2..10fa743 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -312,6 +312,10 @@ enum { (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ AZX_DCAPS_I915_POWERWELL) +#define AZX_DCAPS_INTEL_BROXTON \ + (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\ + AZX_DCAPS_I915_POWERWELL) + /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\ @@ -2125,6 +2129,9 @@ static const struct pci_device_id azx_ids[] = { /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + /* Broxton-P(Apollolake) */ + { PCI_DEVICE(0x8086, 0x5a98), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, -- cgit v0.10.2 From ff9d8859e2d4e47c2d5537e309b49cf1f2ed1ddc Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 19 Nov 2015 23:25:13 +0800 Subject: ALSA: hda - apply SKL display power request/release patch to BXT For SKL, only the HDMI codec is in the display power well while the HD-A controller isn't. So the codec flag 'link_power_control' is set to request/release the display power via bus link_power ops. For BXT, the power well design is the same as SKL, so the patch should be applied to BXT too. Signed-off-by: Lu, Han Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 60cd9e7..bdb6f22 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2378,7 +2378,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) * can cover the codec power request, and so need not set this flag. * For previous platforms, there is no such power well feature. */ - if (is_valleyview_plus(codec) || is_skylake(codec)) + if (is_valleyview_plus(codec) || is_skylake(codec) || + is_broxton(codec)) codec->core.link_power_control = 1; if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { -- cgit v0.10.2 From b9c2fa52135d49a931c56ed2bfc17d61f771b412 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Nov 2015 16:39:50 +0100 Subject: ALSA: hda - Add fixup for Acer Aspire One Cloudbook 14 For making the speakers on Acer Aspire One Cloudbook 14 to work, we need the as same quirk as for another Chromebook. This patch adds the corresponding fixup entry. Reported-by: Patrick Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 081ef9b..53f6a02 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5180,6 +5180,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), -- cgit v0.10.2 From a35bb4458e5e5c9dc19a0daa0629409285f3b25e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 19 Nov 2015 14:17:06 +0100 Subject: scsi: report 'INQUIRY result too short' once per host Some host adapters (e.g. Hyper-V storvsc) are known for not respecting the SPC-2/3/4 requirement for 'INQUIRY data (see table ...) shall contain at least 36 bytes'. As a result we get tons on 'scsi 0:7:1:1: scsi scan: INQUIRY result too short (5), using 36' messages on console. This can be problematic for slow consoles. Introduce short_inquiry flag in struct Scsi_Host to print the message once per host. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index d01e423..403a633 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -702,9 +702,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * strings. */ if (sdev->inquiry_len < 36) { - sdev_printk(KERN_INFO, sdev, - "scsi scan: INQUIRY result too short (%d)," - " using 36\n", sdev->inquiry_len); + if (!sdev->host->short_inquiry) { + shost_printk(KERN_INFO, sdev->host, + "scsi scan: INQUIRY result too short (%d)," + " using 36\n", sdev->inquiry_len); + sdev->host->short_inquiry = 1; + } sdev->inquiry_len = 36; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index e113c75..3a22da7 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -673,6 +673,9 @@ struct Scsi_Host { unsigned use_blk_mq:1; unsigned use_cmd_list:1; + /* Host responded with short (<36 bytes) INQUIRY result */ + unsigned short_inquiry:1; + /* * Optional work queue to be utilized by the transport */ -- cgit v0.10.2 From ab08ee14393724ab52b92be643d588d41a1a05be Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Wed, 18 Nov 2015 15:32:44 +0100 Subject: st: fix potential null pointer dereference. If cdev_add() returns an error, the code calls cdev_del() passing the STm->cdevs[rew] pointer as parameter; the problem is that the pointer has not been initialized yet. This patch fixes the problem by moving the STm->cdevs[rew] pointer initialization before the call to cdev_add(). It also sets STm->devs[rew] and STm->cdevs[rew] to NULL in case of failure. Signed-off-by: Maurizio Lombardi Reviewed-by: Johannes Thumshirn Reviewed-by: Tomas Henzl Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b37b9b0..3e79c80 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4083,6 +4083,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) } cdev->owner = THIS_MODULE; cdev->ops = &st_fops; + STm->cdevs[rew] = cdev; error = cdev_add(cdev, cdev_devno, 1); if (error) { @@ -4091,7 +4092,6 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) pr_err("st%d: Device not attached.\n", dev_num); goto out_free; } - STm->cdevs[rew] = cdev; i = mode << (4 - ST_NBR_MODE_BITS); snprintf(name, 10, "%s%s%s", rew ? "n" : "", @@ -4110,8 +4110,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) return 0; out_free: cdev_del(STm->cdevs[rew]); - STm->cdevs[rew] = NULL; out: + STm->cdevs[rew] = NULL; + STm->devs[rew] = NULL; return error; } -- cgit v0.10.2 From be821fd8e62765de43cc4f0e2db363d0e30a7e9b Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 19 Nov 2015 14:02:19 +0100 Subject: scsi_sysfs: protect against double execution of __scsi_remove_device() On some host errors storvsc module tries to remove sdev by scheduling a job which does the following: sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); } While this code seems correct the following crash is observed: general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC RIP: 0010:[] [] bdi_destroy+0x39/0x220 ... [] ? _raw_spin_unlock_irq+0x2c/0x40 [] blk_cleanup_queue+0x17b/0x270 [] __scsi_remove_device+0x54/0xd0 [scsi_mod] [] scsi_remove_device+0x2b/0x40 [scsi_mod] [] storvsc_remove_lun+0x3d/0x60 [hv_storvsc] [] process_one_work+0x1b1/0x530 ... The problem comes with the fact that many such jobs (for the same device) are being scheduled simultaneously. While scsi_remove_device() uses shost->scan_mutex and scsi_device_lookup() will fail for a device in SDEV_DEL state there is no protection against someone who did scsi_device_lookup() before we actually entered __scsi_remove_device(). So the whole scenario looks like that: two callers do simultaneous (or preemption happens) calls to scsi_device_lookup() ant these calls succeed for both of them, after that they try doing scsi_remove_device(). shost->scan_mutex only serializes their calls to __scsi_remove_device() and we end up doing the cleanup path twice. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8b7fa8a..ed91828 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1100,6 +1100,14 @@ void __scsi_remove_device(struct scsi_device *sdev) { struct device *dev = &sdev->sdev_gendev; + /* + * This cleanup path is not reentrant and while it is impossible + * to get a new reference with scsi_device_get() someone can still + * hold a previously acquired one. + */ + if (sdev->sdev_state == SDEV_DEL) + return; + if (sdev->is_visible) { if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) return; -- cgit v0.10.2 From cd3ed08a86e8b5022f107aa72a1929b6417c1f42 Mon Sep 17 00:00:00 2001 From: Moise Gergaud Date: Thu, 19 Nov 2015 14:54:07 +0100 Subject: ASoC: sti: remove wrong error message Signed-off-by: Moise Gergaud Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index f791239..819eeaf 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -346,7 +346,6 @@ int uni_reader_init(struct platform_device *pdev, 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"); -- cgit v0.10.2 From f9f51973d3a8559731a228e91ac29792b43046a5 Mon Sep 17 00:00:00 2001 From: Moise Gergaud Date: Thu, 19 Nov 2015 14:54:08 +0100 Subject: ASoC: sti: rename ST proprietary DT properties "st," prefix has been added for ST proprietary DT properties. Signed-off-by: Moise Gergaud 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 843f037..1e19a7c 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -989,7 +989,7 @@ static int uni_player_parse_dt(struct platform_device *pdev, if (!info) return -ENOMEM; - if (of_property_read_u32(pnode, "version", &player->ver) || + if (of_property_read_u32(pnode, "st,version", &player->ver) || player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { dev_err(dev, "Unknown uniperipheral version "); return -EINVAL; @@ -998,13 +998,13 @@ static int uni_player_parse_dt(struct platform_device *pdev, if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) info->underflow_enabled = 1; - if (of_property_read_u32(pnode, "uniperiph-id", &info->id)) { + if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) { dev_err(dev, "uniperipheral id not defined"); return -EINVAL; } /* Read the device mode property */ - if (of_property_read_string(pnode, "mode", &mode)) { + if (of_property_read_string(pnode, "st,mode", &mode)) { dev_err(dev, "uniperipheral mode not defined"); return -EINVAL; } diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 819eeaf..8a0eb20 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -316,7 +316,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, if (!info) return -ENOMEM; - if (of_property_read_u32(node, "version", &reader->ver) || + if (of_property_read_u32(node, "st,version", &reader->ver) || reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { dev_err(&pdev->dev, "Unknown uniperipheral version "); return -EINVAL; -- cgit v0.10.2 From 36a65e2072625556191c6c616d65ed4f67f4f0d0 Mon Sep 17 00:00:00 2001 From: Moise Gergaud Date: Thu, 19 Nov 2015 14:54:09 +0100 Subject: ASoC: sti: set player private data Set substream player private data. substream player private data is used in uni_player_irq_handler to lock, stop & unlock the stream when interrupt indicates underflow/overflow. If not set, then segmentation fault occurs. Signed-off-by: Moise Gergaud 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 1e19a7c..5c2bc53 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -669,6 +669,7 @@ static int uni_player_startup(struct snd_pcm_substream *substream, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + player->substream = substream; player->clk_adj = 0; @@ -950,6 +951,8 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, if (player->state != UNIPERIF_STATE_STOPPED) /* Stop the player */ uni_player_stop(player); + + player->substream = NULL; } static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, -- cgit v0.10.2 From bcbd94ff481ec1d7b5c824d90df82d0faafabd35 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 19 Nov 2015 07:36:50 -0500 Subject: dm crypt: fix a possible hang due to race condition on exit A kernel thread executes __set_current_state(TASK_INTERRUPTIBLE), __add_wait_queue, spin_unlock_irq and then tests kthread_should_stop(). It is possible that the processor reorders memory accesses so that kthread_should_stop() is executed before __set_current_state(). If such reordering happens, there is a possible race on thread termination: CPU 0: calls kthread_should_stop() it tests KTHREAD_SHOULD_STOP bit, returns false CPU 1: calls kthread_stop(cc->write_thread) sets the KTHREAD_SHOULD_STOP bit calls wake_up_process on the kernel thread, that sets the thread state to TASK_RUNNING CPU 0: sets __set_current_state(TASK_INTERRUPTIBLE) spin_unlock_irq(&cc->write_thread_wait.lock) schedule() - and the process is stuck and never terminates, because the state is TASK_INTERRUPTIBLE and wake_up_process on CPU 1 already terminated Fix this race condition by using a new flag DM_CRYPT_EXIT_THREAD to signal that the kernel thread should exit. The flag is set and tested while holding cc->write_thread_wait.lock, so there is no possibility of racy access to the flag. Also, remove the unnecessary set_task_state(current, TASK_RUNNING) following the schedule() call. When the process was woken up, its state was already set to TASK_RUNNING. Other kernel code also doesn't set the state to TASK_RUNNING following schedule() (for example, do_wait_for_common in completion.c doesn't do it). Fixes: dc2676210c42 ("dm crypt: offload writes to thread") Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Mike Snitzer diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 917d47e..3147c8d 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -112,7 +112,8 @@ struct iv_tcw_private { * and encrypts / decrypts at the same time. */ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID, - DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD }; + DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD, + DM_CRYPT_EXIT_THREAD}; /* * The fields in here must be read only after initialization. @@ -1203,20 +1204,18 @@ continue_locked: if (!RB_EMPTY_ROOT(&cc->write_tree)) goto pop_from_list; + if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) { + spin_unlock_irq(&cc->write_thread_wait.lock); + break; + } + __set_current_state(TASK_INTERRUPTIBLE); __add_wait_queue(&cc->write_thread_wait, &wait); spin_unlock_irq(&cc->write_thread_wait.lock); - if (unlikely(kthread_should_stop())) { - set_task_state(current, TASK_RUNNING); - remove_wait_queue(&cc->write_thread_wait, &wait); - break; - } - schedule(); - set_task_state(current, TASK_RUNNING); spin_lock_irq(&cc->write_thread_wait.lock); __remove_wait_queue(&cc->write_thread_wait, &wait); goto continue_locked; @@ -1531,8 +1530,13 @@ static void crypt_dtr(struct dm_target *ti) if (!cc) return; - if (cc->write_thread) + if (cc->write_thread) { + spin_lock_irq(&cc->write_thread_wait.lock); + set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags); + wake_up_locked(&cc->write_thread_wait); + spin_unlock_irq(&cc->write_thread_wait.lock); kthread_stop(cc->write_thread); + } if (cc->io_queue) destroy_workqueue(cc->io_queue); -- cgit v0.10.2 From 6824c5ef5e8900e61ce8ed40885cacc1c9301c14 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 18 Nov 2015 16:33:08 -0700 Subject: NVMe: Fix possible arithmetic overflow for max segments Reported-by: Paul Grabinar Signed-off-by: Keith Busch Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 8187df2..394fd16 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2268,7 +2268,7 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid) if (dev->max_hw_sectors) { blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors); blk_queue_max_segments(ns->queue, - ((dev->max_hw_sectors << 9) / dev->page_size) + 1); + (dev->max_hw_sectors / (dev->page_size >> 9)) + 1); } if (dev->stripe_size) blk_queue_chunk_sectors(ns->queue, dev->stripe_size >> 9); -- cgit v0.10.2 From 391e6dcb37857d5659b53def2f41e2f56850d33c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 18 Nov 2015 17:06:00 -0600 Subject: usb: gadget: pxa27x: fix suspend callback pxa27x disconnects pullups on suspend but doesn't notify the gadget driver about it, so gadget driver can't disable the endpoints it was using. This causes problems on resume because gadget core will think endpoints are still enabled and just ignore the following usb_ep_enable(). Fix this problem by calling gadget_driver->disconnect(). Cc: # v3.10+ Tested-by: Robert Jarzmik Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 670ac0b..001a3b7 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2536,6 +2536,9 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) udc->pullup_resume = udc->pullup_on; dplus_pullup(udc, 0); + if (udc->driver) + udc->driver->disconnect(&udc->gadget); + return 0; } -- cgit v0.10.2 From ac722e302cc057a65cb1d975f8b17e8e11144946 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 19 Nov 2015 11:47:47 +0800 Subject: usb: kconfig: fix warning of select USB_OTG When choose randconfig for kernel build, it reports below warning: "warning: (USB_OTG_FSM && FSL_USB2_OTG && USB_MV_OTG) selects USB_OTG which has unmet direct dependencies (USB_SUPPORT && USB && PM)" In fact, USB_OTG is visible symbol and depends on PM, so the driver needs to depend on it to reduce dependency problem. Signed-off-by: Peter Chen Reported-by: Arnd Bergmann Cc: Felipe Balbi Acked-by: Arnd Bergmann Signed-off-by: Felipe Balbi diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index a99c89e..dd28010 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -77,8 +77,7 @@ config USB_OTG_BLACKLIST_HUB config USB_OTG_FSM tristate "USB 2.0 OTG FSM implementation" - depends on USB - select USB_OTG + depends on USB && USB_OTG select USB_PHY help Implements OTG Finite State Machine as specified in On-The-Go diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 1731324..22e8ecb 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -21,7 +21,6 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM - select USB_OTG select USB_PHY help Enable this to support Freescale USB OTG transceiver. @@ -168,8 +167,7 @@ config USB_QCOM_8X16_PHY config USB_MV_OTG tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && PM - select USB_OTG + depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever -- cgit v0.10.2 From c9eb29503e9655e70448bbbf3697d08a56d24854 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 18 Nov 2015 14:33:35 +0900 Subject: usb: renesas_usbhs: gadget: Fix NULL pointer dereference in usbhsg_ep_dequeue() This patch fixes an issue that NULL pointer dereference happens when a gadget driver calls usb_ep_dequeue() for ep0 after disconnected a usb cable. This is because that usbhsg_try_stop() will call usbhsg_ep_disable(&dcp->ep) when a usb cable is disconnected and the pipe of dcp (ep0) is set to NULL. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index de4f97d..8f7a78e 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -131,7 +131,8 @@ static void __usbhsg_queue_pop(struct usbhsg_uep *uep, struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); + if (pipe) + dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); ureq->req.status = status; spin_unlock(usbhs_priv_to_lock(priv)); @@ -685,7 +686,13 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); + if (pipe) + usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); + + /* + * To dequeue a request, this driver should call the usbhsg_queue_pop() + * even if the pipe is NULL. + */ usbhsg_queue_pop(uep, ureq, -ECONNRESET); return 0; -- cgit v0.10.2 From d0464bcf12af54bafe02dd23ac5bd75d825f9fdd Mon Sep 17 00:00:00 2001 From: John Youn Date: Fri, 13 Nov 2015 17:02:10 +0000 Subject: usb: dwc2: Make PHY optional Fixes commit 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") The above commit consolidated the low-level phy access into a common location. This change introduced a check from the gadget requiring that a PHY is specified. This requirement never existed on the host side and broke some platforms when it was moved into platform.c. The gadget doesn't require the PHY either so remove the check. Acked-by: Eric Anholt Reported-by: Stefan Wahren Cc: Marek Szyprowski Signed-off-by: John Youn Tested-by: Marek Szyprowski Fixes: 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index e61d773..60b12a4 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -229,11 +229,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) hsotg->phyif = GUSBCFG_PHYIF8; } - if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) { - dev_err(hsotg->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } - /* Clock */ hsotg->clk = devm_clk_get(hsotg->dev, "otg"); if (IS_ERR(hsotg->clk)) { -- cgit v0.10.2 From 6c2dad69163fdb4ea82344dcba360fc00b4adda4 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 13 Nov 2015 17:02:11 +0000 Subject: usb: dwc2: Return errors from PHY When searching for PHYs, any error was treated as if the PHY did not exist or was not specified. Thus the probe function did not correctly return error conditions such as -EPROBE_DEFER. Fixed so that only a non-existing PHY is ignored and any other error is returned. Acked-by: Eric Anholt Reported-by: Alexander Aring Signed-off-by: John Youn Signed-off-by: Stefan Wahren Tested-by: Marek Szyprowski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 60b12a4..d28f72e 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -212,14 +212,41 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) */ hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy"); if (IS_ERR(hsotg->phy)) { - hsotg->phy = NULL; + ret = PTR_ERR(hsotg->phy); + switch (ret) { + case -ENODEV: + case -ENOSYS: + hsotg->phy = NULL; + break; + case -EPROBE_DEFER: + return ret; + default: + dev_err(hsotg->dev, "error getting phy %d\n", ret); + return ret; + } + } + + if (!hsotg->phy) { hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); - if (IS_ERR(hsotg->uphy)) - hsotg->uphy = NULL; - else - hsotg->plat = dev_get_platdata(hsotg->dev); + if (IS_ERR(hsotg->uphy)) { + ret = PTR_ERR(hsotg->uphy); + switch (ret) { + case -ENODEV: + case -ENXIO: + hsotg->uphy = NULL; + break; + case -EPROBE_DEFER: + return ret; + default: + dev_err(hsotg->dev, "error getting usb phy %d\n", + ret); + return ret; + } + } } + hsotg->plat = dev_get_platdata(hsotg->dev); + if (hsotg->phy) { /* * If using the generic PHY framework, check if the PHY bus -- cgit v0.10.2 From 8aa90cf2a28645c6733f8879c5fe1848c5d510b7 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 13 Nov 2015 17:02:12 +0000 Subject: usb: dwc2: make otg clk optional Fixes commit 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") The above commit consolidated the low-level phy access into a common location. This change made the otg clk a requirement and broke some platforms when it was moved into platform.c. So make clk handling optional again. Acked-by: Eric Anholt Signed-off-by: Stefan Wahren Cc: Marek Szyprowski Acked-by: John Youn Tested-by: Marek Szyprowski Fixes: 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c") Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d28f72e..91e2e6b 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -125,9 +125,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (ret) return ret; - ret = clk_prepare_enable(hsotg->clk); - if (ret) - return ret; + if (hsotg->clk) { + ret = clk_prepare_enable(hsotg->clk); + if (ret) + return ret; + } if (hsotg->uphy) ret = usb_phy_init(hsotg->uphy); @@ -175,7 +177,8 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) if (ret) return ret; - clk_disable_unprepare(hsotg->clk); + if (hsotg->clk) + clk_disable_unprepare(hsotg->clk); ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); -- cgit v0.10.2 From e9ca7e4bb30cbf4c8d2e2e34681a967c10b3ff54 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 10 Nov 2015 17:52:03 +0000 Subject: usb: gadget: f_midi: Transmit data only when IN ep is enabled This makes sure f_midi doesn't try to enqueue data when the IN endpoint is disabled, ie, USB cable is disconnected. Reviewed-by: Robert Baldyga Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 42acb45..7877aa8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -545,7 +545,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) } } - if (req->length > 0) { + if (req->length > 0 && ep->enabled) { int err; err = usb_ep_queue(ep, req, GFP_ATOMIC); -- cgit v0.10.2 From ad0d1a058eac46503edbc510d1ce44c5df8e0c91 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 10 Nov 2015 17:52:06 +0000 Subject: usb: gadget: f_midi: fix leak on failed to enqueue out requests This patch fixes a memory leak that occurs when an endpoint fails to enqueue the request. If that happens the complete function will never be called, thus never freeing the request. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 7877aa8..898a570 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -370,6 +370,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (err) { ERROR(midi, "%s queue req: %d\n", midi->out_ep->name, err); + free_ep_req(midi->out_ep, req); } } -- cgit v0.10.2 From 5c256b68348e9717c8ba23521ef52ef7f69d4448 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 16 Sep 2015 15:52:33 +0800 Subject: usb: phy: mxs: add "fsl,imx6ul-usbphy" compatible string Add "fsl,imx6ul-usbphy" compatible string for iMX6ul usb phy Signed-off-by: Peter Chen Signed-off-by: Li Jun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index b7536af..c2936dc 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -143,12 +143,17 @@ static const struct mxs_phy_data imx6sx_phy_data = { .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS, }; +static const struct mxs_phy_data imx6ul_phy_data = { + .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS, +}; + static const struct of_device_id mxs_phy_dt_ids[] = { { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, }, { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, }, { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, }, { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, }, { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, }, + { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); -- cgit v0.10.2 From 6bb9535bc3f59194a0ae17b17ca71aecd0f7e3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Thu, 19 Nov 2015 12:50:08 +0100 Subject: null_blk: use ppa_cache pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using a page pool, we can save memory by only allocating room for 64 entries for the ppa command. Introduce a ppa_cache to allocate only the required memory for the ppa list. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 8165251..3e9c4f9 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -47,6 +47,7 @@ static LIST_HEAD(nullb_list); static struct mutex lock; static int null_major; static int nullb_indexes; +static struct kmem_cache *ppa_cache; struct completion_queue { struct llist_head list; @@ -521,7 +522,7 @@ static void *null_lnvm_create_dma_pool(struct request_queue *q, char *name) { mempool_t *virtmem_pool; - virtmem_pool = mempool_create_page_pool(64, 0); + virtmem_pool = mempool_create_slab_pool(64, ppa_cache); if (!virtmem_pool) { pr_err("null_blk: Unable to create virtual memory pool\n"); return NULL; @@ -767,6 +768,12 @@ static int __init null_init(void) bs = PAGE_SIZE; } + if (use_lightnvm && bs != 4096) { + pr_warn("null_blk: LightNVM only supports 4k block size\n"); + pr_warn("null_blk: defaults block size to 4k\n"); + bs = 4096; + } + if (use_lightnvm && queue_mode != NULL_Q_MQ) { pr_warn("null_blk: LightNVM only supported for blk-mq\n"); pr_warn("null_blk: defaults queue mode to blk-mq\n"); @@ -803,15 +810,27 @@ static int __init null_init(void) if (null_major < 0) return null_major; + if (use_lightnvm) { + ppa_cache = kmem_cache_create("ppa_cache", 64 * sizeof(u64), + 0, 0, NULL); + if (!ppa_cache) { + pr_err("null_blk: unable to create ppa cache\n"); + return -ENOMEM; + } + } + for (i = 0; i < nr_devices; i++) { if (null_add_dev()) { unregister_blkdev(null_major, "nullb"); - return -EINVAL; + goto err_ppa; } } pr_info("null: module loaded\n"); return 0; +err_ppa: + kmem_cache_destroy(ppa_cache); + return -EINVAL; } static void __exit null_exit(void) @@ -826,6 +845,8 @@ static void __exit null_exit(void) null_del_dev(nullb); } mutex_unlock(&lock); + + kmem_cache_destroy(ppa_cache); } module_init(null_init); -- cgit v0.10.2 From 5b40db99099ddebe31e9b1b759894cf09c0c6679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Thu, 19 Nov 2015 12:50:09 +0100 Subject: null_blk: use device addressing mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linear addressing mode was removed in 7386af2. Make null_blk instead expose the ppa format geometry and support the generic addressing mode. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 3e9c4f9..d51c24a 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -486,6 +486,7 @@ static int null_lnvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) { sector_t size = gb * 1024 * 1024 * 1024ULL; + sector_t blksize; struct nvm_id_group *grp; id->ver_id = 0x1; @@ -493,17 +494,34 @@ static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) id->cgrps = 1; id->cap = 0x3; id->dom = 0x1; - id->ppat = NVM_ADDRMODE_LINEAR; + + id->ppaf.blk_offset = 0; + id->ppaf.blk_len = 16; + id->ppaf.pg_offset = 16; + id->ppaf.pg_len = 16; + id->ppaf.sect_offset = 32; + id->ppaf.sect_len = 8; + id->ppaf.pln_offset = 40; + id->ppaf.pln_len = 8; + id->ppaf.lun_offset = 48; + id->ppaf.lun_len = 8; + id->ppaf.ch_offset = 56; + id->ppaf.ch_len = 8; do_div(size, bs); /* convert size to pages */ + do_div(size, 256); /* concert size to pgs pr blk */ grp = &id->groups[0]; grp->mtype = 0; - grp->fmtype = 1; + grp->fmtype = 0; grp->num_ch = 1; - grp->num_lun = 1; - grp->num_pln = 1; - grp->num_blk = size / 256; grp->num_pg = 256; + blksize = size; + do_div(size, (1 << 16)); + grp->num_lun = size + 1; + do_div(blksize, grp->num_lun); + grp->num_blk = blksize; + grp->num_pln = 1; + grp->fpg_sz = bs; grp->csecs = bs; grp->trdt = 25000; -- cgit v0.10.2 From 54514aa465e94316a4bf1c5dfe970536bec3e76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Thu, 19 Nov 2015 12:50:10 +0100 Subject: null_blk: do not del gendisk with lightnvm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gendisk structure has not been initialized when using lightnvm. Make sure to not delete it upon exit. Also make sure that we use the appropriate disk_name at unregistration. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index d51c24a..5c8ba54 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -435,12 +435,14 @@ static void null_del_dev(struct nullb *nullb) list_del_init(&nullb->list); if (use_lightnvm) - nvm_unregister(nullb->disk->disk_name); - del_gendisk(nullb->disk); + nvm_unregister(nullb->disk_name); + else + del_gendisk(nullb->disk); blk_cleanup_queue(nullb->q); if (queue_mode == NULL_Q_MQ) blk_mq_free_tag_set(&nullb->tag_set); - put_disk(nullb->disk); + if (!use_lightnvm) + put_disk(nullb->disk); cleanup_queues(nullb); kfree(nullb); } -- cgit v0.10.2 From 7fe941422339c96072fc1eec4e8b484ccf7ccd0e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 19 Nov 2015 13:00:14 +0900 Subject: vfio: 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: Baptiste Reynal Signed-off-by: Alex Williamson diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c index f1625dc..b1cc3a7 100644 --- a/drivers/vfio/platform/vfio_platform.c +++ b/drivers/vfio/platform/vfio_platform.c @@ -92,7 +92,6 @@ static struct platform_driver vfio_platform_driver = { .remove = vfio_platform_remove, .driver = { .name = "vfio-platform", - .owner = THIS_MODULE, }, }; -- cgit v0.10.2 From 7d10f4e0797597a31f2724b46e619ee10d8eb501 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 14 Nov 2015 11:07:01 +0100 Subject: vfio-pci: constify pci_error_handlers structures This pci_error_handlers structure is never modified, like all the other pci_error_handlers structures, so declare it as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 32b88bd..2760a7b 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1035,7 +1035,7 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_CAN_RECOVER; } -static struct pci_error_handlers vfio_err_handlers = { +static const struct pci_error_handlers vfio_err_handlers = { .error_detected = vfio_pci_aer_err_detected, }; -- cgit v0.10.2 From 0d51571d51ea8eb72b903b2a4f3f43a38e7bc718 Mon Sep 17 00:00:00 2001 From: Jimmy Berry Date: Fri, 20 Nov 2015 01:10:28 -0600 Subject: HID: usbhid: add Logitech G710+ keyboard quirk NOGET Without quirk keyboard repeats '6' until volume control is used since it indicates the key is pressed without ever releasing. Signed-off-by: Jimmy Berry Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ac1feea..9024a3d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -609,6 +609,7 @@ #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f #define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306 +#define USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS 0xc24d #define USB_DEVICE_ID_LOGITECH_MOUSE_C01A 0xc01a #define USB_DEVICE_ID_LOGITECH_MOUSE_C05A 0xc05a #define USB_DEVICE_ID_LOGITECH_MOUSE_C06A 0xc06a diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 94bb137..2324520 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -84,6 +84,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL }, -- cgit v0.10.2 From 5ad11b50fda1306b5317124f97f0a7a4c022b022 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 17 Nov 2015 10:24:39 +0200 Subject: mac80211: ensure we don't update tx power on a non-running sdata We can't update the Tx power on the device unless it is running. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=101521. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d0dc1bf..53ee049 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, bool update_bss) { - if (__ieee80211_recalc_txpower(sdata) || update_bss) + if (__ieee80211_recalc_txpower(sdata) || + (update_bss && ieee80211_sdata_running(sdata))) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); } -- cgit v0.10.2 From ac0621971a26526cad8cf9db7626d5e50562a441 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 17 Nov 2015 10:24:38 +0200 Subject: mac80211: always set the buf_size in AddBA req to 64 Advertising reordering window in ADDBA less than 64 can crash some APs, an example is LinkSys WRT120N (with FW v1.0.07 build 002 Jun 18 2012). On the other hand, a driver may need to limit Tx A-MPDU size for its own reasons, like specific HW limitations. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 82045fc..760bc4d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2003,8 +2003,10 @@ enum ieee80211_hw_flags { * it shouldn't be set. * * @max_tx_aggregation_subframes: maximum number of subframes in an - * aggregate an HT driver will transmit, used by the peer as a - * hint to size its reorder buffer. + * aggregate an HT driver will transmit. Though ADDBA will advertise + * a constant value of 64 as some older APs can crash if the window + * size is smaller (an example is LinkSys WRT120N with FW v1.0.07 + * build 002 Jun 18 2012). * * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX * (if %IEEE80211_HW_QUEUE_CONTROL is set) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index a758eb84..ff75718 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -500,7 +500,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) /* send AddBA request */ ieee80211_send_addba_request(sdata, sta->sta.addr, tid, tid_tx->dialog_token, start_seq_num, - local->hw.max_tx_aggregation_subframes, + IEEE80211_MAX_AMPDU_BUF, tid_tx->timeout); } @@ -926,6 +926,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK; tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; + buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); mutex_lock(&sta->ampdu_mlme.mtx); -- cgit v0.10.2 From 3f58b7039c70f1d0a19157c7bf97ef69d445565f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 20 Nov 2015 12:25:59 +0800 Subject: ASoC: rt5645: Add dmi_system_id "Google Wizpig" Add platform specific data for Wizpig project. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 647b594..5af9023 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3385,6 +3385,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"), }, }, + { + .ident = "Google Wizpig", + .callback = strago_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"), + }, + }, { } }; -- cgit v0.10.2 From 113b0b20fc123bc522ded68ea710d789b0415ebe Mon Sep 17 00:00:00 2001 From: John Keeping Date: Fri, 20 Nov 2015 11:42:22 +0000 Subject: ASoC: es8328: Fix shifts for mixer switches These are all off by one; the playback and bypass switches are the top two bits of the registers, which are at shifts 7 and 6 not 8 and 7. Signed-off-by: John Keeping Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 969e337..84f5eb0 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -205,18 +205,18 @@ static const struct snd_kcontrol_new es8328_right_line_controls = /* Left Mixer */ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { - SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), - SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), - SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), - SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0), }; /* Right Mixer */ static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { - SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), - SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), - SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), - SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), + SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0), }; static const char * const es8328_pga_sel[] = { -- cgit v0.10.2 From f74875dc36135ebae82a8e005f4b7f52289d2c40 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 12 Nov 2015 21:08:34 +0000 Subject: usb: dwc2: fix kernel oops during driver probe This patch make sure that all necessary members of dwc2_hsotg are initialized before the irq handler is requested. So the kernel oops triggered by dwc2_handle_common_intr has been fixed. dwc2 20980000.usb: Configuration mismatch. Forcing host mode dwc2 20980000.usb: no platform data or transceiver defined Unable to handle kernel paging request at virtual address cc860040 pgd = c0004000 [cc860040] *pgd=0b41e811, *pte=00000000, *ppte=00000000 Internal error: Oops: 7 [#1] ARM CPU: 0 PID: 1 Comm: swapper Not tainted 4.3.0-rc3+ #19 Hardware name: BCM2835 task: cb494000 ti: cb4d0000 task.ti: cb4d0000 PC is at dwc2_is_controller_alive+0x18/0x34 LR is at dwc2_handle_common_intr+0x24/0xb60 Acked-by: John Youn Tested-by: Marek Szyprowski Signed-off-by: Stefan Wahren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 91e2e6b..39c1cbf 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -367,20 +367,6 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) return retval; - irq = platform_get_irq(dev, 0); - if (irq < 0) { - dev_err(&dev->dev, "missing IRQ resource\n"); - return irq; - } - - dev_dbg(hsotg->dev, "registering common handler for irq%d\n", - irq); - retval = devm_request_irq(hsotg->dev, irq, - dwc2_handle_common_intr, IRQF_SHARED, - dev_name(hsotg->dev), hsotg); - if (retval) - return retval; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); hsotg->regs = devm_ioremap_resource(&dev->dev, res); if (IS_ERR(hsotg->regs)) @@ -415,6 +401,20 @@ static int dwc2_driver_probe(struct platform_device *dev) dwc2_set_all_params(hsotg->core_params, -1); + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "missing IRQ resource\n"); + return irq; + } + + dev_dbg(hsotg->dev, "registering common handler for irq%d\n", + irq); + retval = devm_request_irq(hsotg->dev, irq, + dwc2_handle_common_intr, IRQF_SHARED, + dev_name(hsotg->dev), hsotg); + if (retval) + return retval; + retval = dwc2_lowlevel_hw_enable(hsotg); if (retval) return retval; -- cgit v0.10.2 From 480fc0db819d706ea5608545a12d33cf8d5a31ab Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Fri, 20 Nov 2015 13:47:53 +0100 Subject: lightnvm: wrong return value and redundant free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value should be non-zero under error conditions. Remove nvme_free(dev) to avoid free dev more than once. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 8a556f3..bed47e7 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -222,14 +222,13 @@ static void nvm_free(struct nvm_dev *dev) static int nvm_init(struct nvm_dev *dev) { struct nvmm_type *mt; - int ret = 0; + int ret = -EINVAL; if (!dev->q || !dev->ops) - return -EINVAL; + return ret; if (dev->ops->identity(dev->q, &dev->identity)) { pr_err("nvm: device could not be identified\n"); - ret = -EINVAL; goto err; } @@ -275,7 +274,6 @@ static int nvm_init(struct nvm_dev *dev) dev->nr_chnls); return 0; err: - nvm_free(dev); pr_err("nvm: failed to initialize nvm\n"); return ret; } -- cgit v0.10.2 From 93e70c1f2883f2db2d6a1f339d0e26f00b138e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Fri, 20 Nov 2015 13:47:54 +0100 Subject: lightnvm: missing free on init error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If either max_phys_sect is out of bound, the nvm_dev structure is not freed. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index bed47e7..f61d325 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -313,11 +313,13 @@ int nvm_register(struct request_queue *q, char *disk_name, "ppalist"); if (!dev->ppalist_pool) { pr_err("nvm: could not create ppa pool\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_init; } } else if (dev->ops->max_phys_sect > 256) { pr_info("nvm: max sectors supported is 256.\n"); - return -EINVAL; + ret = -EINVAL; + goto err_init; } down_write(&nvm_lock); -- cgit v0.10.2 From 47b3115ae7b799be8b77b0f024215ad4f68d6460 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Fri, 20 Nov 2015 13:47:55 +0100 Subject: nvme: lightnvm: use admin queues for admin cmds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the Open-Channel SSD Specification, the NVMe-NVM admin commands use vendor specific opcodes of NVMe, so use the NVMe admin queue to dispatch these commands. Signed-off-by: Wenwei Tao Updated by me to include set bad block table as well and also use the admin queue for l2p len calculation. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 7e82fe3..9202d1a 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -276,6 +276,7 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id) static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id) { struct nvme_ns *ns = q->queuedata; + struct nvme_dev *dev = ns->dev; struct nvme_nvm_id *nvme_nvm_id; struct nvme_nvm_command c = {}; int ret; @@ -288,8 +289,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id) if (!nvme_nvm_id) return -ENOMEM; - ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, nvme_nvm_id, - sizeof(struct nvme_nvm_id)); + ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c, + nvme_nvm_id, sizeof(struct nvme_nvm_id)); if (ret) { ret = -EIO; goto out; @@ -315,7 +316,7 @@ static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb, struct nvme_ns *ns = q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_command c = {}; - u32 len = queue_max_hw_sectors(q) << 9; + u32 len = queue_max_hw_sectors(dev->admin_q) << 9; u32 nlb_pr_rq = len / sizeof(u64); u64 cmd_slba = slba; void *entries; @@ -333,8 +334,8 @@ static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb, c.l2p.slba = cpu_to_le64(cmd_slba); c.l2p.nlb = cpu_to_le32(cmd_nlb); - ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, - entries, len); + ret = nvme_submit_sync_cmd(dev->admin_q, + (struct nvme_command *)&c, entries, len); if (ret) { dev_err(dev->dev, "L2P table transfer failed (%d)\n", ret); @@ -375,7 +376,8 @@ static int nvme_nvm_get_bb_tbl(struct request_queue *q, struct ppa_addr ppa, if (!bb_tbl) return -ENOMEM; - ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_tbl, tblsz); + ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c, + bb_tbl, tblsz); if (ret) { dev_err(dev->dev, "get bad block table failed (%d)\n", ret); ret = -EIO; @@ -427,7 +429,8 @@ static int nvme_nvm_set_bb_tbl(struct request_queue *q, struct nvm_rq *rqd, c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1); c.set_bb.value = type; - ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0); + ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c, + NULL, 0); if (ret) dev_err(dev->dev, "set bad block table failed (%d)\n", ret); return ret; -- cgit v0.10.2 From 0b59733b95f9d7af6bee6e6a4d0d444eb694c514 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Date: Fri, 20 Nov 2015 13:47:56 +0100 Subject: lightnvm: keep track of block counts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maintain number of in use blocks, free blocks, and bad blocks in a per lun basis. This allows the upper layers to get information about the state of each lun. Also, account for blocks reserved to the device on the free block count. nr_free_blocks matches now the actual number of blocks on the free list when the device is booted. Signed-off-by: Javier Gonzalez Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index c0d0eb2..43c01e0 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -60,6 +60,8 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn) lun->vlun.lun_id = i % dev->luns_per_chnl; lun->vlun.chnl_id = i / dev->luns_per_chnl; lun->vlun.nr_free_blocks = dev->blks_per_lun; + lun->vlun.nr_inuse_blocks = 0; + lun->vlun.nr_bad_blocks = 0; } return 0; } @@ -87,6 +89,7 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks, } list_move_tail(&blk->list, &lun->bb_list); + lun->vlun.nr_bad_blocks++; } return 0; @@ -139,6 +142,7 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) list_move_tail(&blk->list, &lun->used_list); blk->type = 1; lun->vlun.nr_free_blocks--; + lun->vlun.nr_inuse_blocks++; } } @@ -167,8 +171,10 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) block->id = cur_block_id++; /* First block is reserved for device */ - if (unlikely(lun_iter == 0 && blk_iter == 0)) + if (unlikely(lun_iter == 0 && blk_iter == 0)) { + lun->vlun.nr_free_blocks--; continue; + } list_add_tail(&block->list, &lun->free_list); } @@ -266,6 +272,7 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, blk->type = 1; lun->vlun.nr_free_blocks--; + lun->vlun.nr_inuse_blocks++; spin_unlock(&vlun->lock); out: @@ -283,16 +290,21 @@ static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk) case 1: list_move_tail(&blk->list, &lun->free_list); lun->vlun.nr_free_blocks++; + lun->vlun.nr_inuse_blocks--; blk->type = 0; break; case 2: list_move_tail(&blk->list, &lun->bb_list); + lun->vlun.nr_bad_blocks++; + lun->vlun.nr_inuse_blocks--; break; default: WARN_ON_ONCE(1); pr_err("gennvm: erroneous block type (%lu -> %u)\n", blk->id, blk->type); list_move_tail(&blk->list, &lun->bb_list); + lun->vlun.nr_bad_blocks++; + lun->vlun.nr_inuse_blocks--; } spin_unlock(&vlun->lock); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index cbe288a..831a20c 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -213,7 +213,9 @@ struct nvm_lun { int lun_id; int chnl_id; + unsigned int nr_inuse_blocks; /* Number of used blocks */ unsigned int nr_free_blocks; /* Number of unused blocks */ + unsigned int nr_bad_blocks; /* Number of bad blocks */ struct nvm_block *blocks; spinlock_t lock; -- cgit v0.10.2 From 2fde0e482db2b43bb4ed0e9aebfbe78ebcbbf5a6 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Date: Fri, 20 Nov 2015 13:47:57 +0100 Subject: lightnvm: add free and bad lun info to show luns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add free block, used block, and bad block information to the show debug interface. This information is used to debug how targets track blocks. Also, change debug function name to make it more generic. Signed-off-by: Javier Gonzalez Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index f61d325..5178645 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -544,7 +544,7 @@ static int nvm_configure_show(const char *val) if (!dev->mt) return 0; - dev->mt->free_blocks_print(dev); + dev->mt->lun_info_print(dev); return 0; } diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 43c01e0..e20e74e 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -464,15 +464,24 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid) return &gn->luns[lunid].vlun; } -static void gennvm_free_blocks_print(struct nvm_dev *dev) +static void gennvm_lun_info_print(struct nvm_dev *dev) { struct gen_nvm *gn = dev->mp; struct gen_lun *lun; unsigned int i; - gennvm_for_each_lun(gn, lun, i) - pr_info("%s: lun%8u\t%u\n", - dev->name, i, lun->vlun.nr_free_blocks); + + gennvm_for_each_lun(gn, lun, i) { + spin_lock(&lun->vlun.lock); + + pr_info("%s: lun%8u\t%u\t%u\t%u\n", + dev->name, i, + lun->vlun.nr_free_blocks, + lun->vlun.nr_inuse_blocks, + lun->vlun.nr_bad_blocks); + + spin_unlock(&lun->vlun.lock); + } } static struct nvmm_type gennvm = { @@ -490,7 +499,7 @@ static struct nvmm_type gennvm = { .erase_blk = gennvm_erase_blk, .get_lun = gennvm_get_lun, - .free_blocks_print = gennvm_free_blocks_print, + .lun_info_print = gennvm_lun_info_print, }; static int __init gennvm_module_init(void) diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 831a20c..3db5552 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -380,7 +380,7 @@ typedef int (nvmm_end_io_fn)(struct nvm_rq *, int); typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, unsigned long); typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); -typedef void (nvmm_free_blocks_print_fn)(struct nvm_dev *); +typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); struct nvmm_type { const char *name; @@ -404,7 +404,7 @@ struct nvmm_type { nvmm_get_lun_fn *get_lun; /* Statistics */ - nvmm_free_blocks_print_fn *free_blocks_print; + nvmm_lun_info_print_fn *lun_info_print; struct list_head list; }; -- cgit v0.10.2 From 604e8c8da8854351496215d269c3fa93859e3fee Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 20 Nov 2015 08:38:13 -0700 Subject: NVMe: reap completion entries when deleting queue Make sure that there are no unprocesssed entries on a completion queue before deleting it, and check for validity of the CQ door bell before writing completions to it. This fixes problems with doing a sysfs reset of the device while it's handling IO. Tested-by: Jon Derrick Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 394fd16..930042fa 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -968,7 +968,8 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag) if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return; - writel(head, nvmeq->q_db + nvmeq->dev->db_stride); + if (likely(nvmeq->cq_vector >= 0)) + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; @@ -2787,6 +2788,10 @@ static void nvme_del_queue_end(struct nvme_queue *nvmeq) { struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx; nvme_put_dq(dq); + + spin_lock_irq(&nvmeq->q_lock); + nvme_process_cq(nvmeq); + spin_unlock_irq(&nvmeq->q_lock); } static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode, -- cgit v0.10.2 From 0db19b850468a24b70d8471f5ebe71f0a035bbab Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 18 Nov 2015 17:27:25 -0800 Subject: net: cpsw: Fix ethernet regression for dm814x Commit b6745f6e4e63 ("drivers: net: cpsw: davinci_emac: move reading mac id to common file") started using of_machine_is_compatible for detecting type but missed at dm8148 causing Ethernet to stop working. Let's fix the issue by adding handling for dm814x. Cc: Mugunthan V N Signed-off-by: Tony Lindgren Acked-by: Mugunthnan V N Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c index c08be62..1562ab4 100644 --- a/drivers/net/ethernet/ti/cpsw-common.c +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -78,6 +78,9 @@ static int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr) { + if (of_machine_is_compatible("ti,dm8148")) + return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); + if (of_machine_is_compatible("ti,am33xx")) return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); -- cgit v0.10.2 From 8aeea03195ee6e33fcb00039c414eabfc37a4eb8 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 20 Nov 2015 10:46:49 +0100 Subject: mtip32xx: use formatting capability of kthread_create_on_node kthread_create_on_node takes format+args, so there's no need to do the pretty-printing in advance. Moreover, "mtip_svc_thd_99" (including its '\0') only just fits in 16 bytes, so if index could ever go above 99 we'd have a stack buffer overflow. Signed-off-by: Rasmus Villemoes Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index a28a562..3457ac8 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3810,7 +3810,6 @@ static int mtip_block_initialize(struct driver_data *dd) sector_t capacity; unsigned int index = 0; struct kobject *kobj; - unsigned char thd_name[16]; if (dd->disk) goto skip_create_disk; /* hw init done, before rebuild */ @@ -3958,10 +3957,9 @@ skip_create_disk: } start_service_thread: - sprintf(thd_name, "mtip_svc_thd_%02d", index); dd->mtip_svc_handler = kthread_create_on_node(mtip_service_thread, - dd, dd->numa_node, "%s", - thd_name); + dd, dd->numa_node, + "mtip_svc_thd_%02d", index); if (IS_ERR(dd->mtip_svc_handler)) { dev_err(&dd->pdev->dev, "service thread failed to start\n"); -- cgit v0.10.2 From 02e2a5bfebe99edcf9d694575a75032d53fe1b73 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 19 Nov 2015 17:18:54 -0800 Subject: mac: validate mac_partition is within sector If md->signature == MAC_DRIVER_MAGIC and md->block_size == 1023, a single 512 byte sector would be read (secsize / 512). However the partition structure would be located past the end of the buffer (secsize % 512). Signed-off-by: Kees Cook Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe diff --git a/block/partitions/mac.c b/block/partitions/mac.c index c2c48ec..621317a 100644 --- a/block/partitions/mac.c +++ b/block/partitions/mac.c @@ -32,7 +32,7 @@ int mac_partition(struct parsed_partitions *state) Sector sect; unsigned char *data; int slot, blocks_in_map; - unsigned secsize; + unsigned secsize, datasize, partoffset; #ifdef CONFIG_PPC_PMAC int found_root = 0; int found_root_goodness = 0; @@ -50,10 +50,14 @@ int mac_partition(struct parsed_partitions *state) } secsize = be16_to_cpu(md->block_size); put_dev_sector(sect); - data = read_part_sector(state, secsize/512, §); + datasize = round_down(secsize, 512); + data = read_part_sector(state, datasize / 512, §); if (!data) return -1; - part = (struct mac_partition *) (data + secsize%512); + partoffset = secsize % 512; + if (partoffset + sizeof(*part) > datasize) + return -1; + part = (struct mac_partition *) (data + partoffset); if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { put_dev_sector(sect); return 0; /* not a MacOS disk */ -- cgit v0.10.2 From 0e45f4da5981895e885dd72fe912a3f8e32bae73 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Nov 2015 18:17:30 -0800 Subject: tcp: disable Fast Open on timeouts after handshake Some middle-boxes black-hole the data after the Fast Open handshake (https://www.ietf.org/proceedings/94/slides/slides-94-tcpm-13.pdf). The exact reason is unknown. The work-around is to disable Fast Open temporarily after multiple recurring timeouts with few or no data delivered in the established state. Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Reported-by: Christoph Paasch Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index c9c716a..448603a 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -176,6 +176,18 @@ static int tcp_write_timeout(struct sock *sk) syn_set = true; } else { if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) { + /* Some middle-boxes may black-hole Fast Open _after_ + * the handshake. Therefore we conservatively disable + * Fast Open on this path on recurring timeouts with + * few or zero bytes acked after Fast Open. + */ + if (tp->syn_data_acked && + tp->bytes_acked <= tp->rx_opt.mss_clamp) { + tcp_fastopen_cache_set(sk, 0, NULL, true, 0); + if (icsk->icsk_retransmits == sysctl_tcp_retries1) + NET_INC_STATS_BH(sock_net(sk), + LINUX_MIB_TCPFASTOPENACTIVEFAIL); + } /* Black hole detection */ tcp_mtu_probing(icsk, sk); -- cgit v0.10.2 From dd52bc2b4ed16db66f9347aa263d8f1dc889b4b6 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Nov 2015 18:17:31 -0800 Subject: tcp: fix Fast Open snmp over-counting bug Fix incrementing TCPFastOpenActiveFailed snmp stats multiple times when the handshake experiences multiple SYN timeouts. Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 448603a..193ba1f 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -168,7 +168,7 @@ static int tcp_write_timeout(struct sock *sk) dst_negative_advice(sk); if (tp->syn_fastopen || tp->syn_data) tcp_fastopen_cache_set(sk, 0, NULL, true, 0); - if (tp->syn_data) + if (tp->syn_data && icsk->icsk_retransmits == 1) NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVEFAIL); } -- cgit v0.10.2 From 5d4c9bfbabdb1d497f21afd81501e5c54b0c85d9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Nov 2015 21:03:33 -0800 Subject: tcp: fix potential huge kmalloc() calls in TCP_REPAIR tcp_send_rcvq() is used for re-injecting data into tcp receive queue. Problems : - No check against size is performed, allowed user to fool kernel in attempting very large memory allocations, eventually triggering OOM when memory is fragmented. - In case of fault during the copy we do not return correct errno. Lets use alloc_skb_with_frags() to cook optimal skbs. Fixes: 292e8d8c8538 ("tcp: Move rcvq sending to tcp_input.c") Fixes: c0e88ff0f256 ("tcp: Repair socket queues") Signed-off-by: Eric Dumazet Cc: Pavel Emelyanov Acked-by: Pavel Emelyanov Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fdd88c3..a4a0b6b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4481,19 +4481,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) { struct sk_buff *skb; + int err = -ENOMEM; + int data_len = 0; bool fragstolen; if (size == 0) return 0; - skb = alloc_skb(size, sk->sk_allocation); + if (size > PAGE_SIZE) { + int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS); + + data_len = npages << PAGE_SHIFT; + size = data_len + (size & ~PAGE_MASK); + } + skb = alloc_skb_with_frags(size - data_len, data_len, + PAGE_ALLOC_COSTLY_ORDER, + &err, sk->sk_allocation); if (!skb) goto err; + skb_put(skb, size - data_len); + skb->data_len = data_len; + skb->len = size; + if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) goto err_free; - if (memcpy_from_msg(skb_put(skb, size), msg, size)) + err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); + if (err) goto err_free; TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt; @@ -4509,7 +4524,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) err_free: kfree_skb(skb); err: - return -ENOMEM; + return err; + } static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) -- cgit v0.10.2 From 425d3d83707d378d97d1f7d460ce3083a1948c20 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 19 Nov 2015 11:56:51 +0200 Subject: bnx2x: Fix vxlan removal Commmit ac7eccd4d48fc "bnx2x: track vxlan port count" contains a bug - Instead of achieving the required goal, vxlan configuration would not be removed since we're decrementing the port instead of the counter. CC: Jiri Benc Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c9b0367..2e611dc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10139,8 +10139,8 @@ static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port) DP(BNX2X_MSG_SP, "Invalid vxlan port\n"); return; } - bp->vxlan_dst_port--; - if (bp->vxlan_dst_port) + bp->vxlan_dst_port_count--; + if (bp->vxlan_dst_port_count) return; if (netif_running(bp->dev)) { -- cgit v0.10.2 From 7200be7c81cc1a1c54a79348a724c16345c5242f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 19 Nov 2015 16:17:24 -0800 Subject: vfio: platform: remove needless stack usage request_module already takes format strings, so no need to duplicate the effort. Signed-off-by: Kees Cook Signed-off-by: Alex Williamson diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index a1c50d6..418cdd9 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -51,13 +51,10 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, static void vfio_platform_get_reset(struct vfio_platform_device *vdev) { - char modname[256]; - vdev->reset = vfio_platform_lookup_reset(vdev->compat, &vdev->reset_module); if (!vdev->reset) { - snprintf(modname, 256, "vfio-reset:%s", vdev->compat); - request_module(modname); + request_module("vfio-reset:%s", vdev->compat); vdev->reset = vfio_platform_lookup_reset(vdev->compat, &vdev->reset_module); } -- cgit v0.10.2 From de92718883ddbcd11b738d36ffcf57617b97fa12 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Nov 2015 11:42:26 +0100 Subject: net: tulip: turn compile-time warning into dev_warn() The tulip driver causes annoying build-time warnings for allmodconfig builds for all recent architectures: dec/tulip/winbond-840.c:910:2: warning: #warning Processor architecture undefined dec/tulip/tulip_core.c:101:2: warning: #warning Processor architecture undefined! This is the last remaining warning for arm64, and I'd like to get rid of it. We don't really know the cache line size, architecturally it would be at least 16 bytes, but all implementations I found have 64 or 128 bytes. Configuring tulip for 32-byte lines as we do on ARM32 seems to be the safe but slow default, and nobody who cares about performance these days would use a tulip chip anyway, so we can just use that. To save the next person the job of trying to find out what this is for and picking a default for their architecture just to kill off the warning, I'm now removing the preprocessor #warning and turning it into a pr_warn or dev_warn that prints the equivalent information when the driver gets loaded. Signed-off-by: Arnd Bergmann Acked-by: Grant Grundler Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index ed41559..b553409 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -98,8 +98,7 @@ static int csr0 = 0x01A00000 | 0x4800; #elif defined(__mips__) static int csr0 = 0x00200000 | 0x4000; #else -#warning Processor architecture undefined! -static int csr0 = 0x00A00000 | 0x4800; +static int csr0; #endif /* Operational parameters that usually are not changed. */ @@ -1982,6 +1981,12 @@ static int __init tulip_init (void) pr_info("%s", version); #endif + if (!csr0) { + pr_warn("tulip: unknown CPU architecture, using default csr0\n"); + /* default to 8 longword cache line alignment */ + csr0 = 0x00A00000 | 0x4800; + } + /* copy module parms into globals */ tulip_rx_copybreak = rx_copybreak; tulip_max_interrupt_work = max_interrupt_work; diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index 9beb3d3..3c0e4d5 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -907,7 +907,7 @@ static void init_registers(struct net_device *dev) #elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM) i |= 0x4800; #else -#warning Processor architecture undefined + dev_warn(&dev->dev, "unknown CPU architecture, using default csr0 setting\n"); i |= 0x4800; #endif iowrite32(i, ioaddr + PCIBusCfg); -- cgit v0.10.2 From 196543d54574f50e3fd04df4e3048181e006a9da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Nov 2015 14:46:35 +0100 Subject: ALSA: hda - Apply HP headphone fixups more generically It turned out that many HP laptops suffer from the same problem as fixed in commit [c932b98c1e47: ALSA: hda - Apply pin fixup for HP ProBook 6550b]. But, it's tiresome to list up all such PCI SSIDs, as there are really lots of HP machines. Instead, we do a bit more clever, try to check the supposedly dock and built-in headphone pins, and apply the fixup when both seem valid. This rule can be applied generically to all models using the same quirk, so we'll fix all in a shot. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=107491 Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 826122d..2c7c5eb 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3110,6 +3110,29 @@ static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec, spec->gpio_led = 0x08; } +static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin); + + /* count line-out, too, as BIOS sets often so */ + return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE && + (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || + get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT); +} + +static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin); + + /* It was changed in the BIOS to just satisfy MS DTM. + * Lets turn it back into slaved HP + */ + pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) | + (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT); + pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) | + 0x1f; + snd_hda_codec_set_pincfg(codec, pin, pin_cfg); +} static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -3119,22 +3142,12 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, if (action != HDA_FIXUP_ACT_PRE_PROBE) return; - if (hp_blike_system(codec->core.subsystem_id)) { - unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); - if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || - get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || - get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { - /* It was changed in the BIOS to just satisfy MS DTM. - * Lets turn it back into slaved HP - */ - pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) - | (AC_JACK_HP_OUT << - AC_DEFCFG_DEVICE_SHIFT); - pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC - | AC_DEFCFG_SEQUENCE))) - | 0x1f; - snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); - } + /* when both output A and F are assigned, these are supposedly + * dock and built-in headphones; fix both pin configs + */ + if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) { + fixup_hp_headphone(codec, 0x0a); + fixup_hp_headphone(codec, 0x0f); } if (find_mute_led_cfg(codec, 1)) -- cgit v0.10.2 From 2b8bbdb9d0ca1f968817dc1e9ede2c8940e5b7a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Nov 2015 15:22:23 +0100 Subject: scsi: advansys needs ISA dma api for ISA support The advansys drvier uses the request_dma function that is used on ISA machines for the internal DMA controller, which causes build errors on platforms that have ISA slots but do not provide the ISA DMA API: drivers/scsi/advansys.c: In function 'advansys_board_found': drivers/scsi/advansys.c:11300:10: error: implicit declaration of function 'request_dma' [-Werror=implicit-function-declaration] The problem now showed up in ARM randconfig builds after commit 6571fb3f8b7f ("advansys: Update to version 3.5 and remove compilation warning") made it possible to build on platforms that have neither VIRT_TO_BUS nor ISA_DMA_API but that do have ISA. This adds the missing dependency. Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8aed855..528cc7f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -506,6 +506,7 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" depends on SCSI depends on ISA || EISA || PCI + depends on ISA_DMA_API || !ISA help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in -- cgit v0.10.2 From 653cfb85fbe73be44fda14bb67f1b95818bfc37f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Nov 2015 23:04:35 +0100 Subject: scsi: hpsa: select CONFIG_SCSI_SAS_ATTR The hpsa driver recently started using the sas transport class, but it does not ensure that the corresponding code is actually built, which may lead to a link error: drivers/built-in.o: In function `hpsa_free_sas_phy': (.text+0x1ce874): undefined reference to `sas_port_delete_phy' (.text+0x1ce87c): undefined reference to `sas_phy_free' drivers/built-in.o: In function `hpsa_alloc_sas_port': (.text+0x1ceb9c): undefined reference to `sas_port_alloc_num' (.text+0x1ceba8): undefined reference to `sas_port_add' drivers/built-in.o: In function `hpsa_init': (.init.text+0x8838): undefined reference to `sas_attach_transport' (.init.text+0x8868): undefined reference to `sas_release_transport This adds 'select SCSI_SAS_ATTR' in the Kconfig entry, just like we do for all other drivers using those functions. Signed-off-by: Arnd Bergmann Fixes: d04e62b9d63a ("hpsa: add in sas transport class") Reviewed-by: Christoph Hellwig Acked-by: Don Brace Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 528cc7f..e0d2924 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -371,6 +371,7 @@ config SCSI_HPSA tristate "HP Smart Array SCSI driver" depends on PCI && SCSI select CHECK_SIGNATURE + select SCSI_SAS_ATTRS help This driver supports HP Smart Array Controllers (circa 2009). It is a SCSI alternative to the cciss driver, which is a block -- cgit v0.10.2 From 52dfc8301248f5008d64a680e832e2f99c55ec9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5ns=20Rullg=C3=A5rd?= Date: Thu, 19 Nov 2015 13:02:59 +0000 Subject: net: ethernet: add driver for Aurora VLSI NB8800 Ethernet controller This adds a driver for the Aurora VLSI NB8800 Ethernet controller. It is an almost complete rewrite of a driver originally found in a Sigma Designs 2.6.22 tree. Signed-off-by: Mans Rullgard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 955d06b..31c5e47 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -29,6 +29,7 @@ source "drivers/net/ethernet/apm/Kconfig" source "drivers/net/ethernet/apple/Kconfig" source "drivers/net/ethernet/arc/Kconfig" source "drivers/net/ethernet/atheros/Kconfig" +source "drivers/net/ethernet/aurora/Kconfig" source "drivers/net/ethernet/cadence/Kconfig" source "drivers/net/ethernet/adi/Kconfig" source "drivers/net/ethernet/broadcom/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 4a2ee98..071f84e 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_NET_XGENE) += apm/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_ARC) += arc/ obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ +obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/ obj-$(CONFIG_NET_CADENCE) += cadence/ obj-$(CONFIG_NET_BFIN) += adi/ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/ diff --git a/drivers/net/ethernet/aurora/Kconfig b/drivers/net/ethernet/aurora/Kconfig new file mode 100644 index 0000000..a3c7106 --- /dev/null +++ b/drivers/net/ethernet/aurora/Kconfig @@ -0,0 +1,20 @@ +config NET_VENDOR_AURORA + bool "Aurora VLSI devices" + help + If you have a network (Ethernet) device belonging to this class, + say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + questions about Aurora devices. If you say Y, you will be asked + for your specific device in the following questions. + +if NET_VENDOR_AURORA + +config AURORA_NB8800 + tristate "Aurora AU-NB8800 support" + select PHYLIB + help + Support for the AU-NB8800 gigabit Ethernet controller. + +endif diff --git a/drivers/net/ethernet/aurora/Makefile b/drivers/net/ethernet/aurora/Makefile new file mode 100644 index 0000000..6cb528a --- /dev/null +++ b/drivers/net/ethernet/aurora/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AURORA_NB8800) += nb8800.o diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c new file mode 100644 index 0000000..ecc4a33 --- /dev/null +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -0,0 +1,1552 @@ +/* + * Copyright (C) 2015 Mans Rullgard + * + * Mostly rewritten, based on driver from Sigma Designs. Original + * copyright notice below. + * + * + * Driver for tangox SMP864x/SMP865x/SMP867x/SMP868x builtin Ethernet Mac. + * + * Copyright (C) 2005 Maxime Bizon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nb8800.h" + +static void nb8800_tx_done(struct net_device *dev); +static int nb8800_dma_stop(struct net_device *dev); + +static inline u8 nb8800_readb(struct nb8800_priv *priv, int reg) +{ + return readb_relaxed(priv->base + reg); +} + +static inline u32 nb8800_readl(struct nb8800_priv *priv, int reg) +{ + return readl_relaxed(priv->base + reg); +} + +static inline void nb8800_writeb(struct nb8800_priv *priv, int reg, u8 val) +{ + writeb_relaxed(val, priv->base + reg); +} + +static inline void nb8800_writew(struct nb8800_priv *priv, int reg, u16 val) +{ + writew_relaxed(val, priv->base + reg); +} + +static inline void nb8800_writel(struct nb8800_priv *priv, int reg, u32 val) +{ + writel_relaxed(val, priv->base + reg); +} + +static inline void nb8800_maskb(struct nb8800_priv *priv, int reg, + u32 mask, u32 val) +{ + u32 old = nb8800_readb(priv, reg); + u32 new = (old & ~mask) | (val & mask); + + if (new != old) + nb8800_writeb(priv, reg, new); +} + +static inline void nb8800_maskl(struct nb8800_priv *priv, int reg, + u32 mask, u32 val) +{ + u32 old = nb8800_readl(priv, reg); + u32 new = (old & ~mask) | (val & mask); + + if (new != old) + nb8800_writel(priv, reg, new); +} + +static inline void nb8800_modb(struct nb8800_priv *priv, int reg, u8 bits, + bool set) +{ + nb8800_maskb(priv, reg, bits, set ? bits : 0); +} + +static inline void nb8800_setb(struct nb8800_priv *priv, int reg, u8 bits) +{ + nb8800_maskb(priv, reg, bits, bits); +} + +static inline void nb8800_clearb(struct nb8800_priv *priv, int reg, u8 bits) +{ + nb8800_maskb(priv, reg, bits, 0); +} + +static inline void nb8800_modl(struct nb8800_priv *priv, int reg, u32 bits, + bool set) +{ + nb8800_maskl(priv, reg, bits, set ? bits : 0); +} + +static inline void nb8800_setl(struct nb8800_priv *priv, int reg, u32 bits) +{ + nb8800_maskl(priv, reg, bits, bits); +} + +static inline void nb8800_clearl(struct nb8800_priv *priv, int reg, u32 bits) +{ + nb8800_maskl(priv, reg, bits, 0); +} + +static int nb8800_mdio_wait(struct mii_bus *bus) +{ + struct nb8800_priv *priv = bus->priv; + u32 val; + + return readl_poll_timeout_atomic(priv->base + NB8800_MDIO_CMD, + val, !(val & MDIO_CMD_GO), 1, 1000); +} + +static int nb8800_mdio_cmd(struct mii_bus *bus, u32 cmd) +{ + struct nb8800_priv *priv = bus->priv; + int err; + + err = nb8800_mdio_wait(bus); + if (err) + return err; + + nb8800_writel(priv, NB8800_MDIO_CMD, cmd); + udelay(10); + nb8800_writel(priv, NB8800_MDIO_CMD, cmd | MDIO_CMD_GO); + + return nb8800_mdio_wait(bus); +} + +static int nb8800_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct nb8800_priv *priv = bus->priv; + u32 val; + int err; + + err = nb8800_mdio_cmd(bus, MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg)); + if (err) + return err; + + val = nb8800_readl(priv, NB8800_MDIO_STS); + if (val & MDIO_STS_ERR) + return 0xffff; + + return val & 0xffff; +} + +static int nb8800_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + u32 cmd = MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg) | + MDIO_CMD_DATA(val) | MDIO_CMD_WR; + + return nb8800_mdio_cmd(bus, cmd); +} + +static void nb8800_mac_tx(struct net_device *dev, bool enable) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + while (nb8800_readl(priv, NB8800_TXC_CR) & TCR_EN) + cpu_relax(); + + nb8800_modb(priv, NB8800_TX_CTL1, TX_EN, enable); +} + +static void nb8800_mac_rx(struct net_device *dev, bool enable) +{ + nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_EN, enable); +} + +static void nb8800_mac_af(struct net_device *dev, bool enable) +{ + nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_AF_EN, enable); +} + +static void nb8800_start_rx(struct net_device *dev) +{ + nb8800_setl(netdev_priv(dev), NB8800_RXC_CR, RCR_EN); +} + +static int nb8800_alloc_rx(struct net_device *dev, unsigned int i, bool napi) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd = &priv->rx_descs[i]; + struct nb8800_rx_buf *rxb = &priv->rx_bufs[i]; + int size = L1_CACHE_ALIGN(RX_BUF_SIZE); + dma_addr_t dma_addr; + struct page *page; + unsigned long offset; + void *data; + + data = napi ? napi_alloc_frag(size) : netdev_alloc_frag(size); + if (!data) + return -ENOMEM; + + page = virt_to_head_page(data); + offset = data - page_address(page); + + dma_addr = dma_map_page(&dev->dev, page, offset, RX_BUF_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(&dev->dev, dma_addr)) { + skb_free_frag(data); + return -ENOMEM; + } + + rxb->page = page; + rxb->offset = offset; + rxd->desc.s_addr = dma_addr; + + return 0; +} + +static void nb8800_receive(struct net_device *dev, unsigned int i, + unsigned int len) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd = &priv->rx_descs[i]; + struct page *page = priv->rx_bufs[i].page; + int offset = priv->rx_bufs[i].offset; + void *data = page_address(page) + offset; + dma_addr_t dma = rxd->desc.s_addr; + struct sk_buff *skb; + unsigned int size; + int err; + + size = len <= RX_COPYBREAK ? len : RX_COPYHDR; + + skb = napi_alloc_skb(&priv->napi, size); + if (!skb) { + netdev_err(dev, "rx skb allocation failed\n"); + dev->stats.rx_dropped++; + return; + } + + if (len <= RX_COPYBREAK) { + dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE); + memcpy(skb_put(skb, len), data, len); + dma_sync_single_for_device(&dev->dev, dma, len, + DMA_FROM_DEVICE); + } else { + err = nb8800_alloc_rx(dev, i, true); + if (err) { + netdev_err(dev, "rx buffer allocation failed\n"); + dev->stats.rx_dropped++; + return; + } + + dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE); + memcpy(skb_put(skb, RX_COPYHDR), data, RX_COPYHDR); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + offset + RX_COPYHDR, len - RX_COPYHDR, + RX_BUF_SIZE); + } + + skb->protocol = eth_type_trans(skb, dev); + napi_gro_receive(&priv->napi, skb); +} + +static void nb8800_rx_error(struct net_device *dev, u32 report) +{ + if (report & RX_LENGTH_ERR) + dev->stats.rx_length_errors++; + + if (report & RX_FCS_ERR) + dev->stats.rx_crc_errors++; + + if (report & RX_FIFO_OVERRUN) + dev->stats.rx_fifo_errors++; + + if (report & RX_ALIGNMENT_ERROR) + dev->stats.rx_frame_errors++; + + dev->stats.rx_errors++; +} + +static int nb8800_poll(struct napi_struct *napi, int budget) +{ + struct net_device *dev = napi->dev; + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd; + unsigned int last = priv->rx_eoc; + unsigned int next; + int work = 0; + + nb8800_tx_done(dev); + +again: + while (work < budget) { + struct nb8800_rx_buf *rxb; + unsigned int len; + + next = (last + 1) % RX_DESC_COUNT; + + rxb = &priv->rx_bufs[next]; + rxd = &priv->rx_descs[next]; + + if (!rxd->report) + break; + + len = RX_BYTES_TRANSFERRED(rxd->report); + + if (IS_RX_ERROR(rxd->report)) + nb8800_rx_error(dev, rxd->report); + else + nb8800_receive(dev, next, len); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + + if (rxd->report & RX_MULTICAST_PKT) + dev->stats.multicast++; + + rxd->report = 0; + last = next; + work++; + } + + if (work) { + priv->rx_descs[last].desc.config |= DESC_EOC; + wmb(); /* ensure new EOC is written before clearing old */ + priv->rx_descs[priv->rx_eoc].desc.config &= ~DESC_EOC; + priv->rx_eoc = last; + nb8800_start_rx(dev); + } + + if (work < budget) { + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq); + + /* If a packet arrived after we last checked but + * before writing RX_ITR, the interrupt will be + * delayed, so we retrieve it now. + */ + if (priv->rx_descs[next].report) + goto again; + + napi_complete_done(napi, work); + } + + return work; +} + +static void __nb8800_tx_dma_start(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_buf *txb; + u32 txc_cr; + + txb = &priv->tx_bufs[priv->tx_queue]; + if (!txb->ready) + return; + + txc_cr = nb8800_readl(priv, NB8800_TXC_CR); + if (txc_cr & TCR_EN) + return; + + nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc); + wmb(); /* ensure desc addr is written before starting DMA */ + nb8800_writel(priv, NB8800_TXC_CR, txc_cr | TCR_EN); + + priv->tx_queue = (priv->tx_queue + txb->chain_len) % TX_DESC_COUNT; +} + +static void nb8800_tx_dma_start(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + spin_lock_irq(&priv->tx_lock); + __nb8800_tx_dma_start(dev); + spin_unlock_irq(&priv->tx_lock); +} + +static void nb8800_tx_dma_start_irq(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + spin_lock(&priv->tx_lock); + __nb8800_tx_dma_start(dev); + spin_unlock(&priv->tx_lock); +} + +static int nb8800_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_desc *txd; + struct nb8800_tx_buf *txb; + struct nb8800_dma_desc *desc; + dma_addr_t dma_addr; + unsigned int dma_len; + unsigned int align; + unsigned int next; + + if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW) { + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + align = (8 - (uintptr_t)skb->data) & 7; + + dma_len = skb->len - align; + dma_addr = dma_map_single(&dev->dev, skb->data + align, + dma_len, DMA_TO_DEVICE); + + if (dma_mapping_error(&dev->dev, dma_addr)) { + netdev_err(dev, "tx dma mapping error\n"); + kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + if (atomic_dec_return(&priv->tx_free) <= NB8800_DESC_LOW) { + netif_stop_queue(dev); + skb->xmit_more = 0; + } + + next = priv->tx_next; + txb = &priv->tx_bufs[next]; + txd = &priv->tx_descs[next]; + desc = &txd->desc[0]; + + next = (next + 1) % TX_DESC_COUNT; + + if (align) { + memcpy(txd->buf, skb->data, align); + + desc->s_addr = + txb->dma_desc + offsetof(struct nb8800_tx_desc, buf); + desc->n_addr = txb->dma_desc + sizeof(txd->desc[0]); + desc->config = DESC_BTS(2) | DESC_DS | align; + + desc++; + } + + desc->s_addr = dma_addr; + desc->n_addr = priv->tx_bufs[next].dma_desc; + desc->config = DESC_BTS(2) | DESC_DS | DESC_EOF | dma_len; + + if (!skb->xmit_more) + desc->config |= DESC_EOC; + + txb->skb = skb; + txb->dma_addr = dma_addr; + txb->dma_len = dma_len; + + if (!priv->tx_chain) { + txb->chain_len = 1; + priv->tx_chain = txb; + } else { + priv->tx_chain->chain_len++; + } + + netdev_sent_queue(dev, skb->len); + + priv->tx_next = next; + + if (!skb->xmit_more) { + smp_wmb(); + priv->tx_chain->ready = true; + priv->tx_chain = NULL; + nb8800_tx_dma_start(dev); + } + + return NETDEV_TX_OK; +} + +static void nb8800_tx_error(struct net_device *dev, u32 report) +{ + if (report & TX_LATE_COLLISION) + dev->stats.collisions++; + + if (report & TX_PACKET_DROPPED) + dev->stats.tx_dropped++; + + if (report & TX_FIFO_UNDERRUN) + dev->stats.tx_fifo_errors++; + + dev->stats.tx_errors++; +} + +static void nb8800_tx_done(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int limit = priv->tx_next; + unsigned int done = priv->tx_done; + unsigned int packets = 0; + unsigned int len = 0; + + while (done != limit) { + struct nb8800_tx_desc *txd = &priv->tx_descs[done]; + struct nb8800_tx_buf *txb = &priv->tx_bufs[done]; + struct sk_buff *skb; + + if (!txd->report) + break; + + skb = txb->skb; + len += skb->len; + + dma_unmap_single(&dev->dev, txb->dma_addr, txb->dma_len, + DMA_TO_DEVICE); + + if (IS_TX_ERROR(txd->report)) { + nb8800_tx_error(dev, txd->report); + kfree_skb(skb); + } else { + consume_skb(skb); + } + + dev->stats.tx_packets++; + dev->stats.tx_bytes += TX_BYTES_TRANSFERRED(txd->report); + dev->stats.collisions += TX_EARLY_COLLISIONS(txd->report); + + txb->skb = NULL; + txb->ready = false; + txd->report = 0; + + done = (done + 1) % TX_DESC_COUNT; + packets++; + } + + if (packets) { + smp_mb__before_atomic(); + atomic_add(packets, &priv->tx_free); + netdev_completed_queue(dev, packets, len); + netif_wake_queue(dev); + priv->tx_done = done; + } +} + +static irqreturn_t nb8800_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct nb8800_priv *priv = netdev_priv(dev); + irqreturn_t ret = IRQ_NONE; + u32 val; + + /* tx interrupt */ + val = nb8800_readl(priv, NB8800_TXC_SR); + if (val) { + nb8800_writel(priv, NB8800_TXC_SR, val); + + if (val & TSR_DI) + nb8800_tx_dma_start_irq(dev); + + if (val & TSR_TI) + napi_schedule_irqoff(&priv->napi); + + if (unlikely(val & TSR_DE)) + netdev_err(dev, "TX DMA error\n"); + + /* should never happen with automatic status retrieval */ + if (unlikely(val & TSR_TO)) + netdev_err(dev, "TX Status FIFO overflow\n"); + + ret = IRQ_HANDLED; + } + + /* rx interrupt */ + val = nb8800_readl(priv, NB8800_RXC_SR); + if (val) { + nb8800_writel(priv, NB8800_RXC_SR, val); + + if (likely(val & (RSR_RI | RSR_DI))) { + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_poll); + napi_schedule_irqoff(&priv->napi); + } + + if (unlikely(val & RSR_DE)) + netdev_err(dev, "RX DMA error\n"); + + /* should never happen with automatic status retrieval */ + if (unlikely(val & RSR_RO)) + netdev_err(dev, "RX Status FIFO overflow\n"); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static void nb8800_mac_config(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + bool gigabit = priv->speed == SPEED_1000; + u32 mac_mode_mask = RGMII_MODE | HALF_DUPLEX | GMAC_MODE; + u32 mac_mode = 0; + u32 slot_time; + u32 phy_clk; + u32 ict; + + if (!priv->duplex) + mac_mode |= HALF_DUPLEX; + + if (gigabit) { + if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII) + mac_mode |= RGMII_MODE; + + mac_mode |= GMAC_MODE; + phy_clk = 125000000; + + /* Should be 512 but register is only 8 bits */ + slot_time = 255; + } else { + phy_clk = 25000000; + slot_time = 128; + } + + ict = DIV_ROUND_UP(phy_clk, clk_get_rate(priv->clk)); + + nb8800_writeb(priv, NB8800_IC_THRESHOLD, ict); + nb8800_writeb(priv, NB8800_SLOT_TIME, slot_time); + nb8800_maskb(priv, NB8800_MAC_MODE, mac_mode_mask, mac_mode); +} + +static void nb8800_pause_config(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + u32 rxcr; + + if (priv->pause_aneg) { + if (!phydev || !phydev->link) + return; + + priv->pause_rx = phydev->pause; + priv->pause_tx = phydev->pause ^ phydev->asym_pause; + } + + nb8800_modb(priv, NB8800_RX_CTL, RX_PAUSE_EN, priv->pause_rx); + + rxcr = nb8800_readl(priv, NB8800_RXC_CR); + if (!!(rxcr & RCR_FL) == priv->pause_tx) + return; + + if (netif_running(dev)) { + napi_disable(&priv->napi); + netif_tx_lock_bh(dev); + nb8800_dma_stop(dev); + nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx); + nb8800_start_rx(dev); + netif_tx_unlock_bh(dev); + napi_enable(&priv->napi); + } else { + nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx); + } +} + +static void nb8800_link_reconfigure(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + int change = 0; + + if (phydev->link) { + if (phydev->speed != priv->speed) { + priv->speed = phydev->speed; + change = 1; + } + + if (phydev->duplex != priv->duplex) { + priv->duplex = phydev->duplex; + change = 1; + } + + if (change) + nb8800_mac_config(dev); + + nb8800_pause_config(dev); + } + + if (phydev->link != priv->link) { + priv->link = phydev->link; + change = 1; + } + + if (change) + phy_print_status(priv->phydev); +} + +static void nb8800_update_mac_addr(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int i; + + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_SRC_ADDR(i), dev->dev_addr[i]); + + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_UC_ADDR(i), dev->dev_addr[i]); +} + +static int nb8800_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sock = addr; + + if (netif_running(dev)) + return -EBUSY; + + ether_addr_copy(dev->dev_addr, sock->sa_data); + nb8800_update_mac_addr(dev); + + return 0; +} + +static void nb8800_mc_init(struct net_device *dev, int val) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + nb8800_writeb(priv, NB8800_MC_INIT, val); + readb_poll_timeout_atomic(priv->base + NB8800_MC_INIT, val, !val, + 1, 1000); +} + +static void nb8800_set_rx_mode(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct netdev_hw_addr *ha; + int i; + + if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { + nb8800_mac_af(dev, false); + return; + } + + nb8800_mac_af(dev, true); + nb8800_mc_init(dev, 0); + + netdev_for_each_mc_addr(ha, dev) { + for (i = 0; i < ETH_ALEN; i++) + nb8800_writeb(priv, NB8800_MC_ADDR(i), ha->addr[i]); + + nb8800_mc_init(dev, 0xff); + } +} + +#define RX_DESC_SIZE (RX_DESC_COUNT * sizeof(struct nb8800_rx_desc)) +#define TX_DESC_SIZE (TX_DESC_COUNT * sizeof(struct nb8800_tx_desc)) + +static void nb8800_dma_free(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int i; + + if (priv->rx_bufs) { + for (i = 0; i < RX_DESC_COUNT; i++) + if (priv->rx_bufs[i].page) + put_page(priv->rx_bufs[i].page); + + kfree(priv->rx_bufs); + priv->rx_bufs = NULL; + } + + if (priv->tx_bufs) { + for (i = 0; i < TX_DESC_COUNT; i++) + kfree_skb(priv->tx_bufs[i].skb); + + kfree(priv->tx_bufs); + priv->tx_bufs = NULL; + } + + if (priv->rx_descs) { + dma_free_coherent(dev->dev.parent, RX_DESC_SIZE, priv->rx_descs, + priv->rx_desc_dma); + priv->rx_descs = NULL; + } + + if (priv->tx_descs) { + dma_free_coherent(dev->dev.parent, TX_DESC_SIZE, priv->tx_descs, + priv->tx_desc_dma); + priv->tx_descs = NULL; + } +} + +static void nb8800_dma_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_rx_desc *rxd; + struct nb8800_tx_desc *txd; + unsigned int i; + + for (i = 0; i < RX_DESC_COUNT; i++) { + dma_addr_t rx_dma = priv->rx_desc_dma + i * sizeof(*rxd); + + rxd = &priv->rx_descs[i]; + rxd->desc.n_addr = rx_dma + sizeof(*rxd); + rxd->desc.r_addr = + rx_dma + offsetof(struct nb8800_rx_desc, report); + rxd->desc.config = priv->rx_dma_config; + rxd->report = 0; + } + + rxd->desc.n_addr = priv->rx_desc_dma; + rxd->desc.config |= DESC_EOC; + + priv->rx_eoc = RX_DESC_COUNT - 1; + + for (i = 0; i < TX_DESC_COUNT; i++) { + struct nb8800_tx_buf *txb = &priv->tx_bufs[i]; + dma_addr_t r_dma = txb->dma_desc + + offsetof(struct nb8800_tx_desc, report); + + txd = &priv->tx_descs[i]; + txd->desc[0].r_addr = r_dma; + txd->desc[1].r_addr = r_dma; + txd->report = 0; + } + + priv->tx_next = 0; + priv->tx_queue = 0; + priv->tx_done = 0; + atomic_set(&priv->tx_free, TX_DESC_COUNT); + + nb8800_writel(priv, NB8800_RX_DESC_ADDR, priv->rx_desc_dma); + + wmb(); /* ensure all setup is written before starting */ +} + +static int nb8800_dma_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + unsigned int n_rx = RX_DESC_COUNT; + unsigned int n_tx = TX_DESC_COUNT; + unsigned int i; + int err; + + priv->rx_descs = dma_alloc_coherent(dev->dev.parent, RX_DESC_SIZE, + &priv->rx_desc_dma, GFP_KERNEL); + if (!priv->rx_descs) + goto err_out; + + priv->rx_bufs = kcalloc(n_rx, sizeof(*priv->rx_bufs), GFP_KERNEL); + if (!priv->rx_bufs) + goto err_out; + + for (i = 0; i < n_rx; i++) { + err = nb8800_alloc_rx(dev, i, false); + if (err) + goto err_out; + } + + priv->tx_descs = dma_alloc_coherent(dev->dev.parent, TX_DESC_SIZE, + &priv->tx_desc_dma, GFP_KERNEL); + if (!priv->tx_descs) + goto err_out; + + priv->tx_bufs = kcalloc(n_tx, sizeof(*priv->tx_bufs), GFP_KERNEL); + if (!priv->tx_bufs) + goto err_out; + + for (i = 0; i < n_tx; i++) + priv->tx_bufs[i].dma_desc = + priv->tx_desc_dma + i * sizeof(struct nb8800_tx_desc); + + nb8800_dma_reset(dev); + + return 0; + +err_out: + nb8800_dma_free(dev); + + return -ENOMEM; +} + +static int nb8800_dma_stop(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + struct nb8800_tx_buf *txb = &priv->tx_bufs[0]; + struct nb8800_tx_desc *txd = &priv->tx_descs[0]; + int retry = 5; + u32 txcr; + u32 rxcr; + int err; + unsigned int i; + + /* wait for tx to finish */ + err = readl_poll_timeout_atomic(priv->base + NB8800_TXC_CR, txcr, + !(txcr & TCR_EN) && + priv->tx_done == priv->tx_next, + 1000, 1000000); + if (err) + return err; + + /* The rx DMA only stops if it reaches the end of chain. + * To make this happen, we set the EOC flag on all rx + * descriptors, put the device in loopback mode, and send + * a few dummy frames. The interrupt handler will ignore + * these since NAPI is disabled and no real frames are in + * the tx queue. + */ + + for (i = 0; i < RX_DESC_COUNT; i++) + priv->rx_descs[i].desc.config |= DESC_EOC; + + txd->desc[0].s_addr = + txb->dma_desc + offsetof(struct nb8800_tx_desc, buf); + txd->desc[0].config = DESC_BTS(2) | DESC_DS | DESC_EOF | DESC_EOC | 8; + memset(txd->buf, 0, sizeof(txd->buf)); + + nb8800_mac_af(dev, false); + nb8800_setb(priv, NB8800_MAC_MODE, LOOPBACK_EN); + + do { + nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc); + wmb(); + nb8800_writel(priv, NB8800_TXC_CR, txcr | TCR_EN); + + err = readl_poll_timeout_atomic(priv->base + NB8800_RXC_CR, + rxcr, !(rxcr & RCR_EN), + 1000, 100000); + } while (err && --retry); + + nb8800_mac_af(dev, true); + nb8800_clearb(priv, NB8800_MAC_MODE, LOOPBACK_EN); + nb8800_dma_reset(dev); + + return retry ? 0 : -ETIMEDOUT; +} + +static void nb8800_pause_adv(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 adv = 0; + + if (!priv->phydev) + return; + + if (priv->pause_rx) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; + if (priv->pause_tx) + adv ^= ADVERTISED_Asym_Pause; + + priv->phydev->supported |= adv; + priv->phydev->advertising |= adv; +} + +static int nb8800_open(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int err; + + /* clear any pending interrupts */ + nb8800_writel(priv, NB8800_RXC_SR, 0xf); + nb8800_writel(priv, NB8800_TXC_SR, 0xf); + + err = nb8800_dma_init(dev); + if (err) + return err; + + err = request_irq(dev->irq, nb8800_irq, 0, dev_name(&dev->dev), dev); + if (err) + goto err_free_dma; + + nb8800_mac_rx(dev, true); + nb8800_mac_tx(dev, true); + + priv->phydev = of_phy_connect(dev, priv->phy_node, + nb8800_link_reconfigure, 0, + priv->phy_mode); + if (!priv->phydev) + goto err_free_irq; + + nb8800_pause_adv(dev); + + netdev_reset_queue(dev); + napi_enable(&priv->napi); + netif_start_queue(dev); + + nb8800_start_rx(dev); + phy_start(priv->phydev); + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_free_dma: + nb8800_dma_free(dev); + + return err; +} + +static int nb8800_stop(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + phy_stop(priv->phydev); + + netif_stop_queue(dev); + napi_disable(&priv->napi); + + nb8800_dma_stop(dev); + nb8800_mac_rx(dev, false); + nb8800_mac_tx(dev, false); + + phy_disconnect(priv->phydev); + priv->phydev = NULL; + + free_irq(dev->irq, dev); + + nb8800_dma_free(dev); + + return 0; +} + +static int nb8800_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + return phy_mii_ioctl(priv->phydev, rq, cmd); +} + +static const struct net_device_ops nb8800_netdev_ops = { + .ndo_open = nb8800_open, + .ndo_stop = nb8800_stop, + .ndo_start_xmit = nb8800_xmit, + .ndo_set_mac_address = nb8800_set_mac_address, + .ndo_set_rx_mode = nb8800_set_rx_mode, + .ndo_do_ioctl = nb8800_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + +static int nb8800_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int nb8800_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int nb8800_nway_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + + return genphy_restart_aneg(priv->phydev); +} + +static void nb8800_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pp) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + pp->autoneg = priv->pause_aneg; + pp->rx_pause = priv->pause_rx; + pp->tx_pause = priv->pause_tx; +} + +static int nb8800_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pp) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + priv->pause_aneg = pp->autoneg; + priv->pause_rx = pp->rx_pause; + priv->pause_tx = pp->tx_pause; + + nb8800_pause_adv(dev); + + if (!priv->pause_aneg) + nb8800_pause_config(dev); + else if (priv->phydev) + phy_start_aneg(priv->phydev); + + return 0; +} + +static const char nb8800_stats_names[][ETH_GSTRING_LEN] = { + "rx_bytes_ok", + "rx_frames_ok", + "rx_undersize_frames", + "rx_fragment_frames", + "rx_64_byte_frames", + "rx_127_byte_frames", + "rx_255_byte_frames", + "rx_511_byte_frames", + "rx_1023_byte_frames", + "rx_max_size_frames", + "rx_oversize_frames", + "rx_bad_fcs_frames", + "rx_broadcast_frames", + "rx_multicast_frames", + "rx_control_frames", + "rx_pause_frames", + "rx_unsup_control_frames", + "rx_align_error_frames", + "rx_overrun_frames", + "rx_jabber_frames", + "rx_bytes", + "rx_frames", + + "tx_bytes_ok", + "tx_frames_ok", + "tx_64_byte_frames", + "tx_127_byte_frames", + "tx_255_byte_frames", + "tx_511_byte_frames", + "tx_1023_byte_frames", + "tx_max_size_frames", + "tx_oversize_frames", + "tx_broadcast_frames", + "tx_multicast_frames", + "tx_control_frames", + "tx_pause_frames", + "tx_underrun_frames", + "tx_single_collision_frames", + "tx_multi_collision_frames", + "tx_deferred_collision_frames", + "tx_late_collision_frames", + "tx_excessive_collision_frames", + "tx_bytes", + "tx_frames", + "tx_collisions", +}; + +#define NB8800_NUM_STATS ARRAY_SIZE(nb8800_stats_names) + +static int nb8800_get_sset_count(struct net_device *dev, int sset) +{ + if (sset == ETH_SS_STATS) + return NB8800_NUM_STATS; + + return -EOPNOTSUPP; +} + +static void nb8800_get_strings(struct net_device *dev, u32 sset, u8 *buf) +{ + if (sset == ETH_SS_STATS) + memcpy(buf, &nb8800_stats_names, sizeof(nb8800_stats_names)); +} + +static u32 nb8800_read_stat(struct net_device *dev, int index) +{ + struct nb8800_priv *priv = netdev_priv(dev); + + nb8800_writeb(priv, NB8800_STAT_INDEX, index); + + return nb8800_readl(priv, NB8800_STAT_DATA); +} + +static void nb8800_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *estats, u64 *st) +{ + unsigned int i; + u32 rx, tx; + + for (i = 0; i < NB8800_NUM_STATS / 2; i++) { + rx = nb8800_read_stat(dev, i); + tx = nb8800_read_stat(dev, i | 0x80); + st[i] = rx; + st[i + NB8800_NUM_STATS / 2] = tx; + } +} + +static const struct ethtool_ops nb8800_ethtool_ops = { + .get_settings = nb8800_get_settings, + .set_settings = nb8800_set_settings, + .nway_reset = nb8800_nway_reset, + .get_link = ethtool_op_get_link, + .get_pauseparam = nb8800_get_pauseparam, + .set_pauseparam = nb8800_set_pauseparam, + .get_sset_count = nb8800_get_sset_count, + .get_strings = nb8800_get_strings, + .get_ethtool_stats = nb8800_get_ethtool_stats, +}; + +static int nb8800_hw_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 val; + + val = TX_RETRY_EN | TX_PAD_EN | TX_APPEND_FCS; + nb8800_writeb(priv, NB8800_TX_CTL1, val); + + /* Collision retry count */ + nb8800_writeb(priv, NB8800_TX_CTL2, 5); + + val = RX_PAD_STRIP | RX_AF_EN; + nb8800_writeb(priv, NB8800_RX_CTL, val); + + /* Chosen by fair dice roll */ + nb8800_writeb(priv, NB8800_RANDOM_SEED, 4); + + /* TX cycles per deferral period */ + nb8800_writeb(priv, NB8800_TX_SDP, 12); + + /* The following three threshold values have been + * experimentally determined for good results. + */ + + /* RX/TX FIFO threshold for partial empty (64-bit entries) */ + nb8800_writeb(priv, NB8800_PE_THRESHOLD, 0); + + /* RX/TX FIFO threshold for partial full (64-bit entries) */ + nb8800_writeb(priv, NB8800_PF_THRESHOLD, 255); + + /* Buffer size for transmit (64-bit entries) */ + nb8800_writeb(priv, NB8800_TX_BUFSIZE, 64); + + /* Configure tx DMA */ + + val = nb8800_readl(priv, NB8800_TXC_CR); + val &= TCR_LE; /* keep endian setting */ + val |= TCR_DM; /* DMA descriptor mode */ + val |= TCR_RS; /* automatically store tx status */ + val |= TCR_DIE; /* interrupt on DMA chain completion */ + val |= TCR_TFI(7); /* interrupt after 7 frames transmitted */ + val |= TCR_BTS(2); /* 32-byte bus transaction size */ + nb8800_writel(priv, NB8800_TXC_CR, val); + + /* TX complete interrupt after 10 ms or 7 frames (see above) */ + val = clk_get_rate(priv->clk) / 100; + nb8800_writel(priv, NB8800_TX_ITR, val); + + /* Configure rx DMA */ + + val = nb8800_readl(priv, NB8800_RXC_CR); + val &= RCR_LE; /* keep endian setting */ + val |= RCR_DM; /* DMA descriptor mode */ + val |= RCR_RS; /* automatically store rx status */ + val |= RCR_DIE; /* interrupt at end of DMA chain */ + val |= RCR_RFI(7); /* interrupt after 7 frames received */ + val |= RCR_BTS(2); /* 32-byte bus transaction size */ + nb8800_writel(priv, NB8800_RXC_CR, val); + + /* The rx interrupt can fire before the DMA has completed + * unless a small delay is added. 50 us is hopefully enough. + */ + priv->rx_itr_irq = clk_get_rate(priv->clk) / 20000; + + /* In NAPI poll mode we want to disable interrupts, but the + * hardware does not permit this. Delay 10 ms instead. + */ + priv->rx_itr_poll = clk_get_rate(priv->clk) / 100; + + nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq); + + priv->rx_dma_config = RX_BUF_SIZE | DESC_BTS(2) | DESC_DS | DESC_EOF; + + /* Flow control settings */ + + /* Pause time of 0.1 ms */ + val = 100000 / 512; + nb8800_writeb(priv, NB8800_PQ1, val >> 8); + nb8800_writeb(priv, NB8800_PQ2, val & 0xff); + + /* Auto-negotiate by default */ + priv->pause_aneg = true; + priv->pause_rx = true; + priv->pause_tx = true; + + nb8800_mc_init(dev, 0); + + return 0; +} + +static int nb8800_tangox_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + u32 pad_mode = PAD_MODE_MII; + + switch (priv->phy_mode) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + pad_mode = PAD_MODE_MII; + break; + + case PHY_INTERFACE_MODE_RGMII: + pad_mode = PAD_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_RGMII_TXID: + pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY; + break; + + default: + dev_err(dev->dev.parent, "unsupported phy mode %s\n", + phy_modes(priv->phy_mode)); + return -EINVAL; + } + + nb8800_writeb(priv, NB8800_TANGOX_PAD_MODE, pad_mode); + + return 0; +} + +static int nb8800_tangox_reset(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int clk_div; + + nb8800_writeb(priv, NB8800_TANGOX_RESET, 0); + usleep_range(1000, 10000); + nb8800_writeb(priv, NB8800_TANGOX_RESET, 1); + + wmb(); /* ensure reset is cleared before proceeding */ + + clk_div = DIV_ROUND_UP(clk_get_rate(priv->clk), 2 * MAX_MDC_CLOCK); + nb8800_writew(priv, NB8800_TANGOX_MDIO_CLKDIV, clk_div); + + return 0; +} + +static const struct nb8800_ops nb8800_tangox_ops = { + .init = nb8800_tangox_init, + .reset = nb8800_tangox_reset, +}; + +static int nb8800_tango4_init(struct net_device *dev) +{ + struct nb8800_priv *priv = netdev_priv(dev); + int err; + + err = nb8800_tangox_init(dev); + if (err) + return err; + + /* On tango4 interrupt on DMA completion per frame works and gives + * better performance despite generating more rx interrupts. + */ + + /* Disable unnecessary interrupt on rx completion */ + nb8800_clearl(priv, NB8800_RXC_CR, RCR_RFI(7)); + + /* Request interrupt on descriptor DMA completion */ + priv->rx_dma_config |= DESC_ID; + + return 0; +} + +static const struct nb8800_ops nb8800_tango4_ops = { + .init = nb8800_tango4_init, + .reset = nb8800_tangox_reset, +}; + +static const struct of_device_id nb8800_dt_ids[] = { + { + .compatible = "aurora,nb8800", + }, + { + .compatible = "sigma,smp8642-ethernet", + .data = &nb8800_tangox_ops, + }, + { + .compatible = "sigma,smp8734-ethernet", + .data = &nb8800_tango4_ops, + }, + { } +}; + +static int nb8800_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct nb8800_ops *ops = NULL; + struct nb8800_priv *priv; + struct resource *res; + struct net_device *dev; + struct mii_bus *bus; + const unsigned char *mac; + void __iomem *base; + int irq; + int ret; + + match = of_match_device(nb8800_dt_ids, &pdev->dev); + if (match) + ops = match->data; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "No IRQ\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + dev_dbg(&pdev->dev, "AU-NB8800 Ethernet at %pa\n", &res->start); + + dev = alloc_etherdev(sizeof(*priv)); + if (!dev) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + priv = netdev_priv(dev); + priv->base = base; + + priv->phy_mode = of_get_phy_mode(pdev->dev.of_node); + if (priv->phy_mode < 0) + priv->phy_mode = PHY_INTERFACE_MODE_RGMII; + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); + goto err_free_dev; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto err_free_dev; + + spin_lock_init(&priv->tx_lock); + + if (ops && ops->reset) { + ret = ops->reset(dev); + if (ret) + goto err_free_dev; + } + + bus = devm_mdiobus_alloc(&pdev->dev); + if (!bus) { + ret = -ENOMEM; + goto err_disable_clk; + } + + bus->name = "nb8800-mii"; + bus->read = nb8800_mdio_read; + bus->write = nb8800_mdio_write; + bus->parent = &pdev->dev; + snprintf(bus->id, MII_BUS_ID_SIZE, "%lx.nb8800-mii", + (unsigned long)res->start); + bus->priv = priv; + + ret = of_mdiobus_register(bus, pdev->dev.of_node); + if (ret) { + dev_err(&pdev->dev, "failed to register MII bus\n"); + goto err_disable_clk; + } + + priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + if (!priv->phy_node) { + dev_err(&pdev->dev, "no PHY specified\n"); + ret = -ENODEV; + goto err_free_bus; + } + + priv->mii_bus = bus; + + ret = nb8800_hw_init(dev); + if (ret) + goto err_free_bus; + + if (ops && ops->init) { + ret = ops->init(dev); + if (ret) + goto err_free_bus; + } + + dev->netdev_ops = &nb8800_netdev_ops; + dev->ethtool_ops = &nb8800_ethtool_ops; + dev->flags |= IFF_MULTICAST; + dev->irq = irq; + + mac = of_get_mac_address(pdev->dev.of_node); + if (mac) + ether_addr_copy(dev->dev_addr, mac); + + if (!is_valid_ether_addr(dev->dev_addr)) + eth_hw_addr_random(dev); + + nb8800_update_mac_addr(dev); + + netif_carrier_off(dev); + + ret = register_netdev(dev); + if (ret) { + netdev_err(dev, "failed to register netdev\n"); + goto err_free_dma; + } + + netif_napi_add(dev, &priv->napi, nb8800_poll, NAPI_POLL_WEIGHT); + + netdev_info(dev, "MAC address %pM\n", dev->dev_addr); + + return 0; + +err_free_dma: + nb8800_dma_free(dev); +err_free_bus: + mdiobus_unregister(bus); +err_disable_clk: + clk_disable_unprepare(priv->clk); +err_free_dev: + free_netdev(dev); + + return ret; +} + +static int nb8800_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct nb8800_priv *priv = netdev_priv(ndev); + + unregister_netdev(ndev); + + mdiobus_unregister(priv->mii_bus); + + clk_disable_unprepare(priv->clk); + + nb8800_dma_free(ndev); + free_netdev(ndev); + + return 0; +} + +static struct platform_driver nb8800_driver = { + .driver = { + .name = "nb8800", + .of_match_table = nb8800_dt_ids, + }, + .probe = nb8800_probe, + .remove = nb8800_remove, +}; + +module_platform_driver(nb8800_driver); + +MODULE_DESCRIPTION("Aurora AU-NB8800 Ethernet driver"); +MODULE_AUTHOR("Mans Rullgard "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/aurora/nb8800.h b/drivers/net/ethernet/aurora/nb8800.h new file mode 100644 index 0000000..e5adbc2 --- /dev/null +++ b/drivers/net/ethernet/aurora/nb8800.h @@ -0,0 +1,316 @@ +#ifndef _NB8800_H_ +#define _NB8800_H_ + +#include +#include +#include +#include +#include + +#define RX_DESC_COUNT 256 +#define TX_DESC_COUNT 256 + +#define NB8800_DESC_LOW 4 + +#define RX_BUF_SIZE 1552 + +#define RX_COPYBREAK 256 +#define RX_COPYHDR 128 + +#define MAX_MDC_CLOCK 2500000 + +/* Stargate Solutions SSN8800 core registers */ +#define NB8800_TX_CTL1 0x000 +#define TX_TPD BIT(5) +#define TX_APPEND_FCS BIT(4) +#define TX_PAD_EN BIT(3) +#define TX_RETRY_EN BIT(2) +#define TX_EN BIT(0) + +#define NB8800_TX_CTL2 0x001 + +#define NB8800_RX_CTL 0x004 +#define RX_BC_DISABLE BIT(7) +#define RX_RUNT BIT(6) +#define RX_AF_EN BIT(5) +#define RX_PAUSE_EN BIT(3) +#define RX_SEND_CRC BIT(2) +#define RX_PAD_STRIP BIT(1) +#define RX_EN BIT(0) + +#define NB8800_RANDOM_SEED 0x008 +#define NB8800_TX_SDP 0x14 +#define NB8800_TX_TPDP1 0x18 +#define NB8800_TX_TPDP2 0x19 +#define NB8800_SLOT_TIME 0x1c + +#define NB8800_MDIO_CMD 0x020 +#define MDIO_CMD_GO BIT(31) +#define MDIO_CMD_WR BIT(26) +#define MDIO_CMD_ADDR(x) ((x) << 21) +#define MDIO_CMD_REG(x) ((x) << 16) +#define MDIO_CMD_DATA(x) ((x) << 0) + +#define NB8800_MDIO_STS 0x024 +#define MDIO_STS_ERR BIT(31) + +#define NB8800_MC_ADDR(i) (0x028 + (i)) +#define NB8800_MC_INIT 0x02e +#define NB8800_UC_ADDR(i) (0x03c + (i)) + +#define NB8800_MAC_MODE 0x044 +#define RGMII_MODE BIT(7) +#define HALF_DUPLEX BIT(4) +#define BURST_EN BIT(3) +#define LOOPBACK_EN BIT(2) +#define GMAC_MODE BIT(0) + +#define NB8800_IC_THRESHOLD 0x050 +#define NB8800_PE_THRESHOLD 0x051 +#define NB8800_PF_THRESHOLD 0x052 +#define NB8800_TX_BUFSIZE 0x054 +#define NB8800_FIFO_CTL 0x056 +#define NB8800_PQ1 0x060 +#define NB8800_PQ2 0x061 +#define NB8800_SRC_ADDR(i) (0x06a + (i)) +#define NB8800_STAT_DATA 0x078 +#define NB8800_STAT_INDEX 0x07c +#define NB8800_STAT_CLEAR 0x07d + +#define NB8800_SLEEP_MODE 0x07e +#define SLEEP_MODE BIT(0) + +#define NB8800_WAKEUP 0x07f +#define WAKEUP BIT(0) + +/* Aurora NB8800 host interface registers */ +#define NB8800_TXC_CR 0x100 +#define TCR_LK BIT(12) +#define TCR_DS BIT(11) +#define TCR_BTS(x) (((x) & 0x7) << 8) +#define TCR_DIE BIT(7) +#define TCR_TFI(x) (((x) & 0x7) << 4) +#define TCR_LE BIT(3) +#define TCR_RS BIT(2) +#define TCR_DM BIT(1) +#define TCR_EN BIT(0) + +#define NB8800_TXC_SR 0x104 +#define TSR_DE BIT(3) +#define TSR_DI BIT(2) +#define TSR_TO BIT(1) +#define TSR_TI BIT(0) + +#define NB8800_TX_SAR 0x108 +#define NB8800_TX_DESC_ADDR 0x10c + +#define NB8800_TX_REPORT_ADDR 0x110 +#define TX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xffff) +#define TX_FIRST_DEFERRAL BIT(7) +#define TX_EARLY_COLLISIONS(x) (((x) >> 3) & 0xf) +#define TX_LATE_COLLISION BIT(2) +#define TX_PACKET_DROPPED BIT(1) +#define TX_FIFO_UNDERRUN BIT(0) +#define IS_TX_ERROR(r) ((r) & 0x07) + +#define NB8800_TX_FIFO_SR 0x114 +#define NB8800_TX_ITR 0x118 + +#define NB8800_RXC_CR 0x200 +#define RCR_FL BIT(13) +#define RCR_LK BIT(12) +#define RCR_DS BIT(11) +#define RCR_BTS(x) (((x) & 7) << 8) +#define RCR_DIE BIT(7) +#define RCR_RFI(x) (((x) & 7) << 4) +#define RCR_LE BIT(3) +#define RCR_RS BIT(2) +#define RCR_DM BIT(1) +#define RCR_EN BIT(0) + +#define NB8800_RXC_SR 0x204 +#define RSR_DE BIT(3) +#define RSR_DI BIT(2) +#define RSR_RO BIT(1) +#define RSR_RI BIT(0) + +#define NB8800_RX_SAR 0x208 +#define NB8800_RX_DESC_ADDR 0x20c + +#define NB8800_RX_REPORT_ADDR 0x210 +#define RX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xFFFF) +#define RX_MULTICAST_PKT BIT(9) +#define RX_BROADCAST_PKT BIT(8) +#define RX_LENGTH_ERR BIT(7) +#define RX_FCS_ERR BIT(6) +#define RX_RUNT_PKT BIT(5) +#define RX_FIFO_OVERRUN BIT(4) +#define RX_LATE_COLLISION BIT(3) +#define RX_ALIGNMENT_ERROR BIT(2) +#define RX_ERROR_MASK 0xfc +#define IS_RX_ERROR(r) ((r) & RX_ERROR_MASK) + +#define NB8800_RX_FIFO_SR 0x214 +#define NB8800_RX_ITR 0x218 + +/* Sigma Designs SMP86xx additional registers */ +#define NB8800_TANGOX_PAD_MODE 0x400 +#define PAD_MODE_MASK 0x7 +#define PAD_MODE_MII 0x0 +#define PAD_MODE_RGMII 0x1 +#define PAD_MODE_GTX_CLK_INV BIT(3) +#define PAD_MODE_GTX_CLK_DELAY BIT(4) + +#define NB8800_TANGOX_MDIO_CLKDIV 0x420 +#define NB8800_TANGOX_RESET 0x424 + +/* Hardware DMA descriptor */ +struct nb8800_dma_desc { + u32 s_addr; /* start address */ + u32 n_addr; /* next descriptor address */ + u32 r_addr; /* report address */ + u32 config; +} __aligned(8); + +#define DESC_ID BIT(23) +#define DESC_EOC BIT(22) +#define DESC_EOF BIT(21) +#define DESC_LK BIT(20) +#define DESC_DS BIT(19) +#define DESC_BTS(x) (((x) & 0x7) << 16) + +/* DMA descriptor and associated data for rx. + * Allocated from coherent memory. + */ +struct nb8800_rx_desc { + /* DMA descriptor */ + struct nb8800_dma_desc desc; + + /* Status report filled in by hardware */ + u32 report; +}; + +/* Address of buffer on rx ring */ +struct nb8800_rx_buf { + struct page *page; + unsigned long offset; +}; + +/* DMA descriptors and associated data for tx. + * Allocated from coherent memory. + */ +struct nb8800_tx_desc { + /* DMA descriptor. The second descriptor is used if packet + * data is unaligned. + */ + struct nb8800_dma_desc desc[2]; + + /* Status report filled in by hardware */ + u32 report; + + /* Bounce buffer for initial unaligned part of packet */ + u8 buf[8] __aligned(8); +}; + +/* Packet in tx queue */ +struct nb8800_tx_buf { + /* Currently queued skb */ + struct sk_buff *skb; + + /* DMA address of the first descriptor */ + dma_addr_t dma_desc; + + /* DMA address of packet data */ + dma_addr_t dma_addr; + + /* Length of DMA mapping, less than skb->len if alignment + * buffer is used. + */ + unsigned int dma_len; + + /* Number of packets in chain starting here */ + unsigned int chain_len; + + /* Packet chain ready to be submitted to hardware */ + bool ready; +}; + +struct nb8800_priv { + struct napi_struct napi; + + void __iomem *base; + + /* RX DMA descriptors */ + struct nb8800_rx_desc *rx_descs; + + /* RX buffers referenced by DMA descriptors */ + struct nb8800_rx_buf *rx_bufs; + + /* Current end of chain */ + u32 rx_eoc; + + /* Value for rx interrupt time register in NAPI interrupt mode */ + u32 rx_itr_irq; + + /* Value for rx interrupt time register in NAPI poll mode */ + u32 rx_itr_poll; + + /* Value for config field of rx DMA descriptors */ + u32 rx_dma_config; + + /* TX DMA descriptors */ + struct nb8800_tx_desc *tx_descs; + + /* TX packet queue */ + struct nb8800_tx_buf *tx_bufs; + + /* Number of free tx queue entries */ + atomic_t tx_free; + + /* First free tx queue entry */ + u32 tx_next; + + /* Next buffer to transmit */ + u32 tx_queue; + + /* Start of current packet chain */ + struct nb8800_tx_buf *tx_chain; + + /* Next buffer to reclaim */ + u32 tx_done; + + /* Lock for DMA activation */ + spinlock_t tx_lock; + + struct mii_bus *mii_bus; + struct device_node *phy_node; + struct phy_device *phydev; + + /* PHY connection type from DT */ + int phy_mode; + + /* Current link status */ + int speed; + int duplex; + int link; + + /* Pause settings */ + bool pause_aneg; + bool pause_rx; + bool pause_tx; + + /* DMA base address of rx descriptors, see rx_descs above */ + dma_addr_t rx_desc_dma; + + /* DMA base address of tx descriptors, see tx_descs above */ + dma_addr_t tx_desc_dma; + + struct clk *clk; +}; + +struct nb8800_ops { + int (*init)(struct net_device *dev); + int (*reset)(struct net_device *dev); +}; + +#endif /* _NB8800_H_ */ -- cgit v0.10.2 From 9a65083827da0da5fadf9dea5bca25192073b112 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 19 Nov 2015 14:12:50 -0500 Subject: tipc: correct settings of broadcast link state Since commit 5266698661401afc5e ("tipc: let broadcast packet reception use new link receive function") the broadcast send link state was meant to always be set to LINK_ESTABLISHED, since we don't need this link to follow the regular link FSM rules. It was also the intention that this state anyway shouldn't impact the run-time working state of the link, since the latter in reality is controlled by the number of registered peers. We have now discovered that this assumption is not quite correct. If the broadcast link is reset because of too many retransmissions, its state will inadvertently go to LINK_RESETTING, and never go back to LINK_ESTABLISHED, because the LINK_FAILURE event was not anticipated. This will work well once, but if it happens a second time, the reset on a link in LINK_RESETTING has has no effect, and neither the broadcast link nor the unicast links will go down as they should. Furthermore, it is confusing that the management tool shows that this link is in UP state when that obviously isn't the case. We now ensure that this state strictly follows the true working state of the link. The state is set to LINK_ESTABLISHED when the number of peers is non-zero, and to LINK_RESET otherwise. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller diff --git a/net/tipc/link.c b/net/tipc/link.c index 9efbdbd..91aea07 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -191,6 +191,7 @@ void tipc_link_add_bc_peer(struct tipc_link *snd_l, snd_l->ackers++; rcv_l->acked = snd_l->snd_nxt - 1; + snd_l->state = LINK_ESTABLISHED; tipc_link_build_bc_init_msg(uc_l, xmitq); } @@ -206,6 +207,7 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l, rcv_l->state = LINK_RESET; if (!snd_l->ackers) { tipc_link_reset(snd_l); + snd_l->state = LINK_RESET; __skb_queue_purge(xmitq); } } -- cgit v0.10.2 From 4f1dd973acffeb67142d39f3bfbc4dd0569f2da6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Nov 2015 15:16:30 +0100 Subject: sata/mvebu: use #ifdef around suspend/resume code The newly added suspend/resume implementation for ahci_mvebu causes a link error when CONFIG_PM_SLEEP is disabled: ERROR: "ahci_platform_suspend_host" [drivers/ata/ahci_mvebu.ko] undefined! ERROR: "ahci_platform_resume_host" [drivers/ata/ahci_mvebu.ko] undefined! This adds the same #ifdef here that exists in the ahci_platform driver which defines the above functions. Signed-off-by: Arnd Bergmann Fixes: d6ecf1581488 ("ata: ahci_mvebu: add suspend/resume support") Acked-by: Thomas Petazzoni Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 8490d37..f7a7fa8 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -62,6 +62,7 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); } +#ifdef CONFIG_PM_SLEEP static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state) { return ahci_platform_suspend_host(&pdev->dev); @@ -81,6 +82,10 @@ static int ahci_mvebu_resume(struct platform_device *pdev) return ahci_platform_resume_host(&pdev->dev); } +#else +#define ahci_mvebu_suspend NULL +#define ahci_mvebu_resume NULL +#endif static const struct ata_port_info ahci_mvebu_port_info = { .flags = AHCI_FLAG_COMMON, -- cgit v0.10.2 From d6c29c30eaac8a0d6c8c8f44a2c61d3443c51707 Mon Sep 17 00:00:00 2001 From: Leo Liu Date: Tue, 17 Nov 2015 09:28:29 -0500 Subject: drm/amdgpu: reset vce trap interrupt flag Signed-off-by: Leo Liu Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 6a52db6..3acff3a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -576,6 +576,11 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { DRM_DEBUG("IH: VCE\n"); + + WREG32_P(mmVCE_SYS_INT_STATUS, + VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK, + ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK); + switch (entry->src_data) { case 0: amdgpu_fence_process(&adev->vce.ring[0]); -- cgit v0.10.2 From 3c0ff9f18f8239f5a8a4e251fef79384af3d935c Mon Sep 17 00:00:00 2001 From: Leo Liu Date: Tue, 17 Nov 2015 10:25:31 -0500 Subject: drm/amdgpu: vce use multiple cache surface starting from stoney Signed-off-by: Leo Liu Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 3acff3a..370c6c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -40,6 +40,9 @@ #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 +#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 +#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 +#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 #define VCE_V3_0_FW_SIZE (384 * 1024) #define VCE_V3_0_STACK_SIZE (64 * 1024) @@ -130,9 +133,11 @@ static int vce_v3_0_start(struct amdgpu_device *adev) /* set BUSY flag */ WREG32_P(mmVCE_STATUS, 1, ~1); - - WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, - ~VCE_VCPU_CNTL__CLK_EN_MASK); + if (adev->asic_type >= CHIP_STONEY) + WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001); + else + WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK, + ~VCE_VCPU_CNTL__CLK_EN_MASK); WREG32_P(mmVCE_SOFT_RESET, VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK, @@ -391,8 +396,12 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) WREG32(mmVCE_LMI_SWAP_CNTL, 0); WREG32(mmVCE_LMI_SWAP_CNTL1, 0); WREG32(mmVCE_LMI_VM_CTRL, 0); - - WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); + if (adev->asic_type >= CHIP_STONEY) { + WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8)); + WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8)); + WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8)); + } else + WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8)); offset = AMDGPU_VCE_FIRMWARE_OFFSET; size = VCE_V3_0_FW_SIZE; WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff); -- cgit v0.10.2 From d66f8e48f1201620eeb0a11df4c2071f7ee35750 Mon Sep 17 00:00:00 2001 From: Leo Liu Date: Wed, 18 Nov 2015 11:57:33 -0500 Subject: drm/amdgpu: adapt vce session create interface changes Signed-off-by: Leo Liu Reviewed-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 03f0c3b..a745eee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -392,7 +392,10 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ ib->ptr[ib->length_dw++] = handle; - ib->ptr[ib->length_dw++] = 0x00000030; /* len */ + if ((ring->adev->vce.fw_version >> 24) >= 52) + ib->ptr[ib->length_dw++] = 0x00000040; /* len */ + else + ib->ptr[ib->length_dw++] = 0x00000030; /* len */ ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */ ib->ptr[ib->length_dw++] = 0x00000000; ib->ptr[ib->length_dw++] = 0x00000042; @@ -404,6 +407,12 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, ib->ptr[ib->length_dw++] = 0x00000100; ib->ptr[ib->length_dw++] = 0x0000000c; ib->ptr[ib->length_dw++] = 0x00000000; + if ((ring->adev->vce.fw_version >> 24) >= 52) { + ib->ptr[ib->length_dw++] = 0x00000000; + ib->ptr[ib->length_dw++] = 0x00000000; + ib->ptr[ib->length_dw++] = 0x00000000; + ib->ptr[ib->length_dw++] = 0x00000000; + } ib->ptr[ib->length_dw++] = 0x00000014; /* len */ ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */ -- cgit v0.10.2 From 69b576a1bc8b466ae7bff0208f1c139dbaaf802c Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Wed, 18 Nov 2015 11:17:39 +0800 Subject: drm/amdgpu: add mutex for ba_va->valids/invalids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Chunming 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 306f757..50672bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -496,6 +496,7 @@ struct amdgpu_bo_va_mapping { /* bo virtual addresses in a specific vm */ struct amdgpu_bo_va { + struct mutex mutex; /* protected by bo being reserved */ struct list_head bo_list; struct fence *last_pt_update; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 159ce54..d6904ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -922,8 +922,9 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va, vm_status); spin_unlock(&vm->status_lock); - + mutex_lock(&bo_va->mutex); r = amdgpu_vm_bo_update(adev, bo_va, NULL); + mutex_unlock(&bo_va->mutex); if (r) return r; @@ -967,7 +968,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev, INIT_LIST_HEAD(&bo_va->valids); INIT_LIST_HEAD(&bo_va->invalids); INIT_LIST_HEAD(&bo_va->vm_status); - + mutex_init(&bo_va->mutex); list_add_tail(&bo_va->bo_list, &bo->va); return bo_va; @@ -1045,7 +1046,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, mapping->offset = offset; mapping->flags = flags; + mutex_lock(&bo_va->mutex); list_add(&mapping->list, &bo_va->invalids); + mutex_unlock(&bo_va->mutex); spin_lock(&vm->it_lock); interval_tree_insert(&mapping->it, &vm->va); spin_unlock(&vm->it_lock); @@ -1121,7 +1124,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, bool valid = true; saddr /= AMDGPU_GPU_PAGE_SIZE; - + mutex_lock(&bo_va->mutex); list_for_each_entry(mapping, &bo_va->valids, list) { if (mapping->it.start == saddr) break; @@ -1135,10 +1138,12 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, break; } - if (&mapping->list == &bo_va->invalids) + if (&mapping->list == &bo_va->invalids) { + mutex_unlock(&bo_va->mutex); return -ENOENT; + } } - + mutex_unlock(&bo_va->mutex); list_del(&mapping->list); spin_lock(&vm->it_lock); interval_tree_remove(&mapping->it, &vm->va); @@ -1190,8 +1195,8 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, spin_unlock(&vm->it_lock); kfree(mapping); } - fence_put(bo_va->last_pt_update); + mutex_destroy(&bo_va->mutex); kfree(bo_va); } -- cgit v0.10.2 From e98c1b0de6fe73f488df62d83d83f377b1b6e2b8 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Fri, 13 Nov 2015 15:22:04 +0800 Subject: drm/amdgpu: remove vm->mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Chunming 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 50672bb..251b147 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -929,8 +929,6 @@ struct amdgpu_vm_id { }; struct amdgpu_vm { - struct mutex mutex; - struct rb_root va; /* protecting invalidated */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 3afcf02..1d44d50 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -784,8 +784,6 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = dev->dev_private; union drm_amdgpu_cs *cs = data; - struct amdgpu_fpriv *fpriv = filp->driver_priv; - struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_cs_parser parser = {}; bool reserved_buffers = false; int i, r; @@ -803,7 +801,6 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) r = amdgpu_cs_handle_lockup(adev, r); return r; } - mutex_lock(&vm->mutex); r = amdgpu_cs_parser_relocs(&parser); if (r == -ENOMEM) DRM_ERROR("Not enough memory for command submission!\n"); @@ -888,7 +885,6 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) out: amdgpu_cs_parser_fini(&parser, r, reserved_buffers); - mutex_unlock(&vm->mutex); r = amdgpu_cs_handle_lockup(adev, r); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 00c5b58..fc32fc0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -115,12 +115,9 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_va *bo_va; int r; - mutex_lock(&vm->mutex); r = amdgpu_bo_reserve(rbo, false); - if (r) { - mutex_unlock(&vm->mutex); + if (r) return r; - } bo_va = amdgpu_vm_bo_find(vm, rbo); if (!bo_va) { @@ -129,7 +126,6 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri ++bo_va->ref_count; } amdgpu_bo_unreserve(rbo); - mutex_unlock(&vm->mutex); return 0; } @@ -142,10 +138,8 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj, struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_va *bo_va; int r; - mutex_lock(&vm->mutex); r = amdgpu_bo_reserve(rbo, true); if (r) { - mutex_unlock(&vm->mutex); dev_err(adev->dev, "leaking bo va because " "we fail to reserve bo (%d)\n", r); return; @@ -157,7 +151,6 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj, } } amdgpu_bo_unreserve(rbo); - mutex_unlock(&vm->mutex); } static int amdgpu_gem_handle_lockup(struct amdgpu_device *adev, int r) @@ -553,7 +546,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, gobj = drm_gem_object_lookup(dev, filp, args->handle); if (gobj == NULL) return -ENOENT; - mutex_lock(&fpriv->vm.mutex); rbo = gem_to_amdgpu_bo(gobj); INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&duplicates); @@ -568,7 +560,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, } r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates); if (r) { - mutex_unlock(&fpriv->vm.mutex); drm_gem_object_unreference_unlocked(gobj); return r; } @@ -577,7 +568,6 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, if (!bo_va) { ttm_eu_backoff_reservation(&ticket, &list); drm_gem_object_unreference_unlocked(gobj); - mutex_unlock(&fpriv->vm.mutex); return -ENOENT; } @@ -602,7 +592,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ttm_eu_backoff_reservation(&ticket, &list); if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE)) amdgpu_gem_va_update_vm(adev, bo_va, args->operation); - mutex_unlock(&fpriv->vm.mutex); + drm_gem_object_unreference_unlocked(gobj); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d6904ef..ae037e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1241,7 +1241,6 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) vm->ids[i].id = 0; vm->ids[i].flushed_updates = NULL; } - mutex_init(&vm->mutex); vm->va = RB_ROOT; spin_lock_init(&vm->status_lock); INIT_LIST_HEAD(&vm->invalidated); @@ -1325,7 +1324,6 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) fence_put(vm->ids[i].flushed_updates); } - mutex_destroy(&vm->mutex); } /** -- cgit v0.10.2 From b094f89ca42fbb8ce40174d5f85ca8430e499da6 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 20 Nov 2015 20:29:45 -0700 Subject: blk-mq: fix calling unplug callbacks with preempt disabled Liu reported that running certain parts of xfstests threw the following error: BUG: sleeping function called from invalid context at mm/page_alloc.c:3190 in_atomic(): 1, irqs_disabled(): 0, pid: 6, name: kworker/u16:0 3 locks held by kworker/u16:0/6: #0: ("writeback"){++++.+}, at: [] process_one_work+0x173/0x730 #1: ((&(&wb->dwork)->work)){+.+.+.}, at: [] process_one_work+0x173/0x730 #2: (&type->s_umount_key#44){+++++.}, at: [] trylock_super+0x25/0x60 CPU: 5 PID: 6 Comm: kworker/u16:0 Tainted: G OE 4.3.0+ #3 Hardware name: Red Hat KVM, BIOS Bochs 01/01/2011 Workqueue: writeback wb_workfn (flush-btrfs-108) ffffffff81a3abab ffff88042e282ba8 ffffffff8130191b ffffffff81a3abab 0000000000000c76 ffff88042e282ba8 ffff88042e27c180 ffff88042e282bd8 ffffffff8108ed95 ffff880400000004 0000000000000000 0000000000000c76 Call Trace: [] dump_stack+0x4f/0x74 [] ___might_sleep+0x185/0x240 [] __might_sleep+0x52/0x90 [] __alloc_pages_nodemask+0x268/0x410 [] ? sched_clock_local+0x1c/0x90 [] ? local_clock+0x21/0x40 [] ? __lock_release+0x420/0x510 [] ? __lock_acquired+0x16c/0x3c0 [] alloc_pages_current+0xc5/0x210 [] ? rbio_is_full+0x55/0x70 [btrfs] [] ? mark_held_locks+0x78/0xa0 [] ? _raw_spin_unlock_irqrestore+0x40/0x60 [] full_stripe_write+0x5a/0xc0 [btrfs] [] __raid56_parity_write+0x39/0x60 [btrfs] [] run_plug+0x11b/0x140 [btrfs] [] btrfs_raid_unplug+0x23/0x70 [btrfs] [] blk_flush_plug_list+0x82/0x1f0 [] blk_sq_make_request+0x1f9/0x740 [] ? generic_make_request_checks+0x222/0x7c0 [] ? blk_queue_enter+0x124/0x310 [] ? blk_queue_enter+0x92/0x310 [] generic_make_request+0x172/0x2c0 [] ? generic_make_request+0x164/0x2c0 [] submit_bio+0x70/0x140 [] ? rbio_add_io_page+0x99/0x150 [btrfs] [] finish_rmw+0x4d9/0x600 [btrfs] [] full_stripe_write+0x9c/0xc0 [btrfs] [] raid56_parity_write+0xef/0x160 [btrfs] [] btrfs_map_bio+0xe3/0x2d0 [btrfs] [] btrfs_submit_bio_hook+0x8d/0x1d0 [btrfs] [] submit_one_bio+0x74/0xb0 [btrfs] [] submit_extent_page+0xe5/0x1c0 [btrfs] [] __extent_writepage_io+0x408/0x4c0 [btrfs] [] ? alloc_dummy_extent_buffer+0x140/0x140 [btrfs] [] __extent_writepage+0x218/0x3a0 [btrfs] [] ? mark_held_locks+0x78/0xa0 [] extent_write_cache_pages.clone.0+0x2f9/0x400 [btrfs] [] extent_writepages+0x52/0x70 [btrfs] [] ? btrfs_set_inode_index+0x70/0x70 [btrfs] [] btrfs_writepages+0x27/0x30 [btrfs] [] do_writepages+0x23/0x40 [] __writeback_single_inode+0x89/0x4d0 [] ? writeback_sb_inodes+0x260/0x480 [] ? writeback_sb_inodes+0x260/0x480 [] ? writeback_sb_inodes+0x15f/0x480 [] writeback_sb_inodes+0x2d2/0x480 [] ? down_read_trylock+0x57/0x60 [] ? trylock_super+0x25/0x60 [] ? rcu_read_lock_sched_held+0x4f/0x90 [] __writeback_inodes_wb+0x8c/0xc0 [] wb_writeback+0x2b5/0x500 [] ? mark_held_locks+0x78/0xa0 [] ? __local_bh_enable_ip+0x68/0xc0 [] ? wb_do_writeback+0x62/0x310 [] wb_do_writeback+0xc1/0x310 [] ? set_worker_desc+0x79/0x90 [] wb_workfn+0x92/0x330 [] process_one_work+0x223/0x730 [] ? process_one_work+0x173/0x730 [] ? worker_thread+0x18f/0x430 [] worker_thread+0x11d/0x430 [] ? maybe_create_worker+0xf0/0xf0 [] ? maybe_create_worker+0xf0/0xf0 [] kthread+0xef/0x110 [] ? schedule_tail+0x1e/0xd0 [] ? __init_kthread_worker+0x70/0x70 [] ret_from_fork+0x3f/0x70 [] ? __init_kthread_worker+0x70/0x70 The issue is that we've got the software context pinned while calling blk_flush_plug_list(), which flushes callbacks that are allowed to sleep. btrfs and raid has such callbacks. Flip the checks around a bit, so we can enable preempt a bit earlier and flush plugs without having preempt disabled. This only affects blk-mq driven devices, and only those that register a single queue. Reported-by: Liu Bo Tested-by: Liu Bo Cc: stable@kernel.org Signed-off-by: Jens Axboe diff --git a/block/blk-mq.c b/block/blk-mq.c index 3ae09de..6d6f8fe 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1291,15 +1291,16 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_mq_bio_to_request(rq, bio); /* - * we do limited pluging. If bio can be merged, do merge. + * We do limited pluging. If the bio can be merged, do that. * Otherwise the existing request in the plug list will be * issued. So the plug list will have one request at most */ if (plug) { /* * The plug list might get flushed before this. If that - * happens, same_queue_rq is invalid and plug list is empty - **/ + * happens, same_queue_rq is invalid and plug list is + * empty + */ if (same_queue_rq && !list_empty(&plug->mq_list)) { old_rq = same_queue_rq; list_del_init(&old_rq->queuelist); @@ -1380,12 +1381,15 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) blk_mq_bio_to_request(rq, bio); if (!request_count) trace_block_plug(q); - else if (request_count >= BLK_MAX_REQUEST_COUNT) { + + blk_mq_put_ctx(data.ctx); + + if (request_count >= BLK_MAX_REQUEST_COUNT) { blk_flush_plug_list(plug, false); trace_block_plug(q); } + list_add_tail(&rq->queuelist, &plug->mq_list); - blk_mq_put_ctx(data.ctx); return cookie; } -- cgit v0.10.2 From 049af1060bb81532f2700762a8ba71eb3fa81f5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 21 Nov 2015 13:32:21 +0300 Subject: vfio: fix a warning message The first argument to the WARN() macro has to be a condition. I'm sort of disappointed that this code doesn't generate a compiler warning. I guess -Wformat-extra-args doesn't work in the kernel. Signed-off-by: Dan Carpenter Signed-off-by: Alex Williamson diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index de632da..9da0703 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -682,7 +682,7 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev) return 0; /* TODO Prevent device auto probing */ - WARN("Device %s added to live group %d!\n", dev_name(dev), + WARN(1, "Device %s added to live group %d!\n", dev_name(dev), iommu_group_id(group->iommu_group)); return 0; -- cgit v0.10.2 From 2e9fed42209b17116c6221e136ccbd3f252f5f86 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 27 Oct 2015 20:40:56 +0200 Subject: staging: iio: dummy: complete IIO events delivery to userspace Starting with commit fd2bb310ca (Staging: iio: Move evgen interrupt generation to irq_work) event processing is handled by calling both the top half and the threaded part properly simulating real hardware interrupts making use of threaded interrupts. This way the processing is split in 2 parts: * the IRQ handler that runs in IRQ context and only saves the event timestamp * the threaded handler that runs in process context, reads the events and pushes the in the userspace. If the IRQ handler returns IRQ_HANDLED the threaded handler is not even being called since the interrupt is considered to be processed. Because the iio dummy driver processes the events in the threaded handler the IRQ handler must return IRQ_WAKE_THREAD so that the threaded part would be awakened and called. Signed-off-by: Ioana Ciornei Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index bfbf1c5..6eb600f 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -159,7 +159,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private) struct iio_dummy_state *st = iio_priv(indio_dev); st->event_timestamp = iio_get_time_ns(); - return IRQ_HANDLED; + return IRQ_WAKE_THREAD; } /** -- cgit v0.10.2 From 45a6b8218df54087c3bb8dc731424d8789d31790 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Mon, 26 Oct 2015 20:18:23 -0700 Subject: iio: lidar: return -EINVAL on invalid signal Returning zero from the measurment function has the side effect of corrupting the triggered buffer readings, better to use -EINVAL than a zero measurement reading. The INVALID status happens even it isn't out of range sometimes roughly once every second or two. This can be from an invalid second signal return path. Hence there are spurious zero readings from the triggered buffer, and warning messages in the kernel log. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 961f9f99..e544fcf 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -130,10 +130,10 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg) if (ret < 0) break; - /* return 0 since laser is likely pointed out of range */ + /* return -EINVAL since laser is likely pointed out of range */ if (ret & LIDAR_REG_STATUS_INVALID) { *reg = 0; - ret = 0; + ret = -EINVAL; break; } @@ -197,7 +197,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) if (!ret) { iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, iio_get_time_ns()); - } else { + } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); } -- cgit v0.10.2 From 8386c27587594899e4b638010fa0187fe068b295 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 7 Nov 2015 20:21:28 -0800 Subject: iio: light: apds9960: correct ->last_busy count Add missing pm_runtime_mark_last_busy to apds9960_set_power_state function. Unless pm_runtime_mark_last_busy is called the pm_runtime_put_autosuspend may put the device into suspend before the delay time requested. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 7d269ef..f6a07dc 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -453,6 +453,7 @@ static int apds9960_set_power_state(struct apds9960_data *data, bool on) usleep_range(data->als_adc_int_us, APDS9960_MAX_INT_TIME_IN_US); } else { + pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); } -- cgit v0.10.2 From 231bfe53c57e89857753c940192acba933cba56c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 21 Nov 2015 13:33:00 +0300 Subject: iio: fix some warning messages WARN_ON() only takes a condition argument. I have changed these to WARN() instead. Signed-off-by: Dan Carpenter Cc: Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index d7e908a..0f6f63b 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -302,7 +302,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { - WARN_ON("Trying to set scanmask prior to registering buffer\n"); + WARN(1, "Trying to set scanmask prior to registering buffer\n"); goto err_invalid_mask; } bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 208358f..159ede6 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -655,7 +655,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, break; case IIO_SEPARATE: if (!chan->indexed) { - WARN_ON("Differential channels must be indexed\n"); + WARN(1, "Differential channels must be indexed\n"); ret = -EINVAL; goto error_free_full_postfix; } -- cgit v0.10.2 From d4c65fe4ed69a62a30a680789322ed677e3438af Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2015 23:04:13 +0100 Subject: iio: adc: spmi-vadc: add missing of_node_put for_each_available_child_of_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put. A simplified version of the semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // @@ expression root,e; local idexpression child; @@ for_each_available_child_of_node(root, child) { ... when != of_node_put(child) when != e = child ( return child; | + of_node_put(child); ? return ...; ) ... } // Signed-off-by: Julia Lawall Cc: Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index 0c4618b..c2babe5 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -839,8 +839,10 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node) for_each_available_child_of_node(node, child) { ret = vadc_get_dt_channel_data(vadc->dev, &prop, child); - if (ret) + if (ret) { + of_node_put(child); return ret; + } vadc->chan_props[index] = prop; -- cgit v0.10.2 From 79ae4fa5c0e1bc8000c39d3a78cb67828906a0e5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 15 Nov 2015 11:34:20 +0100 Subject: m68k/mm: motorola - Add missing initialization of max_pfn If max_pfn is not initialized, the various /proc/kpage* files are empty, and selftests/vm/mlock2-tests will fail. max_pfn is also used by the block layer to calculate DMA masks. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index b958916..8f37fdd 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -250,7 +250,7 @@ void __init paging_init(void) high_memory = phys_to_virt(max_addr); min_low_pfn = availmem >> PAGE_SHIFT; - max_low_pfn = max_addr >> PAGE_SHIFT; + max_pfn = max_low_pfn = max_addr >> PAGE_SHIFT; for (i = 0; i < m68k_num_memory; i++) { addr = m68k_memory[i].addr; -- cgit v0.10.2 From 4722b8feb0dc53a01a051f36846bef5a95d91a46 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 15 Nov 2015 11:36:29 +0100 Subject: m68k/mm: m54xx - Add missing initialization of max_pfn If max_pfn is not initialized, the various /proc/kpage* files are empty, and selftests/vm/mlock2-tests will fail. max_pfn is also used by the block layer to calculate DMA masks. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer Tested-by: Greg Ungerer diff --git a/arch/m68k/coldfire/m54xx.c b/arch/m68k/coldfire/m54xx.c index f7836c6..c32f767 100644 --- a/arch/m68k/coldfire/m54xx.c +++ b/arch/m68k/coldfire/m54xx.c @@ -98,7 +98,7 @@ static void __init mcf54xx_bootmem_alloc(void) memstart = PAGE_ALIGN(_ramstart); min_low_pfn = PFN_DOWN(_rambase); start_pfn = PFN_DOWN(memstart); - max_low_pfn = PFN_DOWN(_ramend); + max_pfn = max_low_pfn = PFN_DOWN(_ramend); high_memory = (void *)_ramend; m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6; -- cgit v0.10.2 From c73ec319339030a455e7641e7020fc14093a4153 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 15 Nov 2015 11:41:14 +0100 Subject: m68k/mm: sun3 - Add missing initialization of max_pfn and {min,max}_low_pfn If max_pfn is not initialized, the various /proc/kpage* files are empty, and selftests/vm/mlock2-tests will fail. max_pfn is also used by the block layer to calculate DMA masks. Switch from init_bootmem_node() to init_bootmem(), as there's only one memory node on Sun-3. This will initialize min_low_pfn and max_low_pfn, which was also not done before. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index a8b942b..2a5f43a 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -118,13 +118,13 @@ static void __init sun3_bootmem_alloc(unsigned long memory_start, memory_end = memory_end & PAGE_MASK; start_page = __pa(memory_start) >> PAGE_SHIFT; - num_pages = __pa(memory_end) >> PAGE_SHIFT; + max_pfn = num_pages = __pa(memory_end) >> PAGE_SHIFT; high_memory = (void *)memory_end; availmem = memory_start; m68k_setup_node(0); - availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages); + availmem += init_bootmem(start_page, num_pages); availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK; free_bootmem(__pa(availmem), memory_end - (availmem)); -- cgit v0.10.2 From b66f55cdba5559dedd295356bb5138c5ceadb694 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 15 Nov 2015 11:46:55 +0100 Subject: m68knommu: Add missing initialization of max_pfn and {min,max}_low_pfn If max_pfn is not initialized, the block layer may use wrong DMA masks. Replace open-coded shifts by PFN_DOWN(), and drop the "0 on coldfire" comment, as it is not even true on all Coldfires, let alone all m68knommu platforms. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer Tested-By: Greg Ungerer diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index 88c27d9..76b9113 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -238,11 +238,14 @@ void __init setup_arch(char **cmdline_p) * Give all the memory to the bootmap allocator, tell it to put the * boot mem_map at the start of memory. */ + min_low_pfn = PFN_DOWN(memory_start); + max_pfn = max_low_pfn = PFN_DOWN(memory_end); + bootmap_size = init_bootmem_node( NODE_DATA(0), - memory_start >> PAGE_SHIFT, /* map goes here */ - PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ - memory_end >> PAGE_SHIFT); + min_low_pfn, /* map goes here */ + PFN_DOWN(PAGE_OFFSET), + max_pfn); /* * Free the usable memory, we have to make sure we do not free * the bootmem bitmap so we then reserve it after freeing it :-) -- cgit v0.10.2 From 21d380e54c30b5b15aa4167e2458bfe4e4862427 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Nov 2015 10:53:26 +0100 Subject: m68k: Wire up mlock2 Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 0793a7f..f9d96bf 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -4,7 +4,7 @@ #include -#define NR_syscalls 375 +#define NR_syscalls 376 #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h index 5e6fae6..36cf129 100644 --- a/arch/m68k/include/uapi/asm/unistd.h +++ b/arch/m68k/include/uapi/asm/unistd.h @@ -380,5 +380,6 @@ #define __NR_sendmmsg 372 #define __NR_userfaultfd 373 #define __NR_membarrier 374 +#define __NR_mlock2 375 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */ diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 5dd0e80..282cd90 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -395,3 +395,4 @@ ENTRY(sys_call_table) .long sys_sendmmsg .long sys_userfaultfd .long sys_membarrier + .long sys_mlock2 /* 375 */ -- cgit v0.10.2 From c29d387b0bffb3ccce76e4fcdad9bfa7344ba338 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 21 Nov 2015 20:41:07 -0500 Subject: ARM: shmobile: r8a7793: proper constness with __initconst Both the pointer array and the pointed data have to be const when using __initconst to be correct. This also fixes LTO builds that otherwise fail with section mismatch errors. Fixes: ec60d95b4fac ("ARM: shmobile: Basic r8a7793 SoC support") Signed-off-by: Nicolas Pitre Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/setup-r8a7793.c b/arch/arm/mach-shmobile/setup-r8a7793.c index 1d2825c..5fce87f 100644 --- a/arch/arm/mach-shmobile/setup-r8a7793.c +++ b/arch/arm/mach-shmobile/setup-r8a7793.c @@ -19,7 +19,7 @@ #include "common.h" #include "rcar-gen2.h" -static const char *r8a7793_boards_compat_dt[] __initconst = { +static const char * const r8a7793_boards_compat_dt[] __initconst = { "renesas,r8a7793", NULL, }; -- cgit v0.10.2 From 6900317f5eff0a7070c5936e5383f589e0de7a09 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 20 Nov 2015 00:11:56 +0100 Subject: net, scm: fix PaX detected msg_controllen overflow in scm_detach_fds David and HacKurx reported a following/similar size overflow triggered in a grsecurity kernel, thanks to PaX's gcc size overflow plugin: (Already fixed in later grsecurity versions by Brad and PaX Team.) [ 1002.296137] PAX: size overflow detected in function scm_detach_fds net/core/scm.c:314 cicus.202_127 min, count: 4, decl: msg_controllen; num: 0; context: msghdr; [ 1002.296145] CPU: 0 PID: 3685 Comm: scm_rights_recv Not tainted 4.2.3-grsec+ #7 [ 1002.296149] Hardware name: Apple Inc. MacBookAir5,1/Mac-66F35F19FE2A0D05, [...] [ 1002.296153] ffffffff81c27366 0000000000000000 ffffffff81c27375 ffffc90007843aa8 [ 1002.296162] ffffffff818129ba 0000000000000000 ffffffff81c27366 ffffc90007843ad8 [ 1002.296169] ffffffff8121f838 fffffffffffffffc fffffffffffffffc ffffc90007843e60 [ 1002.296176] Call Trace: [ 1002.296190] [] dump_stack+0x45/0x57 [ 1002.296200] [] report_size_overflow+0x38/0x60 [ 1002.296209] [] scm_detach_fds+0x2ce/0x300 [ 1002.296220] [] unix_stream_read_generic+0x609/0x930 [ 1002.296228] [] unix_stream_recvmsg+0x4f/0x60 [ 1002.296236] [] ? unix_set_peek_off+0x50/0x50 [ 1002.296243] [] sock_recvmsg+0x47/0x60 [ 1002.296248] [] ___sys_recvmsg+0xe2/0x1e0 [ 1002.296257] [] __sys_recvmsg+0x46/0x80 [ 1002.296263] [] SyS_recvmsg+0x2c/0x40 [ 1002.296271] [] entry_SYSCALL_64_fastpath+0x12/0x85 Further investigation showed that this can happen when an *odd* number of fds are being passed over AF_UNIX sockets. In these cases CMSG_LEN(i * sizeof(int)) and CMSG_SPACE(i * sizeof(int)), where i is the number of successfully passed fds, differ by 4 bytes due to the extra CMSG_ALIGN() padding in CMSG_SPACE() to an 8 byte boundary on 64 bit. The padding is used to align subsequent cmsg headers in the control buffer. When the control buffer passed in from the receiver side *lacks* these 4 bytes (e.g. due to buggy/wrong API usage), then msg->msg_controllen will overflow in scm_detach_fds(): int cmlen = CMSG_LEN(i * sizeof(int)); <--- cmlen w/o tail-padding err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i * sizeof(int)); <--- cmlen w/ 4 byte extra tail-padding msg->msg_control += cmlen; msg->msg_controllen -= cmlen; <--- iff no tail-padding space here ... } ... wrap-around F.e. it will wrap to a length of 18446744073709551612 bytes in case the receiver passed in msg->msg_controllen of 20 bytes, and the sender properly transferred 1 fd to the receiver, so that its CMSG_LEN results in 20 bytes and CMSG_SPACE in 24 bytes. In case of MSG_CMSG_COMPAT (scm_detach_fds_compat()), I haven't seen an issue in my tests as alignment seems always on 4 byte boundary. Same should be in case of native 32 bit, where we end up with 4 byte boundaries as well. In practice, passing msg->msg_controllen of 20 to recvmsg() while receiving a single fd would mean that on successful return, msg->msg_controllen is being set by the kernel to 24 bytes instead, thus more than the input buffer advertised. It could f.e. become an issue if such application later on zeroes or copies the control buffer based on the returned msg->msg_controllen elsewhere. Maximum number of fds we can send is a hard upper limit SCM_MAX_FD (253). Going over the code, it seems like msg->msg_controllen is not being read after scm_detach_fds() in scm_recv() anymore by the kernel, good! Relevant recvmsg() handler are unix_dgram_recvmsg() (unix_seqpacket_recvmsg()) and unix_stream_recvmsg(). Both return back to their recvmsg() caller, and ___sys_recvmsg() places the updated length, that is, new msg_control - old msg_control pointer into msg->msg_controllen (hence the 24 bytes seen in the example). Long time ago, Wei Yongjun fixed something related in commit 1ac70e7ad24a ("[NET]: Fix function put_cmsg() which may cause usr application memory overflow"). RFC3542, section 20.2. says: The fields shown as "XX" are possible padding, between the cmsghdr structure and the data, and between the data and the next cmsghdr structure, if required by the implementation. While sending an application may or may not include padding at the end of last ancillary data in msg_controllen and implementations must accept both as valid. On receiving a portable application must provide space for padding at the end of the last ancillary data as implementations may copy out the padding at the end of the control message buffer and include it in the received msg_controllen. When recvmsg() is called if msg_controllen is too small for all the ancillary data items including any trailing padding after the last item an implementation may set MSG_CTRUNC. Since we didn't place MSG_CTRUNC for already quite a long time, just do the same as in 1ac70e7ad24a to avoid an overflow. Btw, even man-page author got this wrong :/ See db939c9b26e9 ("cmsg.3: Fix error in SCM_RIGHTS code sample"). Some people must have copied this (?), thus it got triggered in the wild (reported several times during boot by David and HacKurx). No Fixes tag this time as pre 2002 (that is, pre history tree). Reported-by: David Sterba Reported-by: HacKurx Cc: PaX Team Cc: Emese Revfy Cc: Brad Spengler Cc: Wei Yongjun Cc: Eric Dumazet Reviewed-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller diff --git a/net/core/scm.c b/net/core/scm.c index 3b6899b..8a1741b 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -305,6 +305,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG_SPACE(i*sizeof(int)); + if (msg->msg_controllen < cmlen) + cmlen = msg->msg_controllen; msg->msg_control += cmlen; msg->msg_controllen -= cmlen; } -- cgit v0.10.2 From cf869eb1118fac333b26585bce61f862d0e2b3eb Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 19 Nov 2015 17:56:12 -0800 Subject: net: tulip: update MAINTAINER status to Orphan I haven't had any PCI tulip HW for the past ~5 years. I have been reviewing tulip patches and can continue doing that. Signed-off-by: Grant Grundler Acked-by: Helge Deller Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index ea17512..ec07061 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10888,9 +10888,9 @@ S: Maintained F: drivers/media/tuners/tua9001* TULIP NETWORK DRIVERS -M: Grant Grundler L: netdev@vger.kernel.org -S: Maintained +L: linux-parisc@vger.kernel.org +S: Orphan F: drivers/net/ethernet/dec/tulip/ TUN/TAP driver -- cgit v0.10.2 From 0e615e9601a15efeeb8942cf7cd4dadba0c8c5a7 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 20 Nov 2015 13:54:19 +0100 Subject: net: ipmr: fix static mfc/dev leaks on table destruction When destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory, for example: unreferenced object 0xffff880034c144c0 (size 192): comm "mfc-broken", pid 4777, jiffies 4320349055 (age 46001.964s) hex dump (first 32 bytes): 98 53 f0 34 00 88 ff ff 98 53 f0 34 00 88 ff ff .S.4.....S.4.... ef 0a 0a 14 01 02 03 04 00 00 00 00 01 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] kmem_cache_alloc+0x190/0x300 [] ip_mroute_setsockopt+0x5cb/0x910 [] do_ip_setsockopt.isra.11+0x105/0xff0 [] ip_setsockopt+0x30/0xa0 [] raw_setsockopt+0x33/0x90 [] sock_common_setsockopt+0x14/0x20 [] SyS_setsockopt+0x71/0xc0 [] entry_SYSCALL_64_fastpath+0x16/0x7a [] 0xffffffffffffffff Make sure that everything is cleaned on netns destruction. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 92dd4b7..292123b 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, int cmd); -static void mroute_clean_tables(struct mr_table *mrt); +static void mroute_clean_tables(struct mr_table *mrt, bool all); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES @@ -350,7 +350,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) static void ipmr_free_table(struct mr_table *mrt) { del_timer_sync(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, true); kfree(mrt); } @@ -1208,7 +1208,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, * Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct mr_table *mrt) +static void mroute_clean_tables(struct mr_table *mrt, bool all) { int i; LIST_HEAD(list); @@ -1217,8 +1217,9 @@ static void mroute_clean_tables(struct mr_table *mrt) /* Shut down all active vif entries */ for (i = 0; i < mrt->maxvif; i++) { - if (!(mrt->vif_table[i].flags & VIFF_STATIC)) - vif_delete(mrt, i, 0, &list); + if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) + continue; + vif_delete(mrt, i, 0, &list); } unregister_netdevice_many(&list); @@ -1226,7 +1227,7 @@ static void mroute_clean_tables(struct mr_table *mrt) for (i = 0; i < MFC_LINES; i++) { list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { - if (c->mfc_flags & MFC_STATIC) + if (!all && (c->mfc_flags & MFC_STATIC)) continue; list_del_rcu(&c->list); mroute_netlink_event(mrt, c, RTM_DELROUTE); @@ -1261,7 +1262,7 @@ static void mrtsock_destruct(struct sock *sk) NETCONFA_IFINDEX_ALL, net->ipv4.devconf_all); RCU_INIT_POINTER(mrt->mroute_sk, NULL); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, false); } } rtnl_unlock(); -- cgit v0.10.2 From 4c6980462f32b4f282c5d8e5f7ea8070e2937725 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 20 Nov 2015 13:54:20 +0100 Subject: net: ip6mr: fix static mfc/dev leaks on table destruction Similar to ipv4, when destroying an mrt table the static mfc entries and the static devices are kept, which leads to devices that can never be destroyed (because of refcnt taken) and leaked memory. Make sure that everything is cleaned up on netns destruction. Fixes: 8229efdaef1e ("netns: ip6mr: enable namespace support in ipv6 multicast forwarding code") CC: Benjamin Thery Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index ad19136..7a4a1b8 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -118,7 +118,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc, int cmd); static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb); -static void mroute_clean_tables(struct mr6_table *mrt); +static void mroute_clean_tables(struct mr6_table *mrt, bool all); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES @@ -334,7 +334,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) static void ip6mr_free_table(struct mr6_table *mrt) { del_timer_sync(&mrt->ipmr_expire_timer); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, true); kfree(mrt); } @@ -1542,7 +1542,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, * Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct mr6_table *mrt) +static void mroute_clean_tables(struct mr6_table *mrt, bool all) { int i; LIST_HEAD(list); @@ -1552,8 +1552,9 @@ static void mroute_clean_tables(struct mr6_table *mrt) * Shut down all active vif entries */ for (i = 0; i < mrt->maxvif; i++) { - if (!(mrt->vif6_table[i].flags & VIFF_STATIC)) - mif6_delete(mrt, i, &list); + if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC)) + continue; + mif6_delete(mrt, i, &list); } unregister_netdevice_many(&list); @@ -1562,7 +1563,7 @@ static void mroute_clean_tables(struct mr6_table *mrt) */ for (i = 0; i < MFC6_LINES; i++) { list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) { - if (c->mfc_flags & MFC_STATIC) + if (!all && (c->mfc_flags & MFC_STATIC)) continue; write_lock_bh(&mrt_lock); list_del(&c->list); @@ -1625,7 +1626,7 @@ int ip6mr_sk_done(struct sock *sk) net->ipv6.devconf_all); write_unlock_bh(&mrt_lock); - mroute_clean_tables(mrt); + mroute_clean_tables(mrt, false); err = 0; break; } -- cgit v0.10.2 From 3fa2f9496554bc23eb62f958c920e9fcee7ba232 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Sun, 18 Oct 2015 11:18:48 +0530 Subject: ARM: dts: vfxxx: Fix erroneous property in esdhc0 node Something seems to have gone wrong during the merging of the device tree changes with the following patch "ARM: dts: add property for maximum ADC clock frequencies" The property "fsl,adck-max-frequency" instead of being applied for the ADC1 node got applied to the esdhc0 node. This patch fixes it. Signed-off-by: Sanchayan Maity Fixes: def0641e2f61 ("ARM: dts: add property for maximum ADC clock frequencies") Cc: Signed-off-by: Shawn Guo diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index 6736bae..a64bfe1 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -461,6 +461,8 @@ clock-names = "adc"; #io-channel-cells = <1>; status = "disabled"; + fsl,adck-max-frequency = <30000000>, <40000000>, + <20000000>; }; esdhc0: esdhc@400b1000 { @@ -472,8 +474,6 @@ <&clks VF610_CLK_ESDHC0>; clock-names = "ipg", "ahb", "per"; status = "disabled"; - fsl,adck-max-frequency = <30000000>, <40000000>, - <20000000>; }; esdhc1: esdhc@400b2000 { -- cgit v0.10.2 From 4699ccbf8cf2f962031b88de7851f610030e5c17 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 20 Oct 2015 18:44:19 +0800 Subject: ARM: imx: add platform irq type setting in gpc GPC irq domain is a child domain of GIC, now all of platform irqs are inside GPC domain, during the module populate, all devices irq should have correct type setting in GIC, however, there is no .irq_set_type callback setting in GPC, so the irq_set_type will be skipped and cause all irqs' type in /proc/interrupt are "edge" which mismatch with irq type setting in dtb file. Since GPC has no irq type setting, so just tell kernel to use irq_chip_set_type_parent. Signed-off-by: Anson Huang Cc: # 4.1+ Reviewed-by: Lucas Stach Reviewed-by: Marc Zyngier Signed-off-by: Shawn Guo diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 8e7976a..cfc696b 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -177,6 +177,7 @@ static struct irq_chip imx_gpc_chip = { .irq_unmask = imx_gpc_irq_unmask, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_wake = imx_gpc_irq_set_wake, + .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 de55acd100993c70bb7c5ca9473b59cdc4debb20 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Mon, 2 Nov 2015 02:20:20 +0000 Subject: watchdog: omap_wdt: fix null pointer dereference Fix issue from two patches overlapping causing a kernel oops [ 3569.297449] Unable to handle kernel NULL pointer dereference at virtual address 00000088 [ 3569.306272] pgd = dc894000 [ 3569.309287] [00000088] *pgd=00000000 [ 3569.313104] Internal error: Oops: 5 [#1] SMP ARM [ 3569.317986] Modules linked in: ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_filter ebtable_nat ebtable_broute bridge stp llc ebtables ip6table_security ip6table_raw ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_filter ip6_tables iptable_security iptable_raw iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle musb_dsps cppi41 musb_hdrc phy_am335x udc_core phy_generic phy_am335x_control omap_sham omap_aes omap_rng omap_hwspinlock omap_mailbox hwspinlock_core musb_am335x omap_wdt at24 8250_omap leds_gpio cpufreq_dt smsc davinci_mdio mmc_block ti_cpsw cpsw_common ptp pps_core cpsw_ale davinci_cpdma omap_hsmmc omap_dma mmc_core i2c_dev [ 3569.386293] CPU: 0 PID: 1429 Comm: wdctl Not tainted 4.3.0-0.rc7.git0.1.fc24.armv7hl #1 [ 3569.394740] Hardware name: Generic AM33XX (Flattened Device Tree) [ 3569.401179] task: dbd11a00 ti: dbaac000 task.ti: dbaac000 [ 3569.406917] PC is at omap_wdt_get_timeleft+0xc/0x20 [omap_wdt] [ 3569.413106] LR is at watchdog_ioctl+0x3cc/0x42c [ 3569.417902] pc : [] lr : [] psr: 600f0013 [ 3569.417902] sp : dbaadf18 ip : 00000003 fp : 7f5d3bbe [ 3569.430014] r10: 00000000 r9 : 00000003 r8 : bef21ab8 [ 3569.435535] r7 : dbbc0f7c r6 : dbbc0f18 r5 : bef21ab8 r4 : 00000000 [ 3569.442427] r3 : 00000000 r2 : 00000000 r1 : 8004570a r0 : dbbc0f18 [ 3569.449323] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 3569.456858] Control: 10c5387d Table: 9c894019 DAC: 00000051 [ 3569.462927] Process wdctl (pid: 1429, stack limit = 0xdbaac220) [ 3569.469179] Stack: (0xdbaadf18 to 0xdbaae000) [ 3569.473790] df00: bef21ab8 dbf60e38 [ 3569.482441] df20: dc91b840 8004570a bef21ab8 c03988a4 dbaadf48 dc854000 00000000 dd313850 [ 3569.491092] df40: ddf033b8 0000570a dc91b80b dbaadf3c dbf60e38 00000020 c0df9250 c0df6c48 [ 3569.499741] df60: dc91b840 8004570a 00000000 dc91b840 dc91b840 8004570a bef21ab8 00000003 [ 3569.508389] df80: 00000000 c03989d4 bef21b74 7f5d3bad 00000003 00000036 c020fcc4 dbaac000 [ 3569.517037] dfa0: 00000000 c020fb00 bef21b74 7f5d3bad 00000003 8004570a bef21ab8 00000001 [ 3569.525685] dfc0: bef21b74 7f5d3bad 00000003 00000036 00000001 00000000 7f5e4eb0 7f5d3bbe [ 3569.534334] dfe0: 7f5e4f10 bef21a3c 7f5d0a54 b6e97e0c a00f0010 00000003 00000000 00000000 [ 3569.543038] [] (omap_wdt_get_timeleft [omap_wdt]) from [] (watchdog_ioctl+0x3cc/0x42c) [ 3569.553266] [] (watchdog_ioctl) from [] (do_vfs_ioctl+0x5bc/0x698) [ 3569.561648] [] (do_vfs_ioctl) from [] (SyS_ioctl+0x54/0x7c) [ 3569.569400] [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x3c) [ 3569.577413] Code: e12fff1e e52de004 e8bd4000 e5903060 (e5933088) [ 3569.584089] ---[ end trace cec3039bd3ae610a ]--- Cc: # v4.2+ Signed-off-by: Peter Robinson Acked-by: Lars Poeschel Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index d96bee0..6f17c93 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -205,7 +205,7 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog, static unsigned int omap_wdt_get_timeleft(struct watchdog_device *wdog) { - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); void __iomem *base = wdev->base; u32 value; -- cgit v0.10.2 From b647d4297234e7f5456c16635ca0cdd82b7055db Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sat, 17 Oct 2015 21:28:16 +0300 Subject: watchdog: pnx4008: fix warnings caused by enabling unprepared clock If common clock framework is configured, the driver generates a warning, which is fixed by this change: WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:727 clk_core_enable+0x2c/0xa4() Modules linked in: CPU: 0 PID: 1 Comm: swapper Tainted: G W 4.3.0-rc2+ #171 Hardware name: LPC32XX SoC (Flattened Device Tree) Backtrace: [<>] (dump_backtrace) from [<>] (show_stack+0x18/0x1c) [<>] (show_stack) from [<>] (dump_stack+0x20/0x28) [<>] (dump_stack) from [<>] (warn_slowpath_common+0x90/0xb8) [<>] (warn_slowpath_common) from [<>] (warn_slowpath_null+0x24/0x2c) [<>] (warn_slowpath_null) from [<>] (clk_core_enable+0x2c/0xa4) [<>] (clk_core_enable) from [<>] (clk_enable+0x24/0x38) [<>] (clk_enable) from [<>] (pnx4008_wdt_probe+0x78/0x11c) [<>] (pnx4008_wdt_probe) from [<>] (platform_drv_probe+0x50/0xa0) [<>] (platform_drv_probe) from [<>] (driver_probe_device+0x18c/0x408) [<>] (driver_probe_device) from [<>] (__driver_attach+0x70/0x94) [<>] (__driver_attach) from [<>] (bus_for_each_dev+0x74/0x98) [<>] (bus_for_each_dev) from [<>] (driver_attach+0x20/0x28) [<>] (driver_attach) from [<>] (bus_add_driver+0x11c/0x248) [<>] (bus_add_driver) from [<>] (driver_register+0xa4/0xe8) [<>] (driver_register) from [<>] (__platform_driver_register+0x50/0x64) [<>] (__platform_driver_register) from [<>] (platform_wdt_driver_init+0x18/0x20) [<>] (platform_wdt_driver_init) from [<>] (do_one_initcall+0x11c/0x1dc) [<>] (do_one_initcall) from [<>] (kernel_init_freeable+0x10c/0x1d4) [<>] (kernel_init_freeable) from [<>] (kernel_init+0x10/0xec) [<>] (kernel_init) from [<>] (ret_from_fork+0x14/0x24) Signed-off-by: Vladimir Zapolskiy Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 4224b3e..35319a4 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -161,7 +161,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt_clk)) return PTR_ERR(wdt_clk); - ret = clk_enable(wdt_clk); + ret = clk_prepare_enable(wdt_clk); if (ret) return ret; @@ -184,7 +184,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) return 0; disable_clk: - clk_disable(wdt_clk); + clk_disable_unprepare(wdt_clk); return ret; } @@ -192,7 +192,7 @@ static int pnx4008_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&pnx4008_wdd); - clk_disable(wdt_clk); + clk_disable_unprepare(wdt_clk); return 0; } -- cgit v0.10.2 From 4c30737ce16612b0f3b840a7c9928385cbb67555 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 28 Oct 2015 02:55:35 +0200 Subject: watchdog: pnx4008: make global wdt_clk static Silences sparse warning: drivers/watchdog/pnx4008_wdt.c:83:25: warning: symbol 'wdt_clk' was not declared. Should it be static? Signed-off-by: Vladimir Zapolskiy Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 35319a4..313cd1c 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -80,7 +80,7 @@ static unsigned int heartbeat = DEFAULT_HEARTBEAT; static DEFINE_SPINLOCK(io_lock); static void __iomem *wdt_base; -struct clk *wdt_clk; +static struct clk *wdt_clk; static int pnx4008_wdt_start(struct watchdog_device *wdd) { -- cgit v0.10.2 From 62ed853c7de7a77bdf01421fb6836269c9b1aa1f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Nov 2015 12:56:31 +0300 Subject: watchdog: w83977f_wdt: underflow in wdt_set_timeout() "t" is controlled by the user. If "t" is a very large integer then it could lead to a negative "tmrval". We cap the upper bound of "tmrval" but, in the current code, we allow negatives. This is a bug and it causes a static checker warning. Let's make "tmrval" unsigned to avoid this problem. Signed-off-by: Dan Carpenter Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c index 91bf55a..20e2bba 100644 --- a/drivers/watchdog/w83977f_wdt.c +++ b/drivers/watchdog/w83977f_wdt.c @@ -224,7 +224,7 @@ static int wdt_keepalive(void) static int wdt_set_timeout(int t) { - int tmrval; + unsigned int tmrval; /* * Convert seconds to watchdog counter time units, rounding up. -- cgit v0.10.2 From 0879eee13f9cf79793ce88fb41bf0dd2a51093c0 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Mon, 9 Nov 2015 16:11:38 -0800 Subject: watchdog: tegra: Stop watchdog first if restarting If we need to restart the watchdog due to someone changing the timeout interval, stop the watchdog before restarting it. Otherwise, the new timeout doesn't seem to take. Signed-off-by: Andrew Chew Reviewed-by: Thierry Reding Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 7f97cdd..9ec5760 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -140,8 +140,10 @@ static int tegra_wdt_set_timeout(struct watchdog_device *wdd, { wdd->timeout = timeout; - if (watchdog_active(wdd)) + if (watchdog_active(wdd)) { + tegra_wdt_stop(wdd); return tegra_wdt_start(wdd); + } return 0; } -- cgit v0.10.2 From 646251a59c73253a7a2c7b1d6adbedd2292390a0 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Tue, 17 Nov 2015 17:53:19 +0800 Subject: watchdog: Add support for Freescale Layerscape platforms Modify watchdog/Kconfig file to support Layerscape platforms. Signed-off-by: Shaohui Xie Signed-off-by: Hou Zhiqiang Acked-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 7a8a6c6..1c427be 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -446,7 +446,7 @@ config MAX63XX_WATCHDOG config IMX2_WDT tristate "IMX2+ Watchdog" - depends on ARCH_MXC + depends on ARCH_MXC || ARCH_LAYERSCAPE select REGMAP_MMIO select WATCHDOG_CORE help -- cgit v0.10.2 From 5da2bf1ac8fbe701a138efb340b9f2ef26c10ed7 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 18 Nov 2015 10:45:01 +0800 Subject: watchdog: mtk_wdt: Use MODE_KEY when stopping the watchdog WDT_MODE value need to be or-ed with MODE_KEY when setting watchdog mode. Add it to mtk_wdt_stop function, so that the watchdog can be stopped (e.g. during suspend). Signed-off-by: Nicolas Boichat Acked-by: Matthias Brugger Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 6ad9df9..b751f43 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -123,6 +123,7 @@ static int mtk_wdt_stop(struct watchdog_device *wdt_dev) reg = readl(wdt_base + WDT_MODE); reg &= ~WDT_MODE_EN; + reg |= WDT_MODE_KEY; iowrite32(reg, wdt_base + WDT_MODE); return 0; -- cgit v0.10.2 From ddaaf4e291dd63db0667991e4a335fcf3a7df13e Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Thu, 12 Nov 2015 11:00:03 +0100 Subject: perf/core: Fix RCU problem with cgroup context switching code The RCU checker detected RCU violation in the cgroup switching routines perf_cgroup_sched_in() and perf_cgroup_sched_out(). We were dereferencing cgroup from task without holding the RCU lock. Fix this by holding the RCU read lock. We move the locking from perf_cgroup_switch() to avoid double locking. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: edumazet@google.com Link: http://lkml.kernel.org/r/1447322404-10920-2-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 36babfd..60e71ca 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -489,7 +489,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode) * we reschedule only in the presence of cgroup * constrained events. */ - rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); @@ -531,8 +530,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode) } } - rcu_read_unlock(); - local_irq_restore(flags); } @@ -542,6 +539,7 @@ static inline void perf_cgroup_sched_out(struct task_struct *task, struct perf_cgroup *cgrp1; struct perf_cgroup *cgrp2 = NULL; + rcu_read_lock(); /* * we come here when we know perf_cgroup_events > 0 */ @@ -561,6 +559,8 @@ static inline void perf_cgroup_sched_out(struct task_struct *task, */ if (cgrp1 != cgrp2) perf_cgroup_switch(task, PERF_CGROUP_SWOUT); + + rcu_read_unlock(); } static inline void perf_cgroup_sched_in(struct task_struct *prev, @@ -569,6 +569,7 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev, struct perf_cgroup *cgrp1; struct perf_cgroup *cgrp2 = NULL; + rcu_read_lock(); /* * we come here when we know perf_cgroup_events > 0 */ @@ -584,6 +585,8 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev, */ if (cgrp1 != cgrp2) perf_cgroup_switch(task, PERF_CGROUP_SWIN); + + rcu_read_unlock(); } static inline int perf_cgroup_connect(int fd, struct perf_event *event, @@ -9452,7 +9455,9 @@ static void perf_cgroup_css_free(struct cgroup_subsys_state *css) static int __perf_cgroup_move(void *info) { struct task_struct *task = info; + rcu_read_lock(); perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN); + rcu_read_unlock(); return 0; } -- cgit v0.10.2 From 614e4c4ebc75517295bccd29b20ddbc5b52af6fc Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Thu, 12 Nov 2015 11:00:04 +0100 Subject: perf/core: Robustify the perf_cgroup_from_task() RCU checks This patch reinforces the lockdep checks performed by perf_cgroup_from_tsk() by passing the perf_event_context whenever possible. It is okay to not hold the RCU read lock when we know we hold the ctx->lock. This patch makes sure this property holds. In some functions, such as perf_cgroup_sched_in(), we do not pass the context because we are sure we are holding the RCU read lock. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: edumazet@google.com Link: http://lkml.kernel.org/r/1447322404-10920-3-git-send-email-eranian@google.com 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 377e8f8..a316ca9 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c +++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c @@ -298,7 +298,7 @@ static bool __match_event(struct perf_event *a, struct perf_event *b) static inline struct perf_cgroup *event_to_cgroup(struct perf_event *event) { if (event->attach_state & PERF_ATTACH_TASK) - return perf_cgroup_from_task(event->hw.target); + return perf_cgroup_from_task(event->hw.target, event->ctx); return event->cgrp; } diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index d841d33..f9828a4 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -697,9 +697,11 @@ struct perf_cgroup { * if there is no cgroup event for the current CPU context. */ static inline struct perf_cgroup * -perf_cgroup_from_task(struct task_struct *task) +perf_cgroup_from_task(struct task_struct *task, struct perf_event_context *ctx) { - return container_of(task_css(task, perf_event_cgrp_id), + return container_of(task_css_check(task, perf_event_cgrp_id, + ctx ? lockdep_is_held(&ctx->lock) + : true), struct perf_cgroup, css); } #endif /* CONFIG_CGROUP_PERF */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 60e71ca..1ac857a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -435,7 +435,7 @@ static inline void update_cgrp_time_from_event(struct perf_event *event) if (!is_cgroup_event(event)) return; - cgrp = perf_cgroup_from_task(current); + cgrp = perf_cgroup_from_task(current, event->ctx); /* * Do not update time when cgroup is not active */ @@ -458,7 +458,7 @@ perf_cgroup_set_timestamp(struct task_struct *task, if (!task || !ctx->nr_cgroups) return; - cgrp = perf_cgroup_from_task(task); + cgrp = perf_cgroup_from_task(task, ctx); info = this_cpu_ptr(cgrp->info); info->timestamp = ctx->timestamp; } @@ -521,8 +521,10 @@ static void perf_cgroup_switch(struct task_struct *task, int mode) * set cgrp before ctxsw in to allow * event_filter_match() to not have to pass * task around + * we pass the cpuctx->ctx to perf_cgroup_from_task() + * because cgorup events are only per-cpu */ - cpuctx->cgrp = perf_cgroup_from_task(task); + cpuctx->cgrp = perf_cgroup_from_task(task, &cpuctx->ctx); cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); } perf_pmu_enable(cpuctx->ctx.pmu); @@ -542,15 +544,17 @@ static inline void perf_cgroup_sched_out(struct task_struct *task, rcu_read_lock(); /* * we come here when we know perf_cgroup_events > 0 + * we do not need to pass the ctx here because we know + * we are holding the rcu lock */ - cgrp1 = perf_cgroup_from_task(task); + cgrp1 = perf_cgroup_from_task(task, NULL); /* * next is NULL when called from perf_event_enable_on_exec() * that will systematically cause a cgroup_switch() */ if (next) - cgrp2 = perf_cgroup_from_task(next); + cgrp2 = perf_cgroup_from_task(next, NULL); /* * only schedule out current cgroup events if we know @@ -572,11 +576,13 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev, rcu_read_lock(); /* * we come here when we know perf_cgroup_events > 0 + * we do not need to pass the ctx here because we know + * we are holding the rcu lock */ - cgrp1 = perf_cgroup_from_task(task); + cgrp1 = perf_cgroup_from_task(task, NULL); /* prev can never be NULL */ - cgrp2 = perf_cgroup_from_task(prev); + cgrp2 = perf_cgroup_from_task(prev, NULL); /* * only need to schedule in cgroup events if we are changing -- cgit v0.10.2 From 89b411081d70fe3772efa4665279293269c1150d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Nov 2015 17:19:58 +0100 Subject: sched/rt: Hide the push_irq_work_func() declaration The push_irq_work_func() function is conditionally defined only when both CONFIG_SMP and HAVE_RT_PUSH_IPI are defined, but the forward declaration remains visibile without HAVE_RT_PUSH_IPI, causing a gcc warning in ARM64 allnoconfig: kernel/sched/rt.c:68:13: warning: 'push_irq_work_func' declared 'static' but never defined [-Wunused-function] This changes the code to use the same condition for both the declaration and the function definition, which gets rid of the warning. As Peter Zijlstra, we can possibly get rid of the whole HAVE_RT_PUSH_IPI thing after: 8053871d0f7f ("smp: Fix smp_call_function_single_async() locking") Until that is done, this patch can be used to avoid the warning. Signed-off-by: Arnd Bergmann Signed-off-by: Peter Zijlstra (Intel) Acked-by: Steven Rostedt Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: b6366f048e0c ("sched/rt: Use IPI to trigger RT task push migration instead of pulling") Link: http://lkml.kernel.org/r/3828565.oKfGk7yNIT@wuerfel Signed-off-by: Ingo Molnar diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index e3cc163..8ec86ab 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -64,7 +64,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b) raw_spin_unlock(&rt_b->rt_runtime_lock); } -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI) static void push_irq_work_func(struct irq_work *work); #endif -- cgit v0.10.2 From 7cecd9ab80f43972c056dc068338f7bcc407b71c Mon Sep 17 00:00:00 2001 From: Mirza Krak Date: Tue, 10 Nov 2015 14:59:34 +0100 Subject: can: sja1000: clear interrupts on start According to SJA1000 data sheet error-warning (EI) interrupt is not cleared by setting the controller in to reset-mode. Then if we have the following case: - system is suspended (echo mem > /sys/power/state) and SJA1000 is left in operating state - A bus error condition occurs which activates EI interrupt, system is still suspended which means EI interrupt will be not be handled nor cleared. If the above two events occur, on resume there is no way to return the SJA1000 to operating state, except to cycle power to it. By simply reading the IR register on start we will clear any previous conditions that could be present. Signed-off-by: Mirza Krak Reported-by: Christian Magnusson Cc: linux-stable Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 7b92e91..f10834b 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -218,6 +218,9 @@ static void sja1000_start(struct net_device *dev) priv->write_reg(priv, SJA1000_RXERR, 0x0); priv->read_reg(priv, SJA1000_ECC); + /* clear interrupt flags */ + priv->read_reg(priv, SJA1000_IR); + /* leave reset mode */ set_normal_mode(dev); } -- cgit v0.10.2 From ffd461f80d536336811d573f197f3e6d9872d054 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 21 Nov 2015 18:41:20 +0100 Subject: can: fix assignment of error location in CAN error messages As Dan Carpenter reported in http://marc.info/?l=linux-can&m=144793696016187 the assignment of the error location in CAN error messages had some bit wise overlaps. Indeed the value to be assigned in data[3] is no bitfield but defines a single value which points to a location inside the CAN frame on the wire. This patch fixes the assignments for the error locations in error messages. Reported-by: Dan Carpenter Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 5d214d1..7c9892ab 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -975,8 +975,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); @@ -988,8 +987,7 @@ static int c_can_handle_bus_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; default: break; diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 70a8cbb..1e37313 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -578,7 +578,7 @@ static int cc770_err(struct net_device *dev, u8 status) cf->data[2] |= CAN_ERR_PROT_BIT0; break; case STAT_LEC_CRC: - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; } } diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 868fe94..41c0fc9 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -535,13 +535,13 @@ static void do_bus_err(struct net_device *dev, if (reg_esr & FLEXCAN_ESR_ACK_ERR) { netdev_dbg(dev, "ACK_ERR irq\n"); cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; tx_errors = 1; } if (reg_esr & FLEXCAN_ESR_CRC_ERR) { netdev_dbg(dev, "CRC_ERR irq\n"); cf->data[2] |= CAN_ERR_PROT_BIT; - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; rx_errors = 1; } if (reg_esr & FLEXCAN_ESR_FRM_ERR) { diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index ef65517..9dd3ca7 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -500,8 +500,7 @@ static int m_can_handle_lec_err(struct net_device *dev, break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); @@ -513,8 +512,7 @@ static int m_can_handle_lec_err(struct net_device *dev, break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; default: break; diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index e187ca7..c131788 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -559,8 +559,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) stats->rx_errors++; break; case PCH_CRC_ERR: - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; priv->can.can_stats.bus_error++; stats->rx_errors++; break; diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 7bd5419..9161f04 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -251,7 +251,7 @@ static void rcar_can_error(struct net_device *ndev) tx_errors++; writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr); if (skb) - cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL; } if (ecsr & RCAR_CAN_ECSR_BE0F) { netdev_dbg(priv->ndev, "Bit Error (dominant)\n"); @@ -272,7 +272,7 @@ static void rcar_can_error(struct net_device *ndev) rx_errors++; writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr); if (skb) - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } if (ecsr & RCAR_CAN_ECSR_AEF) { netdev_dbg(priv->ndev, "ACK Error\n"); @@ -280,7 +280,7 @@ static void rcar_can_error(struct net_device *ndev) writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr); if (skb) { cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } if (ecsr & RCAR_CAN_ECSR_FEF) { diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index cf345cb..6eab4fe 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -737,13 +737,11 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, } if (err_status & HECC_CANES_CRCE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE); - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } if (err_status & HECC_CANES_ACKE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); - cf->data[3] |= CAN_ERR_PROT_LOC_ACK | - CAN_ERR_PROT_LOC_ACK_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 8b17a90..022bfa1 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -944,10 +944,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; if (es->leaf.error_factor & M16C_EF_ACKE) - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); + cf->data[3] = CAN_ERR_PROT_LOC_ACK; if (es->leaf.error_factor & M16C_EF_CRCE) - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; if (es->leaf.error_factor & M16C_EF_FORME) cf->data[2] |= CAN_ERR_PROT_FORM; if (es->leaf.error_factor & M16C_EF_STFE) diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index de95b1c..017ae50 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -402,8 +402,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, break; case USB_8DEV_STATUSMSG_CRC: cf->data[2] |= CAN_ERR_PROT_UNSPEC; - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; rx_errors = 1; break; case USB_8DEV_STATUSMSG_BIT0: diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index fc55e8e..4c57ddf 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -618,7 +618,7 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) stats->tx_errors++; if (skb) { cf->can_id |= CAN_ERR_ACK; - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + cf->data[3] = CAN_ERR_PROT_LOC_ACK; } } @@ -654,8 +654,7 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) stats->rx_errors++; if (skb) { cf->can_id |= CAN_ERR_PROT; - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL; + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } } priv->can.can_stats.bus_error++; -- cgit v0.10.2 From a2ec19f888f1fb06e2424486423a16f86ad1fcc4 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 21 Nov 2015 18:41:21 +0100 Subject: can: remove obsolete assignment for CAN protocol error type The assignment 'cf->data[2] |= CAN_ERR_PROT_UNSPEC' used at CAN error message creation time is obsolete as CAN_ERR_PROT_UNSPEC is zero and cf->data[2] is initialized with zero in alloc_can_err_skb() anyway. So we could either assign 'cf->data[2] = CAN_ERR_PROT_UNSPEC' correctly or we can remove the obsolete OR operation entirely. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 57dadd5..1deb8ff 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -501,8 +501,6 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) cf->data[2] |= CAN_ERR_PROT_FORM; else if (status & SER) cf->data[2] |= CAN_ERR_PROT_STUFF; - else - cf->data[2] |= CAN_ERR_PROT_UNSPEC; } priv->can.state = state; diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 7c9892ab..f91b094 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -962,7 +962,6 @@ static int c_can_handle_bus_err(struct net_device *dev, * type of the last error to occur on the CAN bus */ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; switch (lec_type) { case LEC_STUFF_ERROR: diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index c1e8536..5d04f54 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1096,7 +1096,6 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & ECC_SEG; break; } diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 9dd3ca7..39cf911 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -487,7 +487,6 @@ static int m_can_handle_lec_err(struct net_device *dev, * type of the last error to occur on the CAN bus */ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; switch (lec_type) { case LEC_STUFF_ERROR: diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 9161f04..bc46be3 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -241,10 +241,9 @@ static void rcar_can_error(struct net_device *ndev) u8 ecsr; netdev_dbg(priv->ndev, "Bus error interrupt:\n"); - if (skb) { + if (skb) cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_UNSPEC; - } + ecsr = readb(&priv->regs->ecsr); if (ecsr & RCAR_CAN_ECSR_ADEF) { netdev_dbg(priv->ndev, "ACK Delimiter Error\n"); diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f10834b..8dda3b7 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -449,7 +449,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & ECC_SEG; break; } diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index d9a42c6..68ef0a4 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -575,7 +575,6 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE) >> 16; break; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 6eab4fe..680d1ff 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -722,7 +722,6 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, if (err_status & HECC_BUS_ERROR) { ++priv->can.can_stats.bus_error; cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; if (err_status & HECC_CANES_FE) { hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE); cf->data[2] |= CAN_ERR_PROT_FORM; diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 2d39038..fc5b756 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -377,7 +377,6 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & SJA1000_ECC_SEG; break; } diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 0e5a449..113e64f 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -282,7 +282,6 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & SJA1000_ECC_SEG; break; } diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 017ae50..a731720 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -401,7 +401,6 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, tx_errors = 1; break; case USB_8DEV_STATUSMSG_CRC: - cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; rx_errors = 1; break; diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 4c57ddf..51670b3 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -608,10 +608,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) /* Check for error interrupt */ if (isr & XCAN_IXR_ERROR_MASK) { - if (skb) { + if (skb) cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_UNSPEC; - } /* Check for Ack error interrupt */ if (err_status & XCAN_ESR_ACKER_MASK) { -- cgit v0.10.2 From daecbd267daad36c1cd90254f502610f82efcb30 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 16 Nov 2015 11:07:44 +0100 Subject: perf: Update email address in MAINTAINERS While still valid, I'm trying to phase out this email address. Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar diff --git a/MAINTAINERS b/MAINTAINERS index 050d0e7..a45fe35 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8284,7 +8284,7 @@ F: include/linux/delayacct.h F: kernel/delayacct.c PERFORMANCE EVENTS SUBSYSTEM -M: Peter Zijlstra +M: Peter Zijlstra M: Ingo Molnar M: Arnaldo Carvalho de Melo L: linux-kernel@vger.kernel.org -- cgit v0.10.2 From b28ae9560b693bcd2e9f4d6d9c415d5380b7c3c5 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 20 Oct 2015 11:46:33 -0700 Subject: perf/x86: Fix LBR call stack save/restore This fixes a bug I added in the following commit: 90405aa02247 ("perf/x86/intel/lbr: Limit LBR accesses to TOS in callstack mode") The bug could lead to lost LBR call stacks. When restoring the LBR state we need to use the TOS of the previous context, not the current context. To do that we need to save/restore the TOS. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1445366797-30894-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 499f533..ffa7a92 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -627,6 +627,7 @@ struct x86_perf_task_context { u64 lbr_from[MAX_LBR_ENTRIES]; u64 lbr_to[MAX_LBR_ENTRIES]; u64 lbr_info[MAX_LBR_ENTRIES]; + int tos; int lbr_callstack_users; int lbr_stack_state; }; diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index bfd0b71..659f01e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -239,7 +239,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) } mask = x86_pmu.lbr_nr - 1; - tos = intel_pmu_lbr_tos(); + tos = task_ctx->tos; for (i = 0; i < tos; i++) { lbr_idx = (tos - i) & mask; wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]); @@ -247,6 +247,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } + wrmsrl(x86_pmu.lbr_tos, tos); task_ctx->lbr_stack_state = LBR_NONE; } @@ -270,6 +271,7 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } + task_ctx->tos = tos; task_ctx->lbr_stack_state = LBR_VALID; } -- cgit v0.10.2 From 90eec103b96e30401c0b846045bf8a1c7159b6da Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 16 Nov 2015 11:08:45 +0100 Subject: treewide: Remove old email address There were still a number of references to my old Red Hat email address in the kernel source. Remove these while keeping the Red Hat copyright notices intact. Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c index 1e9c8b0..170d786 100644 --- a/arch/blackfin/kernel/perf_event.c +++ b/arch/blackfin/kernel/perf_event.c @@ -14,7 +14,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, * * ppc: diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c index 7cfd7f1..4dca183 100644 --- a/arch/sh/kernel/perf_event.c +++ b/arch/sh/kernel/perf_event.c @@ -10,7 +10,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, * * ppc: diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index b0da5ae..3091267 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -9,7 +9,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra */ #include diff --git a/arch/tile/kernel/perf_event.c b/arch/tile/kernel/perf_event.c index bb509ce..8767060 100644 --- a/arch/tile/kernel/perf_event.c +++ b/arch/tile/kernel/perf_event.c @@ -21,7 +21,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, * Copyright (C) 2009 Google, Inc., Stephane Eranian */ diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4562cf0..2bf79d7 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -5,7 +5,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, * Copyright (C) 2009 Google, Inc., Stephane Eranian * diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index ffa7a92..ab18b8a 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -5,7 +5,7 @@ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra * Copyright (C) 2009 Intel Corporation, * Copyright (C) 2009 Google, Inc., Stephane Eranian * diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c index dc5fa6a..3512ba6 100644 --- a/arch/x86/kernel/irq_work.c +++ b/arch/x86/kernel/irq_work.c @@ -1,7 +1,7 @@ /* * x86 specific code for irq_work * - * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra */ #include diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index db284bf..9dbb739 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -5,7 +5,7 @@ * Copyright 2001 Red Hat, Inc. * Based on code from mm/memory.c Copyright Linus Torvalds and others. * - * Copyright 2011 Red Hat, Inc., Peter Zijlstra + * Copyright 2011 Red Hat, Inc., Peter Zijlstra * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 8dde559..0536524 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -5,7 +5,7 @@ * Jump label support * * Copyright (C) 2009-2012 Jason Baron - * Copyright (C) 2011-2012 Peter Zijlstra + * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra * * DEPRECATED API: * diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 70400dc..c57e424 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -2,7 +2,7 @@ * Runtime locking correctness validator * * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * see Documentation/locking/lockdep-design.txt for more details. */ diff --git a/include/linux/proportions.h b/include/linux/proportions.h index 5440f64..2122133 100644 --- a/include/linux/proportions.h +++ b/include/linux/proportions.h @@ -1,7 +1,7 @@ /* * FLoating proportions * - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * This file contains the public data structure and API definitions. */ diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 0bdc72f..4a29c75 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -21,7 +21,7 @@ * Authors: * Srikar Dronamraju * Jim Keniston - * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra */ #include diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index d659487..9c41800 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Thomas Gleixner * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING diff --git a/kernel/events/core.c b/kernel/events/core.c index 1ac857a..5854fcf 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Thomas Gleixner * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index b5d1ea7..adfdc05 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Thomas Gleixner * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 4e5e979..7dad849 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -19,7 +19,7 @@ * Authors: * Srikar Dronamraju * Jim Keniston - * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra */ #include diff --git a/kernel/irq_work.c b/kernel/irq_work.c index cbf9fb8..bcf107c 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra * * Provides a framework for enqueueing and running callbacks from hardirq * context. The enqueueing is NMI-safe. diff --git a/kernel/jump_label.c b/kernel/jump_label.c index f7dd15d..05254ee 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -2,7 +2,7 @@ * jump label support * * Copyright (C) 2009 Jason Baron - * Copyright (C) 2011 Peter Zijlstra + * Copyright (C) 2011 Peter Zijlstra * */ #include diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index deae390..60ace56 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -6,7 +6,7 @@ * Started by Ingo Molnar: * * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * this code maps all the lock dependencies as they occur in a live kernel * and will warn about the following classes of locking bugs: diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c index d83d798..dbb61a3 100644 --- a/kernel/locking/lockdep_proc.c +++ b/kernel/locking/lockdep_proc.c @@ -6,7 +6,7 @@ * Started by Ingo Molnar: * * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * Code for /proc/lockdep and /proc/lockdep_stats: * diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c index c0a2051..caf4041 100644 --- a/kernel/sched/clock.c +++ b/kernel/sched/clock.c @@ -1,7 +1,7 @@ /* * sched_clock for unstable cpu clocks * - * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra * * Updates and enhancements: * Copyright (C) 2008 Red Hat, Inc. Steven Rostedt diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index f04fda8..90e26b1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -17,7 +17,7 @@ * Copyright (C) 2007, Thomas Gleixner * * Adaptive scheduling granularity, math enhancements by Peter Zijlstra - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra */ #include diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index abfc903..cc9f7a9 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -1,7 +1,7 @@ /* * trace event based perf event profiling/tracing * - * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra + * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra * Copyright (C) 2009-2010 Frederic Weisbecker */ diff --git a/lib/btree.c b/lib/btree.c index 4264871..f93a945 100644 --- a/lib/btree.c +++ b/lib/btree.c @@ -5,7 +5,7 @@ * * Copyright (c) 2007-2008 Joern Engel * Bits and pieces stolen from Peter Zijlstra's code, which is - * Copyright 2007, Red Hat Inc. Peter Zijlstra + * Copyright 2007, Red Hat Inc. Peter Zijlstra * GPLv2 * * see http://programming.kicks-ass.net/kernel-patches/vma_lookup/btree.patch diff --git a/lib/proportions.c b/lib/proportions.c index 6f72429..efa54f25 100644 --- a/lib/proportions.c +++ b/lib/proportions.c @@ -1,7 +1,7 @@ /* * Floating proportions * - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * Description: * diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 3e4d654..d15d88c 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2,7 +2,7 @@ * mm/page-writeback.c * * Copyright (C) 2002, Linus Torvalds. - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * * Contains functions related to writing back dirty pages at the * address_space level. -- cgit v0.10.2 From d2b9d2a5ad5ef04ff978c9923d19730cb05efd55 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 19 Nov 2015 15:44:44 +1100 Subject: powerpc/tm: Block signal return setting invalid MSR state Currently we allow both the MSR T and S bits to be set by userspace on a signal return. Unfortunately this is a reserved configuration and will cause a TM Bad Thing exception if attempted (via rfid). This patch checks for this case in both the 32 and 64 bit signals code. If both T and S are set, we mark the context as invalid. Found using a syscall fuzzer. Fixes: 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index a908ada..2220f7a 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -108,6 +108,7 @@ #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */ #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */ #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */ +#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */ #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T) #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 0dbee46..ef7c24e 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs, return 1; #endif /* CONFIG_SPE */ + /* Get the top half of the MSR from the user context */ + if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) + return 1; + msr_hi <<= 32; + /* If TM bits are set to the reserved value, it's an invalid context */ + if (MSR_TM_RESV(msr_hi)) + return 1; + /* Pull in the MSR TM bits from the user context */ + regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK); /* Now, recheckpoint. This loads up all of the checkpointed (older) * registers, including FP and V[S]Rs. After recheckpointing, the * transactional versions should be loaded. @@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, current->thread.tm_texasr |= TEXASR_FS; /* This loads the checkpointed FP/VEC state, if used */ tm_recheckpoint(¤t->thread, msr); - /* Get the top half of the MSR */ - if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR])) - return 1; - /* Pull in MSR TM from user context */ - regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK); /* This loads the speculative FP/VEC state, if used */ if (msr & MSR_FP) { diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 20756df..c676ece 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, /* get MSR separately, transfer the LE bit if doing signal return */ err |= __get_user(msr, &sc->gp_regs[PT_MSR]); + /* Don't allow reserved mode. */ + if (MSR_TM_RESV(msr)) + return -EINVAL; + /* pull in MSR TM from user context */ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); -- cgit v0.10.2 From 7f821fc9c77a9b01fe7b1d6e72717b33d8d64142 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 19 Nov 2015 15:44:45 +1100 Subject: powerpc/tm: Check for already reclaimed tasks Currently we can hit a scenario where we'll tm_reclaim() twice. This results in a TM bad thing exception because the second reclaim occurs when not in suspend mode. The scenario in which this can happen is the following. We attempt to deliver a signal to userspace. To do this we need obtain the stack pointer to write the signal context. To get this stack pointer we must tm_reclaim() in case we need to use the checkpointed stack pointer (see get_tm_stackpointer()). Normally we'd then return directly to userspace to deliver the signal without going through __switch_to(). Unfortunatley, if at this point we get an error (such as a bad userspace stack pointer), we need to exit the process. The exit will result in a __switch_to(). __switch_to() will attempt to save the process state which results in another tm_reclaim(). This tm_reclaim() now causes a TM Bad Thing exception as this state has already been saved and the processor is no longer in TM suspend mode. Whee! This patch checks the state of the MSR to ensure we are TM suspended before we attempt the tm_reclaim(). If we've already saved the state away, we should no longer be in TM suspend mode. This has the additional advantage of checking for a potential TM Bad Thing exception. Found using syscall fuzzer. Fixes: fb09692e71f1 ("powerpc: Add reclaim and recheckpoint functions for context switching transactional memory processes") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 75b6676..646bf4d 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr, msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; } + /* + * Use the current MSR TM suspended bit to track if we have + * checkpointed state outstanding. + * On signal delivery, we'd normally reclaim the checkpointed + * state to obtain stack pointer (see:get_tm_stackpointer()). + * This will then directly return to userspace without going + * through __switch_to(). However, if the stack frame is bad, + * we need to exit this thread which calls __switch_to() which + * will again attempt to reclaim the already saved tm state. + * Hence we need to check that we've not already reclaimed + * this state. + * We do this using the current MSR, rather tracking it in + * some specific thread_struct bit, as it has the additional + * benifit of checking for a potential TM bad thing exception. + */ + if (!MSR_TM_SUSPENDED(mfmsr())) + return; + tm_reclaim(thr, thr->regs->msr, cause); /* Having done the reclaim, we now have the checkpointed -- cgit v0.10.2 From 7c90e610b60cd1ed6abafd806acfaedccbbe52d1 Mon Sep 17 00:00:00 2001 From: Konstantin Shkolnyy Date: Tue, 10 Nov 2015 16:40:13 -0600 Subject: USB: cp210x: Remove CP2110 ID from compatibility list CP2110 ID (0x10c4, 0xea80) doesn't belong here because it's a HID and completely different from CP210x devices. Signed-off-by: Konstantin Shkolnyy Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index eac7cca..7d4f51a 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -132,7 +132,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ -- cgit v0.10.2 From f33a7f72e5fc033daccbb8d4753d7c5c41a4d67b Mon Sep 17 00:00:00 2001 From: Jonas Jonsson Date: Sun, 22 Nov 2015 11:47:17 +0100 Subject: USB: cdc_acm: Ignore Infineon Flash Loader utility Some modems, such as the Telit UE910, are using an Infineon Flash Loader utility. It has two interfaces, 2/2/0 (Abstract Modem) and 10/0/0 (CDC Data). The latter can be used as a serial interface to upgrade the firmware of the modem. However, that isn't possible when the cdc-acm driver takes control of the device. The following is an explanation of the behaviour by Daniele Palmas during discussion on linux-usb. "This is what happens when the device is turned on (without modifying the drivers): [155492.352031] usb 1-3: new high-speed USB device number 27 using ehci-pci [155492.485429] usb 1-3: config 1 interface 0 altsetting 0 endpoint 0x81 has an invalid bInterval 255, changing to 11 [155492.485436] usb 1-3: New USB device found, idVendor=058b, idProduct=0041 [155492.485439] usb 1-3: New USB device strings: Mfr=0, Product=0, SerialNumber=0 [155492.485952] cdc_acm 1-3:1.0: ttyACM0: USB ACM device This is the flashing device that is caught by the cdc-acm driver. Once the ttyACM appears, the application starts sending a magic string (simple write on the file descriptor) to keep the device in flashing mode. If this magic string is not properly received in a certain time interval, the modem goes on in normal operative mode: [155493.748094] usb 1-3: USB disconnect, device number 27 [155494.916025] usb 1-3: new high-speed USB device number 28 using ehci-pci [155495.059978] usb 1-3: New USB device found, idVendor=1bc7, idProduct=0021 [155495.059983] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [155495.059986] usb 1-3: Product: 6 CDC-ACM + 1 CDC-ECM [155495.059989] usb 1-3: Manufacturer: Telit [155495.059992] usb 1-3: SerialNumber: 359658044004697 [155495.138958] cdc_acm 1-3:1.0: ttyACM0: USB ACM device [155495.140832] cdc_acm 1-3:1.2: ttyACM1: USB ACM device [155495.142827] cdc_acm 1-3:1.4: ttyACM2: USB ACM device [155495.144462] cdc_acm 1-3:1.6: ttyACM3: USB ACM device [155495.145967] cdc_acm 1-3:1.8: ttyACM4: USB ACM device [155495.147588] cdc_acm 1-3:1.10: ttyACM5: USB ACM device [155495.154322] cdc_ether 1-3:1.12 wwan0: register 'cdc_ether' at usb-0000:00:1a.7-3, Mobile Broadband Network Device, 00:00:11:12:13:14 Using the cdc-acm driver, the string, though being sent in the same way than using the usb-serial-simple driver (I can confirm that the data is passing properly since I used an hw usb sniffer), does not make the device to stay in flashing mode." Signed-off-by: Jonas Jonsson Tested-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b30e742..26ca4f9 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1838,6 +1838,11 @@ static const struct usb_device_id acm_ids[] = { }, #endif + /* Exclude Infineon Flash Loader utility */ + { USB_DEVICE(0x058b, 0x0041), + .driver_info = IGNORE_DEVICE, + }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) }, -- cgit v0.10.2 From a0e80fbd56b4573de997c9a088a33abbc1121400 Mon Sep 17 00:00:00 2001 From: Jonas Jonsson Date: Sun, 22 Nov 2015 11:47:18 +0100 Subject: USB: serial: Another Infineon flash loader USB ID The flash loader has been seen on a Telit UE910 modem. The flash loader is a bit special, it presents both an ACM and CDC Data interface but only the latter is useful. Unless a magic string is sent to the device it will disappear and the regular modem device appears instead. Signed-off-by: Jonas Jonsson Tested-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 3658662..a204782 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -53,6 +53,7 @@ DEVICE(funsoft, FUNSOFT_IDS); /* Infineon Flashloader driver */ #define FLASHLOADER_IDS() \ + { USB_DEVICE_INTERFACE_CLASS(0x058b, 0x0041, USB_CLASS_CDC_DATA) }, \ { USB_DEVICE(0x8087, 0x0716) } DEVICE(flashloader, FLASHLOADER_IDS); -- cgit v0.10.2 From 2d5be37d686c4dae8e60d20283d6f44ac2c44f65 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 20 Nov 2015 12:24:00 +0100 Subject: x86/microcode: Initialize the driver late when facilities are up Running microcode_init() from setup_arch() is a bad idea because not even kmalloc() is ready at that point and the loader does all kinds of allocations and init/registration with various subsystems. Make it a late initcall when required facilities are initialized so that the microcode driver initialization can succeed too. Reported-and-tested-by: Markus Trippelsdorf Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20151120112400.GC4028@pd.tnic Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 7fc27f1..b3e94ef 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -698,3 +698,4 @@ int __init microcode_init(void) return error; } +late_initcall(microcode_init); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 29db25f..d2bbe34 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1250,8 +1250,6 @@ void __init setup_arch(char **cmdline_p) if (efi_enabled(EFI_BOOT)) efi_apply_memmap_quirks(); #endif - - microcode_init(); } #ifdef CONFIG_X86_32 -- cgit v0.10.2 From 0ad7d3a04b2a1a43fa71eb89f754527b082213ad Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 23 Nov 2015 12:51:53 +0200 Subject: ASoC: davinci-mcasp: Fix master capture only mode When McASP is used as TX/RX synchronous (TX side generating clocks for RX side also) and only capture is used we need to configure the number of TX slots in order McASP to be able to generate the Frame sync. Fixes: 9273de1940d9e ("ASoC: davinci-mcasp: Add set_tdm_slots() support") Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index caa0beb..c1c9c2e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -908,6 +908,14 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRMOD(total_slots), FSRMOD(0x1FF)); + /* + * If McASP is set to be TX/RX synchronous and the playback is + * not running already we need to configure the TX slots in + * order to have correct FSX on the bus + */ + if (mcasp_is_synchronous(mcasp) && !mcasp->channels) + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, + FSXMOD(total_slots), FSXMOD(0x1FF)); } return 0; -- cgit v0.10.2 From 87b5ed8ecb9fe05a696e1c0b53c7a49ea66432c1 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 23 Nov 2015 16:38:48 +0530 Subject: ASoC: Intel: Skylake: fix memory leak We have requested the firmware but missed releasing it. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index a7854c8..ffea427 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1240,6 +1240,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) */ ret = snd_soc_tplg_component_load(&platform->component, &skl_tplg_ops, fw, 0); + release_firmware(fw); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); return -EINVAL; -- cgit v0.10.2 From f3d4bb3342630cd3d89882586851498d8dc7c0f2 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 23 Nov 2015 08:13:45 +0100 Subject: spi: pl022: handle EPROBE_DEFER for dma Handle EPROBE_DEFER explicitly so that we ensure that we get the DMA channel specified in the device tree, instead of depending on the DMA controller getting probed before us. Signed-off-by: Rabin Vincent Signed-off-by: Mark Brown diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 94af806..5e5fd77 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1171,19 +1171,31 @@ err_no_rxchan: static int pl022_dma_autoprobe(struct pl022 *pl022) { struct device *dev = &pl022->adev->dev; + struct dma_chan *chan; + int err; /* automatically configure DMA channels from platform, normally using DT */ - pl022->dma_rx_channel = dma_request_slave_channel(dev, "rx"); - if (!pl022->dma_rx_channel) + chan = dma_request_slave_channel_reason(dev, "rx"); + if (IS_ERR(chan)) { + err = PTR_ERR(chan); goto err_no_rxchan; + } + + pl022->dma_rx_channel = chan; - pl022->dma_tx_channel = dma_request_slave_channel(dev, "tx"); - if (!pl022->dma_tx_channel) + chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(chan)) { + err = PTR_ERR(chan); goto err_no_txchan; + } + + pl022->dma_tx_channel = chan; pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!pl022->dummypage) + if (!pl022->dummypage) { + err = -ENOMEM; goto err_no_dummypage; + } return 0; @@ -1194,7 +1206,7 @@ err_no_txchan: dma_release_channel(pl022->dma_rx_channel); pl022->dma_rx_channel = NULL; err_no_rxchan: - return -ENODEV; + return err; } static void terminate_dma(struct pl022 *pl022) @@ -2236,6 +2248,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) /* Get DMA channels, try autoconfiguration first */ status = pl022_dma_autoprobe(pl022); + if (status == -EPROBE_DEFER) { + dev_dbg(dev, "deferring probe to get DMA channel\n"); + goto err_no_irq; + } /* If that failed, use channels from platform_info */ if (status == 0) -- cgit v0.10.2 From 0b466dc238cb660bbdb9ef6e121e1757057484c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Nov 2015 09:58:05 +0000 Subject: drm/i915: Mark uneven memory banks on gen4 desktop as unknown swizzling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have varied reports of swizzling corruption on gen4 desktop, and confirmation that one at least is triggered by uneven memory banks (L-shaped memory). The implication is that the swizzling varies between the paired channels and the remainder of memory on the single channel. As the object then has unpredictable swizzling (it will vary depending on exact page allocation and may even change during the object's lifetime as the pages are replaced), we have to report to userspace that the swizzling is unknown. However, some existing userspace is buggy when it meets an unknown swizzling configuration and so we need to tell another white lie and mark the swizzling as NONE but report it as UNKNOWN through the extended get-tiling-ioctl. See commit 5eb3e5a5e11d14f9deb2a4b83555443b69ab9940 Author: Chris Wilson Date: Sun Jun 28 09:19:26 2015 +0100 drm/i915: Declare the swizzling unknown for L-shaped configurations for the previous example where we found that telling the truth to userspace just ends up in a world of hurt. Also since we don't truly know what the swizzling is on the pages, we need to keep them pinned to prevent swapping as the reports also suggest that some gen4 devices have previously undetected bit17 swizzling. v2: Combine unknown + quirk patches to prevent userspace ever seeing unknown swizzling through the normal get-tiling-ioctl. Also use the same path for the existing uneven bank detection for mobile gen4. Reported-by: Matti Hämäläinen Tested-by: Matti Hämäläinen References: https://bugs.freedesktop.org/show_bug.cgi?id=90725 Signed-off-by: Chris Wilson Cc: Matti Hämäläinen Cc: Daniel Vetter Cc: Jani Nikula Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1447927085-31726-1-git-send-email-chris@chris-wilson.co.uk Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index 40a10b2..f010391 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -642,11 +642,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } /* check for L-shaped memory aka modified enhanced addressing */ - if (IS_GEN4(dev)) { - uint32_t ddc2 = I915_READ(DCC2); - - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) - dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + if (IS_GEN4(dev) && + !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) { + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; } if (dcc == 0xffffffff) { @@ -675,16 +674,35 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) * matching, which was the case for the swizzling required in * the table above, or from the 1-ch value being less than * the minimum size of a rank. + * + * Reports indicate that the swizzling actually + * varies depending upon page placement inside the + * channels, i.e. we see swizzled pages where the + * banks of memory are paired and unswizzled on the + * uneven portion, so leave that as unknown. */ - if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else { + if (I915_READ16(C0DRB3) == I915_READ16(C1DRB3)) { swizzle_x = I915_BIT_6_SWIZZLE_9_10; swizzle_y = I915_BIT_6_SWIZZLE_9; } } + if (swizzle_x == I915_BIT_6_SWIZZLE_UNKNOWN || + swizzle_y == I915_BIT_6_SWIZZLE_UNKNOWN) { + /* Userspace likes to explode if it sees unknown swizzling, + * so lie. We will finish the lie when reporting through + * the get-tiling-ioctl by reporting the physical swizzle + * mode as unknown instead. + * + * As we don't strictly know what the swizzling is, it may be + * bit17 dependent, and so we need to also prevent the pages + * from being moved. + */ + dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + dev_priv->mm.bit_6_swizzle_x = swizzle_x; dev_priv->mm.bit_6_swizzle_y = swizzle_y; } -- cgit v0.10.2 From 2e22502c080f27afeab5e6f11e618fb7bc7aea53 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 23 Nov 2015 19:32:51 +0530 Subject: ARC: dw2 unwind: Remove falllback linear search thru FDE entries Fixes STAR 9000953410: "perf callgraph profiling causing RCU stalls" | perf record -g -c 15000 -e cycles /sbin/hackbench | | INFO: rcu_preempt self-detected stall on CPU | 1: (1 GPs behind) idle=609/140000000000002/0 softirq=2914/2915 fqs=603 | Task dump for CPU 1: in-kernel dwarf unwinder has a fast binary lookup and a fallback linear search (which iterates thru each of ~11K entries) thus takes 2 orders of magnitude longer (~3 million cycles vs. 2000). Routines written in hand assembler lack dwarf info (as we don't support assembler CFI pseudo-ops yet) fail the unwinder binary lookup, hit linear search, failing nevertheless in the end. However the linear search is pointless as binary lookup tables are created from it in first place. It is impossible to have binary lookup fail while succeed the linear search. It is pure waste of cycles thus removed by this patch. This manifested as RCU stalls / NMI watchdog splat when running hackbench under perf with callgraph profiling. The triggering condition was perf counter overflowing in routine lacking dwarf info (like memset) leading to patheic 3 million cycle unwinder slow path and by the time it returned new interrupts were already pending (Timer, IPI) and taken rightaway. The original memset didn't make forward progress, system kept accruing more interrupts and more unwinder delayes in a vicious feedback loop, ultimately triggering the NMI diagnostic. Cc: stable@vger.kernel.org Signed-off-by: Vineet Gupta diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index 93c6ea5..7352475 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c @@ -986,42 +986,13 @@ int arc_unwind(struct unwind_frame_info *frame) (const u8 *)(fde + 1) + *fde, ptrType); - if (pc >= endLoc) + if (pc >= endLoc) { fde = NULL; - } else - fde = NULL; - } - if (fde == NULL) { - for (fde = table->address, tableSize = table->size; - cie = NULL, tableSize > sizeof(*fde) - && tableSize - sizeof(*fde) >= *fde; - tableSize -= sizeof(*fde) + *fde, - fde += 1 + *fde / sizeof(*fde)) { - cie = cie_for_fde(fde, table); - if (cie == &bad_cie) { cie = NULL; - break; } - if (cie == NULL - || cie == ¬_fde - || (ptrType = fde_pointer_type(cie)) < 0) - continue; - ptr = (const u8 *)(fde + 2); - startLoc = read_pointer(&ptr, - (const u8 *)(fde + 1) + - *fde, ptrType); - if (!startLoc) - continue; - if (!(ptrType & DW_EH_PE_indirect)) - ptrType &= - DW_EH_PE_FORM | DW_EH_PE_signed; - endLoc = - startLoc + read_pointer(&ptr, - (const u8 *)(fde + - 1) + - *fde, ptrType); - if (pc >= startLoc && pc < endLoc) - break; + } else { + fde = NULL; + cie = NULL; } } } -- cgit v0.10.2 From fe761bcb9046029dbdb277de41e40c1c5ad0cf8c Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 20 Nov 2015 11:54:08 +0800 Subject: net: fsl: expands dependencies of NET_VENDOR_FREESCALE Freescale hosts some ARMv8 based SoCs, and a generic convention ARCH_LAYERSCAPE is used to cover such SoCs. Adding ARCH_LAYERSCAPE to dependencies of NET_VENDOR_FREESCALE to support networking on those SoCs. The ARCH_LAYERSCAPE is introduced by: commit: 53a5fde05 arm64: Use generic Layerscape SoC family naming Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index ff76d4e..bee32a9 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -7,7 +7,8 @@ config NET_VENDOR_FREESCALE default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \ + ARCH_LAYERSCAPE ---help--- If you have a network (Ethernet) card belonging to this class, say Y. -- cgit v0.10.2 From 3b13758f51de30618d9c7f3fc174d8d1a3cb13cd Mon Sep 17 00:00:00 2001 From: Nina Schiff Date: Fri, 20 Nov 2015 12:31:39 -0800 Subject: cgroups: Allow dynamically changing net_classid The classid of a process is changed either when a process is moved to or from a cgroup or when the net_cls.classid file is updated. Previously net_cls only supported propogating these changes to the cgroup's related sockets when a process was added or removed from the cgroup. This means it was neccessary to remove and re-add all processes to a cgroup in order to update its classid. This change introduces support for doing this dynamically - i.e. when the value is changed in the net_cls_classid file, this will also trigger an update to the classid associated with all sockets controlled by the cgroup. This mimics the behaviour of other cgroup subsystems. net_prio circumvents this issue by storing an index into a table with each socket (and so any updates to the table, don't require updating the value associated with the socket). net_cls, however, passes the socket the classid directly, and so this additional step is needed. Signed-off-by: Nina Schiff Acked-by: Tejun Heo Signed-off-by: David S. Miller diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 6441f47..2e4df84 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -56,7 +56,7 @@ static void cgrp_css_free(struct cgroup_subsys_state *css) kfree(css_cls_state(css)); } -static int update_classid(const void *v, struct file *file, unsigned n) +static int update_classid_sock(const void *v, struct file *file, unsigned n) { int err; struct socket *sock = sock_from_file(file, &err); @@ -67,18 +67,25 @@ static int update_classid(const void *v, struct file *file, unsigned n) return 0; } -static void cgrp_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void update_classid(struct cgroup_subsys_state *css, void *v) { - struct cgroup_cls_state *cs = css_cls_state(css); - void *v = (void *)(unsigned long)cs->classid; + struct css_task_iter it; struct task_struct *p; - cgroup_taskset_for_each(p, tset) { + css_task_iter_start(css, &it); + while ((p = css_task_iter_next(&it))) { task_lock(p); - iterate_fd(p->files, 0, update_classid, v); + iterate_fd(p->files, 0, update_classid_sock, v); task_unlock(p); } + css_task_iter_end(&it); +} + +static void cgrp_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + update_classid(css, + (void *)(unsigned long)css_cls_state(css)->classid); } static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft) @@ -89,8 +96,11 @@ static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft) static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, u64 value) { - css_cls_state(css)->classid = (u32) value; + struct cgroup_cls_state *cs = css_cls_state(css); + + cs->classid = (u32)value; + update_classid(css, (void *)(unsigned long)cs->classid); return 0; } -- cgit v0.10.2 From 393a0bd4376a8ecdde079344681a014ec3eb1291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 5 Nov 2015 12:57:10 +0100 Subject: drm/amdgpu: optimize scheduler fence handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only need to wait for jobs to be scheduled when the dependency is from the same scheduler. Signed-off-by: Christian König Reviewed-by: Chunming Zhou diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index ea30d6a..b7cd108 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -211,6 +211,41 @@ static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb) amd_sched_wakeup(entity->sched); } +static bool amd_sched_entity_add_dependency_cb(struct amd_sched_entity *entity) +{ + struct amd_gpu_scheduler *sched = entity->sched; + struct fence * fence = entity->dependency; + struct amd_sched_fence *s_fence; + + if (fence->context == entity->fence_context) { + /* We can ignore fences from ourself */ + fence_put(entity->dependency); + return false; + } + + s_fence = to_amd_sched_fence(fence); + if (s_fence && s_fence->sched == sched) { + /* Fence is from the same scheduler */ + if (test_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &fence->flags)) { + /* Ignore it when it is already scheduled */ + fence_put(entity->dependency); + return false; + } + + /* Wait for fence to be scheduled */ + entity->cb.func = amd_sched_entity_wakeup; + list_add_tail(&entity->cb.node, &s_fence->scheduled_cb); + return true; + } + + if (!fence_add_callback(entity->dependency, &entity->cb, + amd_sched_entity_wakeup)) + return true; + + fence_put(entity->dependency); + return false; +} + static struct amd_sched_job * amd_sched_entity_pop_job(struct amd_sched_entity *entity) { @@ -223,20 +258,9 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity) if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job))) return NULL; - while ((entity->dependency = sched->ops->dependency(sched_job))) { - - if (entity->dependency->context == entity->fence_context) { - /* We can ignore fences from ourself */ - fence_put(entity->dependency); - continue; - } - - if (fence_add_callback(entity->dependency, &entity->cb, - amd_sched_entity_wakeup)) - fence_put(entity->dependency); - else + while ((entity->dependency = sched->ops->dependency(sched_job))) + if (amd_sched_entity_add_dependency_cb(entity)) return NULL; - } return sched_job; } @@ -400,6 +424,7 @@ static int amd_sched_main(void *param) atomic_inc(&sched->hw_rq_count); fence = sched->ops->run_job(sched_job); + amd_sched_fence_scheduled(s_fence); if (fence) { r = fence_add_callback(fence, &s_fence->cb, amd_sched_process_job); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 939692b..a0f0ae5 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -27,6 +27,8 @@ #include #include +#define AMD_SCHED_FENCE_SCHEDULED_BIT FENCE_FLAG_USER_BITS + struct amd_gpu_scheduler; struct amd_sched_rq; @@ -68,6 +70,7 @@ struct amd_sched_rq { struct amd_sched_fence { struct fence base; struct fence_cb cb; + struct list_head scheduled_cb; struct amd_gpu_scheduler *sched; spinlock_t lock; void *owner; @@ -134,7 +137,7 @@ void amd_sched_entity_push_job(struct amd_sched_job *sched_job); struct amd_sched_fence *amd_sched_fence_create( struct amd_sched_entity *s_entity, void *owner); +void amd_sched_fence_scheduled(struct amd_sched_fence *fence); void amd_sched_fence_signal(struct amd_sched_fence *fence); - #endif diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c index 8d2130b..87c78ee 100644 --- a/drivers/gpu/drm/amd/scheduler/sched_fence.c +++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c @@ -35,6 +35,8 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL); if (fence == NULL) return NULL; + + INIT_LIST_HEAD(&fence->scheduled_cb); fence->owner = owner; fence->sched = s_entity->sched; spin_lock_init(&fence->lock); @@ -55,6 +57,17 @@ void amd_sched_fence_signal(struct amd_sched_fence *fence) FENCE_TRACE(&fence->base, "was already signaled\n"); } +void amd_sched_fence_scheduled(struct amd_sched_fence *s_fence) +{ + struct fence_cb *cur, *tmp; + + set_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &s_fence->base.flags); + list_for_each_entry_safe(cur, tmp, &s_fence->scheduled_cb, node) { + list_del_init(&cur->node); + cur->func(&s_fence->base, cur); + } +} + static const char *amd_sched_fence_get_driver_name(struct fence *fence) { return "amd_sched"; -- cgit v0.10.2 From 3d65193635e122d0783b97cb2202b7f21601037a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 12 Nov 2015 21:10:35 +0100 Subject: drm/amdgpu: move dependency handling out of atomic section v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way the driver isn't limited in the dependency handling callback. v2: remove extra check in amd_sched_entity_pop_job() Signed-off-by: Christian König Reviewed-by: Chunming Zhou diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index b7cd108..651129f 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -30,8 +30,7 @@ #define CREATE_TRACE_POINTS #include "gpu_sched_trace.h" -static struct amd_sched_job * -amd_sched_entity_pop_job(struct amd_sched_entity *entity); +static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity); static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); struct kmem_cache *sched_fence_slab; @@ -64,36 +63,36 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq, } /** - * Select next job from a specified run queue with round robin policy. - * Return NULL if nothing available. + * Select an entity which could provide a job to run + * + * @rq The run queue to check. + * + * Try to find a ready entity, returns NULL if none found. */ -static struct amd_sched_job * -amd_sched_rq_select_job(struct amd_sched_rq *rq) +static struct amd_sched_entity * +amd_sched_rq_select_entity(struct amd_sched_rq *rq) { struct amd_sched_entity *entity; - struct amd_sched_job *sched_job; spin_lock(&rq->lock); entity = rq->current_entity; if (entity) { list_for_each_entry_continue(entity, &rq->entities, list) { - sched_job = amd_sched_entity_pop_job(entity); - if (sched_job) { + if (amd_sched_entity_is_ready(entity)) { rq->current_entity = entity; spin_unlock(&rq->lock); - return sched_job; + return entity; } } } list_for_each_entry(entity, &rq->entities, list) { - sched_job = amd_sched_entity_pop_job(entity); - if (sched_job) { + if (amd_sched_entity_is_ready(entity)) { rq->current_entity = entity; spin_unlock(&rq->lock); - return sched_job; + return entity; } if (entity == rq->current_entity) @@ -177,6 +176,24 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) } /** + * Check if entity is ready + * + * @entity The pointer to a valid scheduler entity + * + * Return true if entity could provide a job. + */ +static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity) +{ + if (kfifo_is_empty(&entity->job_queue)) + return false; + + if (ACCESS_ONCE(entity->dependency)) + return false; + + return true; +} + +/** * Destroy a context entity * * @sched Pointer to scheduler instance @@ -252,9 +269,6 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity) struct amd_gpu_scheduler *sched = entity->sched; struct amd_sched_job *sched_job; - if (ACCESS_ONCE(entity->dependency)) - return NULL; - if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job))) return NULL; @@ -328,22 +342,22 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) } /** - * Select next to run + * Select next entity to process */ -static struct amd_sched_job * -amd_sched_select_job(struct amd_gpu_scheduler *sched) +static struct amd_sched_entity * +amd_sched_select_entity(struct amd_gpu_scheduler *sched) { - struct amd_sched_job *sched_job; + struct amd_sched_entity *entity; if (!amd_sched_ready(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ - sched_job = amd_sched_rq_select_job(&sched->kernel_rq); - if (sched_job == NULL) - sched_job = amd_sched_rq_select_job(&sched->sched_rq); + entity = amd_sched_rq_select_entity(&sched->kernel_rq); + if (entity == NULL) + entity = amd_sched_rq_select_entity(&sched->sched_rq); - return sched_job; + return entity; } static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) @@ -405,13 +419,16 @@ static int amd_sched_main(void *param) unsigned long flags; wait_event_interruptible(sched->wake_up_worker, - kthread_should_stop() || - (sched_job = amd_sched_select_job(sched))); + (entity = amd_sched_select_entity(sched)) || + kthread_should_stop()); + if (!entity) + continue; + + sched_job = amd_sched_entity_pop_job(entity); if (!sched_job) continue; - entity = sched_job->s_entity; s_fence = sched_job->s_fence; if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { -- cgit v0.10.2 From 7d267278a9ece963d77eefec61630223fce08c6c Mon Sep 17 00:00:00 2001 From: Rainer Weikusat Date: Fri, 20 Nov 2015 22:07:23 +0000 Subject: unix: avoid use-after-free in ep_remove_wait_queue Rainer Weikusat writes: An AF_UNIX datagram socket being the client in an n:1 association with some server socket is only allowed to send messages to the server if the receive queue of this socket contains at most sk_max_ack_backlog datagrams. This implies that prospective writers might be forced to go to sleep despite none of the message presently enqueued on the server receive queue were sent by them. In order to ensure that these will be woken up once space becomes again available, the present unix_dgram_poll routine does a second sock_poll_wait call with the peer_wait wait queue of the server socket as queue argument (unix_dgram_recvmsg does a wake up on this queue after a datagram was received). This is inherently problematic because the server socket is only guaranteed to remain alive for as long as the client still holds a reference to it. In case the connection is dissolved via connect or by the dead peer detection logic in unix_dgram_sendmsg, the server socket may be freed despite "the polling mechanism" (in particular, epoll) still has a pointer to the corresponding peer_wait queue. There's no way to forcibly deregister a wait queue with epoll. Based on an idea by Jason Baron, the patch below changes the code such that a wait_queue_t belonging to the client socket is enqueued on the peer_wait queue of the server whenever the peer receive queue full condition is detected by either a sendmsg or a poll. A wake up on the peer queue is then relayed to the ordinary wait queue of the client socket via wake function. The connection to the peer wait queue is again dissolved if either a wake up is about to be relayed or the client socket reconnects or a dead peer is detected or the client socket is itself closed. This enables removing the second sock_poll_wait from unix_dgram_poll, thus avoiding the use-after-free, while still ensuring that no blocked writer sleeps forever. Signed-off-by: Rainer Weikusat Fixes: ec0d215f9420 ("af_unix: fix 'poll for write'/connected DGRAM sockets") Reviewed-by: Jason Baron Signed-off-by: David S. Miller diff --git a/include/net/af_unix.h b/include/net/af_unix.h index b36d837..2a91a05 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -62,6 +62,7 @@ struct unix_sock { #define UNIX_GC_CANDIDATE 0 #define UNIX_GC_MAYBE_CYCLE 1 struct socket_wq peer_wq; + wait_queue_t peer_wake; }; static inline struct unix_sock *unix_sk(const struct sock *sk) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 955ec15..4e95bdf 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -326,6 +326,118 @@ found: return s; } +/* Support code for asymmetrically connected dgram sockets + * + * If a datagram socket is connected to a socket not itself connected + * to the first socket (eg, /dev/log), clients may only enqueue more + * messages if the present receive queue of the server socket is not + * "too large". This means there's a second writeability condition + * poll and sendmsg need to test. The dgram recv code will do a wake + * up on the peer_wait wait queue of a socket upon reception of a + * datagram which needs to be propagated to sleeping would-be writers + * since these might not have sent anything so far. This can't be + * accomplished via poll_wait because the lifetime of the server + * socket might be less than that of its clients if these break their + * association with it or if the server socket is closed while clients + * are still connected to it and there's no way to inform "a polling + * implementation" that it should let go of a certain wait queue + * + * In order to propagate a wake up, a wait_queue_t of the client + * socket is enqueued on the peer_wait queue of the server socket + * whose wake function does a wake_up on the ordinary client socket + * wait queue. This connection is established whenever a write (or + * poll for write) hit the flow control condition and broken when the + * association to the server socket is dissolved or after a wake up + * was relayed. + */ + +static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags, + void *key) +{ + struct unix_sock *u; + wait_queue_head_t *u_sleep; + + u = container_of(q, struct unix_sock, peer_wake); + + __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, + q); + u->peer_wake.private = NULL; + + /* relaying can only happen while the wq still exists */ + u_sleep = sk_sleep(&u->sk); + if (u_sleep) + wake_up_interruptible_poll(u_sleep, key); + + return 0; +} + +static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) +{ + struct unix_sock *u, *u_other; + int rc; + + u = unix_sk(sk); + u_other = unix_sk(other); + rc = 0; + spin_lock(&u_other->peer_wait.lock); + + if (!u->peer_wake.private) { + u->peer_wake.private = other; + __add_wait_queue(&u_other->peer_wait, &u->peer_wake); + + rc = 1; + } + + spin_unlock(&u_other->peer_wait.lock); + return rc; +} + +static void unix_dgram_peer_wake_disconnect(struct sock *sk, + struct sock *other) +{ + struct unix_sock *u, *u_other; + + u = unix_sk(sk); + u_other = unix_sk(other); + spin_lock(&u_other->peer_wait.lock); + + if (u->peer_wake.private == other) { + __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); + u->peer_wake.private = NULL; + } + + spin_unlock(&u_other->peer_wait.lock); +} + +static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, + struct sock *other) +{ + unix_dgram_peer_wake_disconnect(sk, other); + wake_up_interruptible_poll(sk_sleep(sk), + POLLOUT | + POLLWRNORM | + POLLWRBAND); +} + +/* preconditions: + * - unix_peer(sk) == other + * - association is stable + */ +static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) +{ + int connected; + + connected = unix_dgram_peer_wake_connect(sk, other); + + if (unix_recvq_full(other)) + return 1; + + if (connected) + unix_dgram_peer_wake_disconnect(sk, other); + + return 0; +} + static int unix_writable(const struct sock *sk) { return sk->sk_state != TCP_LISTEN && @@ -431,6 +543,8 @@ static void unix_release_sock(struct sock *sk, int embrion) skpair->sk_state_change(skpair); sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); } + + unix_dgram_peer_wake_disconnect(sk, skpair); sock_put(skpair); /* It may now die */ unix_peer(sk) = NULL; } @@ -666,6 +780,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern) INIT_LIST_HEAD(&u->link); mutex_init(&u->readlock); /* single task reading lock */ init_waitqueue_head(&u->peer_wait); + init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); unix_insert_socket(unix_sockets_unbound(sk), sk); out: if (sk == NULL) @@ -1033,6 +1148,8 @@ restart: if (unix_peer(sk)) { struct sock *old_peer = unix_peer(sk); unix_peer(sk) = other; + unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); + unix_state_double_unlock(sk, other); if (other != old_peer) @@ -1472,6 +1589,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, struct scm_cookie scm; int max_level; int data_len = 0; + int sk_locked; wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); @@ -1550,12 +1668,14 @@ restart: goto out_free; } + sk_locked = 0; unix_state_lock(other); +restart_locked: err = -EPERM; if (!unix_may_send(sk, other)) goto out_unlock; - if (sock_flag(other, SOCK_DEAD)) { + if (unlikely(sock_flag(other, SOCK_DEAD))) { /* * Check with 1003.1g - what should * datagram error @@ -1563,10 +1683,14 @@ restart: unix_state_unlock(other); sock_put(other); + if (!sk_locked) + unix_state_lock(sk); + err = 0; - unix_state_lock(sk); if (unix_peer(sk) == other) { unix_peer(sk) = NULL; + unix_dgram_peer_wake_disconnect_wakeup(sk, other); + unix_state_unlock(sk); unix_dgram_disconnected(sk, other); @@ -1592,21 +1716,38 @@ restart: goto out_unlock; } - if (unix_peer(other) != sk && unix_recvq_full(other)) { - if (!timeo) { - err = -EAGAIN; - goto out_unlock; + if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { + if (timeo) { + timeo = unix_wait_for_peer(other, timeo); + + err = sock_intr_errno(timeo); + if (signal_pending(current)) + goto out_free; + + goto restart; } - timeo = unix_wait_for_peer(other, timeo); + if (!sk_locked) { + unix_state_unlock(other); + unix_state_double_lock(sk, other); + } - err = sock_intr_errno(timeo); - if (signal_pending(current)) - goto out_free; + if (unix_peer(sk) != other || + unix_dgram_peer_wake_me(sk, other)) { + err = -EAGAIN; + sk_locked = 1; + goto out_unlock; + } - goto restart; + if (!sk_locked) { + sk_locked = 1; + goto restart_locked; + } } + if (unlikely(sk_locked)) + unix_state_unlock(sk); + if (sock_flag(other, SOCK_RCVTSTAMP)) __net_timestamp(skb); maybe_add_creds(skb, sock, other); @@ -1620,6 +1761,8 @@ restart: return len; out_unlock: + if (sk_locked) + unix_state_unlock(sk); unix_state_unlock(other); out_free: kfree_skb(skb); @@ -2476,14 +2619,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, return mask; writable = unix_writable(sk); - other = unix_peer_get(sk); - if (other) { - if (unix_peer(other) != sk) { - sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); - if (unix_recvq_full(other)) - writable = 0; - } - sock_put(other); + if (writable) { + unix_state_lock(sk); + + other = unix_peer(sk); + if (other && unix_peer(other) != sk && + unix_recvq_full(other) && + unix_dgram_peer_wake_me(sk, other)) + writable = 0; + + unix_state_unlock(sk); } if (writable) -- cgit v0.10.2 From 6af1a07316f3448c49a39667e7616493f72a38f8 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Mon, 19 Oct 2015 11:09:34 -0700 Subject: soc: ti: use request_firmware_direct() as acc firmware is optional When firmware image for PDSP firmware is absent in the file system the kernel boot with ramfs/nfs is stuck for 60 seconds being the the default timeout. request_firmware_direct() is to take care of such optional firmware loading and hence replace the call in the driver with this API. Signed-off-by: Murali Karicheri Signed-off-by: Santosh Shilimkar diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index f3a0b6a..89789e2 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1519,9 +1519,9 @@ static int knav_queue_load_pdsp(struct knav_device *kdev, for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) { if (knav_acc_firmwares[i]) { - ret = request_firmware(&fw, - knav_acc_firmwares[i], - kdev->dev); + ret = request_firmware_direct(&fw, + knav_acc_firmwares[i], + kdev->dev); if (!ret) { found = true; break; -- cgit v0.10.2 From f7f2bccd1fe635eecb1739af1018eb0d4072282f Mon Sep 17 00:00:00 2001 From: Michal Morawiec Date: Mon, 23 Nov 2015 10:35:21 -0800 Subject: soc: ti: knav_qmss_queue: Fix linking RAM setup for queue managers Configure linking RAM for both queue managers also in case when only linking RAM 0 is specified in device tree. Currently hwqueue driver configures linking RAM(s) to be used cooperatively by the QMs (shared mode). Therefore if both queue managers are used then both must be configured with exactly the same linking RAM info (base address and size) independent of the number of linking RAM(s) specified in the device tree. For proper operation only one linking RAM is required and in most cases this can be internal one as long as it is able to handle the number of descriptors used in the system. Current driver code however skips configuration of second queue manager if second linking RAM is not specified. If the configuration for the QM2 is missing there will be a crash when it tries to push/pop descriptors from its queues. Signed-off-by: Michal Morawiec Signed-off-by: Santosh Shilimkar diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 89789e2..8c03a80 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1179,7 +1179,7 @@ static int knav_queue_setup_link_ram(struct knav_device *kdev) block++; if (!block->size) - return 0; + continue; dev_dbg(kdev->dev, "linkram1: phys:%x, virt:%p, size:%x\n", block->phys, block->virt, block->size); -- cgit v0.10.2 From 17e846aa390d89adae053d9d2ba8acb286b64af7 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Mon, 23 Nov 2015 10:35:25 -0800 Subject: ARM: dts: keystone: k2l: fix kernel crash when clk_ignore_unused is not in bootargs Currently kernel crash randomly when K2L EVM is booted without clk_ignore_unused in the bootargs. This workaround is not needed on other K2 devices such as K2HK and K2E and with this fix, we can remove the workaround altogether. netcp driver on K2L uses linked ram on OSR (On chip Static RAM) and requires the clock to this peripheral enabled for proper functioning. This is the reason for the kernel crash. So add the clock node to fix this issue. While at it, remove the workaround documentation as well. With the fix applied, clk_summary dump shows the clock to OSR enabled. cat /sys/kernel/debug/clk/clk_summary ------cut-------------- tcp3d-1 0 0 399360000 0 0 tcp3d-0 0 0 399360000 0 0 osr 1 1 399360000 0 0 fftc-0 0 0 399360000 0 0 -----cut---------------- Signed-off-by: Murali Karicheri Signed-off-by: Santosh Shilimkar diff --git a/Documentation/arm/keystone/Overview.txt b/Documentation/arm/keystone/Overview.txt index f17bc4c..400c0c2 100644 --- a/Documentation/arm/keystone/Overview.txt +++ b/Documentation/arm/keystone/Overview.txt @@ -49,24 +49,6 @@ specified through DTS. Following are the DTS used:- The device tree documentation for the keystone machines are located at Documentation/devicetree/bindings/arm/keystone/keystone.txt -Known issues & workaround -------------------------- - -Some of the device drivers used on keystone are re-used from that from -DaVinci and other TI SoCs. These device drivers may use clock APIs directly. -Some of the keystone specific drivers such as netcp uses run time power -management API instead to enable clock. As this API has limitations on -keystone, following workaround is needed to boot Linux. - - Add 'clk_ignore_unused' to the bootargs env variable in u-boot. Otherwise - clock frameworks will try to disable clocks that are unused and disable - the hardware. This is because netcp related power domain and clock - domains are enabled in u-boot as run time power management API currently - doesn't enable clocks for netcp due to a limitation. This workaround is - expected to be removed in the future when proper API support becomes - available. Until then, this work around is needed. - - Document Author --------------- Murali Karicheri diff --git a/arch/arm/boot/dts/k2l-netcp.dtsi b/arch/arm/boot/dts/k2l-netcp.dtsi index 01aef23..5acbd0d 100644 --- a/arch/arm/boot/dts/k2l-netcp.dtsi +++ b/arch/arm/boot/dts/k2l-netcp.dtsi @@ -137,7 +137,7 @@ netcp: netcp@26000000 { /* NetCP address range */ ranges = <0 0x26000000 0x1000000>; - clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>; + clocks = <&clkosr>, <&papllclk>, <&clkcpgmac>, <&chipclk12>; dma-coherent; ti,navigator-dmas = <&dma_gbe 0>, -- cgit v0.10.2 From 0fcb04d59351f790efb8da18edefd6ab4d9bbf3b Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 23 Nov 2015 13:44:38 -0500 Subject: dm thin: fix regression in advertised discard limits When establishing a thin device's discard limits we cannot rely on the underlying thin-pool device's discard capabilities (which are inherited from the thin-pool's underlying data device) given that DM thin devices must provide discard support even when the thin-pool's underlying data device doesn't support discards. Users were exposed to this thin device discard limits regression if their thin-pool's underlying data device does _not_ support discards. This regression caused all upper-layers that called the blkdev_issue_discard() interface to not be able to issue discards to thin devices (because discard_granularity was 0). This regression wasn't caught earlier because the device-mapper-test-suite's extensive 'thin-provisioning' discard tests are only ever performed against thin-pool's with data devices that support discards. Fix is to have thin_io_hints() test the pool's 'discard_enabled' feature rather than inferring whether or not a thin device's discard support should be enabled by looking at the thin-pool's discard_granularity. Fixes: 216076705 ("dm thin: disable discard support for thin devices if pool's is disabled") Reported-by: Mike Gerber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 4.1+ diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 9f0b94f..63903a5 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -4250,10 +4250,9 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) { struct thin_c *tc = ti->private; struct pool *pool = tc->pool; - struct queue_limits *pool_limits = dm_get_queue_limits(pool->pool_md); - if (!pool_limits->discard_granularity) - return; /* pool's discard support is disabled */ + if (!pool->pf.discard_enabled) + return; limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; limits->max_discard_sectors = 2048 * 1024 * 16; /* 16G */ -- cgit v0.10.2 From 3d1a54e801b661fdc7a409cfc350b6ee555e00fc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 21 Nov 2015 13:34:12 +0300 Subject: net/hsr: fix a warning message WARN_ON_ONCE() takes a condition, it doesn't take an error message. I have converted this to WARN() instead. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 35a9788..c7d1adc 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -312,7 +312,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master, u8 type) return; out: - WARN_ON_ONCE("HSR: Could not send supervision frame\n"); + WARN_ONCE(1, "HSR: Could not send supervision frame\n"); kfree_skb(skb); } -- cgit v0.10.2 From 9dc17917733f5a53ef970ac95a48d2dfb7dc7202 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Thu, 19 Nov 2015 10:40:07 -0500 Subject: cpufreq: CPPC: Initialize and check CPUFreq CPU co-ord type correctly The CPU policy struct indicates the co-ordination type for all CPUs of a common freq domain. Initialize it correctly using the CPU specific data gathered from CPPC ACPI lib via acpi_get_psd_map(). The PSD object is optional, so the cpu->shared_type can also be 0. So instead of assuming any value other than SW_ANY(0xFD) is unsupported, explictly check if shared_type is SW_ALL and then bail. Signed-off-by: Ashwin Chaugule Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index e8cb334..7c0bdfb 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -98,10 +98,11 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->max = cpu->perf_caps.highest_perf; policy->cpuinfo.min_freq = policy->min; policy->cpuinfo.max_freq = policy->max; + policy->shared_type = cpu->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) cpumask_copy(policy->cpus, cpu->shared_cpu_map); - else { + else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) { /* Support only SW_ANY for now. */ pr_debug("Unsupported CPU co-ord type\n"); return -EFAULT; -- cgit v0.10.2 From f344dae0fe9f88d3c7ec45f2d7bba84d6ce1ac00 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 21 Nov 2015 09:06:49 +0530 Subject: cpufreq: Always remove sysfs cpuX/cpufreq link on ->remove_dev() Subsys interface's ->remove_dev() is called when the cpufreq driver is unregistering or the CPU is getting physically removed. We keep removing the cpuX/cpufreq link for all CPUs except the last one, which is a mistake as all CPUs contain a link now. Because of this, one CPU from each policy will still contain a link (to an already removed policyX directory), after the cpufreq driver is unregistered. Fix that by removing the link first and then only see if the policy is required to be freed. That will make sure that no links are left out. Fixes: 96bdda61f58b ("cpufreq: create cpu/cpufreq/policyX directories") Reported-and-tested-by: Srinivas Pandruvada Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7c48e73..a83c995 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1401,13 +1401,10 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) } cpumask_clear_cpu(cpu, policy->real_cpus); + remove_cpu_dev_symlink(policy, cpu); - if (cpumask_empty(policy->real_cpus)) { + if (cpumask_empty(policy->real_cpus)) cpufreq_policy_free(policy, true); - return; - } - - remove_cpu_dev_symlink(policy, cpu); } static void handle_update(struct work_struct *work) -- cgit v0.10.2 From 8478f53946f01b8365a206ac58a2640e3e408fb2 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Fri, 20 Nov 2015 18:47:56 -0500 Subject: cpufreq: intel_pstate: Fix limits->max_policy_pct rounding error I have a Intel (6,63) processor with a "marketing" frequency (from /proc/cpuinfo) of 2100MHz, and a max turbo frequency of 2600MHz. I can execute cpupower frequency-set -g powersave --min 1200MHz --max 2100MHz and the max_freq_pct is set to 80. When adding load to the system I noticed that the cpu frequency only reached 2000MHZ and not 2100MHz as expected. This is because limits->max_policy_pct is calculated as 2100 * 100 /2600 = 80.7 and is rounded down to 80 when it should be rounded up to 81. This patch adds a DIV_ROUND_UP() which will return the correct value. Signed-off-by: Prarit Bhargava Acked-by: Srinivas Pandruvada Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 001a532..eb75053 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1108,7 +1108,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits = &powersave_limits; limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq; limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100); - limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq; + limits->max_policy_pct = DIV_ROUND_UP(policy->max * 100, + policy->cpuinfo.max_freq); limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100); /* Normalize user input to [min_policy_pct, max_policy_pct] */ -- cgit v0.10.2 From 785ee27881411bd971d5e37a7fd72a5063fc1237 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Fri, 20 Nov 2015 18:47:57 -0500 Subject: cpufreq: intel_pstate: Fix limits->max_perf rounding error A rounding error was found in the calculation of limits->max_perf in intel_pstate_set_policy(), which is used to calculate the max and min pstate values in intel_pstate_get_min_max(). In that code, limits->max_perf is truncated to 2 hex digits such that, for example, 0x169 was incorrectly calculated to 0x16 instead of 0x17. This resulted in the pstate being set one level too low. This patch rounds the value of limits->max_perf up instead of down so that the correct max pstate can be reached. Signed-off-by: Prarit Bhargava Acked-by: Srinivas Pandruvada Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index eb75053..8ad1f95 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1121,6 +1121,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits->max_sysfs_pct); limits->max_perf_pct = max(limits->min_policy_pct, limits->max_perf_pct); + limits->max_perf = round_up(limits->max_perf, 8); /* Make sure min_perf_pct <= max_perf_pct */ limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct); -- cgit v0.10.2 From 73124ced9cd7d0bceab50888a3d3d3a3c8796b4c Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Wed, 18 Nov 2015 13:52:44 +0000 Subject: cpufreq: SCPI: Depend on SCPI clk driver The SCPI clk driver registers the virtual cpufreq device that kicks off initialisation of the SCPI cpufreq driver. Also, clk_get() will fail for the cpufreq driver if the SCPI clk driver is missing. Fix this by making the SCPI cpufreq driver explicitly depend on the SCPI clk driver. Fixes: 8def31034d03 (cpufreq: arm_big_little: add SCPI interface driver) Signed-off-by: Punit Agrawal Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 8014c23..235a1ba 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -202,7 +202,7 @@ config ARM_SA1110_CPUFREQ config ARM_SCPI_CPUFREQ tristate "SCPI based CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL + depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI help This adds the CPUfreq driver support for ARM big.LITTLE platforms using SCPI protocol for CPU power management. -- cgit v0.10.2 From 7f109f7cc37108cba7243bc832988525b0d85909 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Sat, 21 Nov 2015 19:46:19 +0100 Subject: vrf: fix double free and memory corruption on register_netdevice failure When vrf's ->newlink is called, if register_netdevice() fails then it does free_netdev(), but that's also done by rtnl_newlink() so a second free happens and memory gets corrupted, to reproduce execute the following line a couple of times (1 - 5 usually is enough): $ for i in `seq 1 5`; do ip link add vrf: type vrf table 1; done; This works because we fail in register_netdevice() because of the wrong name "vrf:". And here's a trace of one crash: [ 28.792157] ------------[ cut here ]------------ [ 28.792407] kernel BUG at fs/namei.c:246! [ 28.792608] invalid opcode: 0000 [#1] SMP [ 28.793240] Modules linked in: vrf nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace sunrpc crct10dif_pclmul crc32_pclmul crc32c_intel qxl drm_kms_helper ttm drm aesni_intel aes_x86_64 psmouse glue_helper lrw evdev gf128mul i2c_piix4 ablk_helper cryptd ppdev parport_pc parport serio_raw pcspkr virtio_balloon virtio_console i2c_core acpi_cpufreq button 9pnet_virtio 9p 9pnet fscache ipv6 autofs4 ext4 crc16 mbcache jbd2 virtio_blk virtio_net sg sr_mod cdrom ata_generic ehci_pci uhci_hcd ehci_hcd e1000 usbcore usb_common ata_piix libata virtio_pci virtio_ring virtio scsi_mod floppy [ 28.796016] CPU: 0 PID: 1148 Comm: ld-linux-x86-64 Not tainted 4.4.0-rc1+ #24 [ 28.796016] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014 [ 28.796016] task: ffff8800352561c0 ti: ffff88003592c000 task.ti: ffff88003592c000 [ 28.796016] RIP: 0010:[] [] putname+0x43/0x60 [ 28.796016] RSP: 0018:ffff88003592fe88 EFLAGS: 00010246 [ 28.796016] RAX: 0000000000000000 RBX: ffff8800352561c0 RCX: 0000000000000001 [ 28.796016] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88003784f000 [ 28.796016] RBP: ffff88003592ff08 R08: 0000000000000001 R09: 0000000000000000 [ 28.796016] R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000 [ 28.796016] R13: 000000000000047c R14: ffff88003784f000 R15: ffff8800358c4a00 [ 28.796016] FS: 0000000000000000(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000 [ 28.796016] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 28.796016] CR2: 00007ffd583bc2d9 CR3: 0000000035a99000 CR4: 00000000000406f0 [ 28.796016] Stack: [ 28.796016] ffffffff8121045d ffffffff812102d3 ffff8800352561c0 ffff880035a91660 [ 28.796016] ffff8800008a9880 0000000000000000 ffffffff81a49940 00ffffff81218684 [ 28.796016] ffff8800352561c0 000000000000047c 0000000000000000 ffff880035b36d80 [ 28.796016] Call Trace: [ 28.796016] [] ? do_execveat_common.isra.34+0x74d/0x930 [ 28.796016] [] ? do_execveat_common.isra.34+0x5c3/0x930 [ 28.796016] [] do_execve+0x2c/0x30 [ 28.796016] [] call_usermodehelper_exec_async+0xf0/0x140 [ 28.796016] [] ? umh_complete+0x40/0x40 [ 28.796016] [] ret_from_fork+0x3f/0x70 [ 28.796016] Code: 48 8d 47 1c 48 89 e5 53 48 8b 37 48 89 fb 48 39 c6 74 1a 48 8b 3d 7e e9 8f 00 e8 49 fa fc ff 48 89 df e8 f1 01 fd ff 5b 5d f3 c3 <0f> 0b 48 89 fe 48 8b 3d 61 e9 8f 00 e8 2c fa fc ff 5b 5d eb e9 [ 28.796016] RIP [] putname+0x43/0x60 [ 28.796016] RSP Fixes: 193125dbd8eb ("net: Introduce VRF device driver") Signed-off-by: Nikolay Aleksandrov Acked-by: David Ahern Signed-off-by: David S. Miller diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 92fa3e1..4f97484 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -907,7 +907,6 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct net_vrf *vrf = netdev_priv(dev); - int err; if (!data || !data[IFLA_VRF_TABLE]) return -EINVAL; @@ -916,15 +915,7 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev, dev->priv_flags |= IFF_L3MDEV_MASTER; - err = register_netdevice(dev); - if (err < 0) - goto out_fail; - - return 0; - -out_fail: - free_netdev(dev); - return err; + return register_netdevice(dev); } static size_t vrf_nl_getsize(const struct net_device *dev) -- cgit v0.10.2 From e4217468ae72a02e5d4f33d517a32a8c48b91c44 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 22:43:50 +0100 Subject: Revert "thermal: qcom_spmi: allow compile test" This just caused build errors: warning: (QCOM_SPMI_TEMP_ALARM) selects REGMAP_SPMI which has unmet direct dependencies (SPMI) drivers/built-in.o: In function `regmap_spmi_ext_gather_write': :(.text+0x609b0): undefined reference to `spmi_ext_register_write' :(.text+0x609f0): undefined reference to `spmi_ext_register_writel' While it's generally a good idea to allow compile testing, in this case, it just doesn't work, so reverting the patch that introduced the compile-test variant seems the most appropriate solution. Note that SPMI also has a 'depends on ARCH_QCOM || COMPILE_TEST' statement, so we should be able to enable SPMI on all architectures for compile testing already. Signed-off-by: Arnd Bergmann Fixes: cb7fb4d34202 ("thermal: qcom_spmi: allow compile test") Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index c463c89..8cc4ac6 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -382,7 +382,7 @@ endmenu config QCOM_SPMI_TEMP_ALARM tristate "Qualcomm SPMI PMIC Temperature Alarm" - depends on OF && (SPMI || COMPILE_TEST) && IIO + depends on OF && SPMI && IIO select REGMAP_SPMI help This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP) -- cgit v0.10.2 From c86b3de8c8b02d7e474fdc002c8df533b844524c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Nov 2015 17:48:52 +0100 Subject: thermal: fix thermal_zone_bind_cooling_device prototype When the prototype for thermal_zone_bind_cooling_device changed, the static inline wrapper function was left alone, which in theory can cause build warnings: I have seen this error in the past: drivers/thermal/db8500_thermal.c: In function 'db8500_cdev_bind': drivers/thermal/db8500_thermal.c:78:9: error: too many arguments to function 'thermal_zone_bind_cooling_device' ret = thermal_zone_bind_cooling_device(thermal, i, cdev, while this one no longer shows up, there is no doubt that the prototype is still wrong, so let's just fix it anyway. Signed-off-by: Arnd Bergmann Fixes: 6cd9e9f629f1 ("thermal: of: fix cooling device weights in device tree") Signed-off-by: Eduardo Valentin diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 4014a59..613c29b 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -438,7 +438,8 @@ static inline void thermal_zone_device_unregister( static inline int thermal_zone_bind_cooling_device( struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev, - unsigned long upper, unsigned long lower) + unsigned long upper, unsigned long lower, + unsigned int weight) { return -ENODEV; } static inline int thermal_zone_unbind_cooling_device( struct thermal_zone_device *tz, int trip, -- cgit v0.10.2 From a2291badc355d58ead5c19ae0609468947416040 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 19 Nov 2015 06:49:40 -0800 Subject: imx: thermal: use CPU temperature grade info for thresholds The IMX6Q/IMX6DL SoC's have a 2-bit temperature grade stored in OTP which is valid for all IMX6 SoC's (despite the fact that the IMXSDLRM and IMXSXRM do not document this - this has been proven via tests as well as verified by Freescale FAE). Instead of assuming a fixed 85C for passive cooling threshold and 105C for critical use the thermal grade for these configurations. We will set the critical to maxT - 5C and passive to maxT - 10C. Cc: Anson Huang Cc: Fabio Estevam Acked-by: Shawn Guo Acked-by: Jon Nettleton Signed-off-by: Tim Harvey ---- v3: - rebase against linux-soc-thermal.git - added ack's from Shawn and Jon v2: - remove check for IMX6Q and update comments: The OTP values have been tested on IMX6SOLO, IMX6DUALLITE, and IMX6SX and Freescale FAE has shared data with me that the OTP settings are the same and that the reference manuals will reflect this in their next updates. - set critical to max - 5C - set passive to max - 10C - display max temp in info - do not allow passive to be set above critical Signed-off-by: Eduardo Valentin diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index c8fe3ca..c5547bd 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -55,6 +55,7 @@ #define TEMPSENSE2_PANIC_VALUE_SHIFT 16 #define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000 +#define OCOTP_MEM0 0x0480 #define OCOTP_ANA1 0x04e0 /* The driver supports 1 passive trip point and 1 critical trip point */ @@ -64,12 +65,6 @@ enum imx_thermal_trip { IMX_TRIP_NUM, }; -/* - * It defines the temperature in millicelsius for passive trip point - * that will trigger cooling action when crossed. - */ -#define IMX_TEMP_PASSIVE 85000 - #define IMX_POLLING_DELAY 2000 /* millisecond */ #define IMX_PASSIVE_DELAY 1000 @@ -100,12 +95,14 @@ struct imx_thermal_data { u32 c1, c2; /* See formula in imx_get_sensor_data() */ int temp_passive; int temp_critical; + int temp_max; int alarm_temp; int last_temp; bool irq_enabled; int irq; struct clk *thermal_clk; const struct thermal_soc_data *socdata; + const char *temp_grade; }; static void imx_set_panic_temp(struct imx_thermal_data *data, @@ -285,10 +282,12 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, { struct imx_thermal_data *data = tz->devdata; + /* do not allow changing critical threshold */ if (trip == IMX_TRIP_CRITICAL) return -EPERM; - if (temp < 0 || temp > IMX_TEMP_PASSIVE) + /* do not allow passive to be set higher than critical */ + if (temp < 0 || temp > data->temp_critical) return -EINVAL; data->temp_passive = temp; @@ -404,17 +403,39 @@ static int imx_get_sensor_data(struct platform_device *pdev) data->c1 = temp64; data->c2 = n1 * data->c1 + 1000 * t1; - /* - * Set the default passive cooling trip point, - * can be changed from userspace. - */ - data->temp_passive = IMX_TEMP_PASSIVE; + /* use OTP for thermal grade */ + ret = regmap_read(map, OCOTP_MEM0, &val); + if (ret) { + dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret); + return ret; + } + + /* The maximum die temp is specified by the Temperature Grade */ + switch ((val >> 6) & 0x3) { + case 0: /* Commercial (0 to 95C) */ + data->temp_grade = "Commercial"; + data->temp_max = 95000; + break; + case 1: /* Extended Commercial (-20 to 105C) */ + data->temp_grade = "Extended Commercial"; + data->temp_max = 105000; + break; + case 2: /* Industrial (-40 to 105C) */ + data->temp_grade = "Industrial"; + data->temp_max = 105000; + break; + case 3: /* Automotive (-40 to 125C) */ + data->temp_grade = "Automotive"; + data->temp_max = 125000; + break; + } /* - * The maximum die temperature set to 20 C higher than - * IMX_TEMP_PASSIVE. + * Set the critical trip point at 5C under max + * Set the passive trip point at 10C under max (can change via sysfs) */ - data->temp_critical = 1000 * 20 + data->temp_passive; + data->temp_critical = data->temp_max - (1000 * 5); + data->temp_passive = data->temp_max - (1000 * 10); return 0; } @@ -551,6 +572,11 @@ static int imx_thermal_probe(struct platform_device *pdev) return ret; } + dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC" + " critical:%dC passive:%dC\n", data->temp_grade, + data->temp_max / 1000, data->temp_critical / 1000, + data->temp_passive / 1000); + /* Enable measurements at ~ 10 Hz */ regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ -- cgit v0.10.2 From 0ebf7f10d67a70e120f365018f1c5fce9ddc567d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 23 Nov 2015 21:11:08 -0500 Subject: fix sysvfs symlinks The thing got broken back in 2002 - sysvfs does *not* have inline symlinks; even short ones have bodies stored in the first block of file. sysv_symlink() handles that correctly; unfortunately, attempting to look an existing symlink up will end up confusing them for inline symlinks, and interpret the block number containing the body as the body itself. Nobody has noticed until now, which says something about the level of testing sysvfs gets ;-/ Cc: stable@vger.kernel.org # all of them, not that anyone cared Signed-off-by: Al Viro diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 590ad92..02fa1dc 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -162,15 +162,8 @@ void sysv_set_inode(struct inode *inode, dev_t rdev) inode->i_fop = &sysv_dir_operations; inode->i_mapping->a_ops = &sysv_aops; } else if (S_ISLNK(inode->i_mode)) { - if (inode->i_blocks) { - inode->i_op = &sysv_symlink_inode_operations; - inode->i_mapping->a_ops = &sysv_aops; - } else { - inode->i_op = &simple_symlink_inode_operations; - inode->i_link = (char *)SYSV_I(inode)->i_data; - nd_terminate_link(inode->i_link, inode->i_size, - sizeof(SYSV_I(inode)->i_data) - 1); - } + inode->i_op = &sysv_symlink_inode_operations; + inode->i_mapping->a_ops = &sysv_aops; } else init_special_inode(inode, inode->i_mode, rdev); } -- cgit v0.10.2 From c725bfce7968009756ed2836a8cd7ba4dc163011 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 23 Nov 2015 13:09:50 +0100 Subject: vfs: Make sendfile(2) killable even better Commit 296291cdd162 (mm: make sendfile(2) killable) fixed an issue where sendfile(2) was doing a lot of tiny writes into a filesystem and thus was unkillable for a long time. However sendfile(2) can be (mis)used to issue lots of writes into arbitrary file descriptor such as evenfd or similar special file descriptors which never hit the standard filesystem write path and thus are still unkillable. E.g. the following example from Dmitry burns CPU for ~16s on my test system without possibility to be killed: int r1 = eventfd(0, 0); int r2 = memfd_create("", 0); unsigned long n = 1<<30; fallocate(r2, 0, 0, n); sendfile(r1, r2, 0, n); There are actually quite a few tests for pending signals in sendfile code however we data to write is always available none of them seems to trigger. So fix the problem by adding a test for pending signal into splice_from_pipe_next() also before the loop waiting for pipe buffers to be available. This should fix all the lockup issues with sendfile of the do-ton-of-tiny-writes nature. CC: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/splice.c b/fs/splice.c index 801c21c..22adbbe 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -809,6 +809,13 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des */ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) { + /* + * Check for signal early to make process killable when there are + * always buffers available + */ + if (signal_pending(current)) + return -ERESTARTSYS; + while (!pipe->nrbufs) { if (!pipe->writers) return 0; -- cgit v0.10.2 From c2489e07c0a71a56fb2c84bc0ee66cddfca7d068 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 23 Nov 2015 13:09:51 +0100 Subject: vfs: Avoid softlockups with sendfile(2) The following test program from Dmitry can cause softlockups or RCU stalls as it copies 1GB from tmpfs into eventfd and we don't have any scheduling point at that path in sendfile(2) implementation: int r1 = eventfd(0, 0); int r2 = memfd_create("", 0); unsigned long n = 1<<30; fallocate(r2, 0, 0, n); sendfile(r1, r2, 0, n); Add cond_resched() into __splice_from_pipe() to fix the problem. CC: Dmitry Vyukov CC: stable@vger.kernel.org Signed-off-by: Jan Kara Signed-off-by: Al Viro diff --git a/fs/splice.c b/fs/splice.c index 22adbbe..4cf700d 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -891,6 +891,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_from_pipe_begin(sd); do { + cond_resched(); ret = splice_from_pipe_next(pipe, sd); if (ret > 0) ret = splice_from_pipe_feed(pipe, sd, actor); -- cgit v0.10.2 From 9494b2ce4b511e6d285afc0a5006b6cf5ea2b115 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Nov 2015 09:38:45 +0100 Subject: nfs: pass on count for CLONE operations Currently we pass uninitialized stack garbage in the count parameter. The value is usually large enought to clone whole files and thus let simple tests pass, but it makes the tests for range clones very unhappy. Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 3e92a3c..303d22e 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f, .dst_fh = NFS_FH(dst_inode), .src_offset = src_offset, .dst_offset = dst_offset, + .count = count, .dst_bitmask = server->cache_consistency_bitmask, }; struct nfs42_clone_res res = { -- cgit v0.10.2 From 3a2e176905b1a8d1b51cbfda719058f5ce893efd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Nov 2015 09:38:46 +0100 Subject: nfs: offer native ioctls even if CONFIG_COMPAT is set Without this for example 64-bit binaries on typical amd64 distributions would not be able to use ioctls on NFS. For now this only affects clones. Additionally ->compat_ioctl is defined even for non-compat builds, so get rid of the pointless ifdef. Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 4aa5719..e45f686 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -347,9 +347,6 @@ const struct file_operations nfs4_file_operations = { #endif /* CONFIG_NFS_V4_2 */ .check_flags = nfs_check_flags, .setlease = simple_nosetlease, -#ifdef CONFIG_COMPAT .unlocked_ioctl = nfs4_ioctl, -#else .compat_ioctl = nfs4_ioctl, -#endif /* CONFIG_COMPAT */ }; -- cgit v0.10.2 From 21fad313d5890b674432fe3ad0c7bcf040320340 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Nov 2015 09:38:47 +0100 Subject: nfs: allow intra-file CLONE Originally CLONE didn't allow for intra-file clones, but we recently updated the spec to support this feature which is also supported by local Linux file systems. Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index e45f686..61f1c1c 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -203,6 +203,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, struct fd src_file; struct inode *src_inode; unsigned int bs = server->clone_blksize; + bool same_inode = false; int ret; /* dst file must be opened for writing */ @@ -221,10 +222,8 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, src_inode = file_inode(src_file.file); - /* src and dst must be different files */ - ret = -EINVAL; if (src_inode == dst_inode) - goto out_fput; + same_inode = true; /* src file must be opened for reading */ if (!(src_file.file->f_mode & FMODE_READ)) @@ -249,8 +248,16 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, goto out_fput; } + /* verify if ranges are overlapped within the same file */ + if (same_inode) { + if (dst_off + count > src_off && dst_off < src_off + count) + goto out_fput; + } + /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */ - if (dst_inode < src_inode) { + if (same_inode) { + mutex_lock(&src_inode->i_mutex); + } else if (dst_inode < src_inode) { mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD); } else { @@ -275,7 +282,9 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1); out_unlock: - if (dst_inode < src_inode) { + if (same_inode) { + mutex_unlock(&src_inode->i_mutex); + } else if (dst_inode < src_inode) { mutex_unlock(&src_inode->i_mutex); mutex_unlock(&dst_inode->i_mutex); } else { -- cgit v0.10.2 From 0f42a6a9b807b092841f7e1b381f8c7e80a0d86a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Nov 2015 09:38:48 +0100 Subject: nfs: use btrfs ioctl defintions for clone The NFS CLONE_RANGE defintion was wrong and thus never worked. Fix this by simply using the btrfs ioctl defintion. Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 61f1c1c..1353530 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -7,6 +7,7 @@ #include #include #include +#include /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */ #include "delegation.h" #include "internal.h" #include "iostat.h" @@ -300,12 +301,13 @@ out_drop_write: static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) { - struct nfs_ioctl_clone_range_args args; + struct btrfs_ioctl_clone_range_args args; if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; - return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count); + return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset, + args.dest_offset, args.src_length); } #else static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, @@ -325,9 +327,9 @@ long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) void __user *argp = (void __user *)arg; switch (cmd) { - case NFS_IOC_CLONE: + case BTRFS_IOC_CLONE: return nfs42_ioctl_clone(file, arg, 0, 0, 0); - case NFS_IOC_CLONE_RANGE: + case BTRFS_IOC_CLONE_RANGE: return nfs42_ioctl_clone_range(file, argp); } diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h index 654bae3..5e62961 100644 --- a/include/uapi/linux/nfs.h +++ b/include/uapi/linux/nfs.h @@ -33,17 +33,6 @@ #define NFS_PIPE_DIRNAME "nfs" -/* NFS ioctls */ -/* Let's follow btrfs lead on CLONE to avoid messing userspace */ -#define NFS_IOC_CLONE _IOW(0x94, 9, int) -#define NFS_IOC_CLONE_RANGE _IOW(0x94, 13, int) - -struct nfs_ioctl_clone_range_args { - __s64 src_fd; - __u64 src_off, count; - __u64 dst_off; -}; - /* * NFS stats. The good thing with these values is that NFSv3 errors are * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which -- cgit v0.10.2 From 6b7153da2c1a58b0e809a8c50bcc3bab7374ce7b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 13 Nov 2015 09:38:49 +0100 Subject: nfs: reduce the amount of ifdefs for v4.2 in nfs4file.c Signed-off-by: Christoph Hellwig Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 1353530..db9b5fe 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -309,18 +309,6 @@ static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_offset, args.dest_offset, args.src_length); } -#else -static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, - u64 src_off, u64 dst_off, u64 count) -{ - return -ENOTTY; -} - -static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) -{ - return -ENOTTY; -} -#endif /* CONFIG_NFS_V4_2 */ long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -335,13 +323,9 @@ long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -ENOTTY; } +#endif /* CONFIG_NFS_V4_2 */ const struct file_operations nfs4_file_operations = { -#ifdef CONFIG_NFS_V4_2 - .llseek = nfs4_file_llseek, -#else - .llseek = nfs_file_llseek, -#endif .read_iter = nfs_file_read, .write_iter = nfs_file_write, .mmap = nfs_file_mmap, @@ -353,11 +337,14 @@ const struct file_operations nfs4_file_operations = { .flock = nfs_flock, .splice_read = nfs_file_splice_read, .splice_write = iter_file_splice_write, -#ifdef CONFIG_NFS_V4_2 - .fallocate = nfs42_fallocate, -#endif /* CONFIG_NFS_V4_2 */ .check_flags = nfs_check_flags, .setlease = simple_nosetlease, +#ifdef CONFIG_NFS_V4_2 + .llseek = nfs4_file_llseek, + .fallocate = nfs42_fallocate, .unlocked_ioctl = nfs4_ioctl, .compat_ioctl = nfs4_ioctl, +#else + .llseek = nfs_file_llseek, +#endif }; -- cgit v0.10.2 From 291e1b9459936c7e86951736d432e223b0710225 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 16 Nov 2015 14:51:07 -0500 Subject: NFS: Properly set NFS v4.2 NFSDBG_FACILITY NFS v4.2 operations can work outside of pNFS, so dprintk() output shouldn't be placed under NFSDBG_PNFS. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 303d22e..6b1ce98 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -14,7 +14,7 @@ #include "pnfs.h" #include "internal.h" -#define NFSDBG_FACILITY NFSDBG_PNFS +#define NFSDBG_FACILITY NFSDBG_PROC static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, fmode_t fmode) -- cgit v0.10.2 From f54423a1f8fb0da4226a982618d2c703e413d4d6 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 18 Nov 2015 10:39:26 +0800 Subject: NFS4: Cleanup FATTR4_WORD0_FS_LOCATIONS after decoding success Commit 1ca843a2d2 "nfs: Fix GETATTR bitmap verification" has check the bitmap after decoding success, but decode_attr_fs_locations forgets cleanup the FATTR4_WORD0_FS_LOCATIONS bits. decode_getfattr_attrs always return -EIO when meeting FS_LOCATIONS now. ls: cannot access /mnt/referal: Input/output error ls: cannot access /mnt/replicas: Input/output error total 32 drwxr-xr-x. 7 root root 8192 Nov 16 20:36 pnfs ??????????? ? ? ? ? ? referal ??????????? ? ? ? ? ? replicas v2: clear the bit earlier Signed-off-by: Andreas Gruenbacher Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index dfed4f5..4e44412 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3615,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st status = 0; if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) goto out; + bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS; status = -EIO; /* Ignore borken servers that return unrequested attrs */ if (unlikely(res == NULL)) -- cgit v0.10.2 From 91ab4b4d16e6649fbbf65f303c0c4e20ed680bd1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 19 Nov 2015 14:30:26 -0500 Subject: nfs: use sliding delay when LAYOUTGET gets NFS4ERR_DELAY When LAYOUTGET gets NFS4ERR_DELAY, we currently will wait 15s before retrying the call. That is a _very_ long time, so add a timeout value to struct nfs4_layoutget and pass nfs4_async_handle_error a pointer to it. This allows the RPC engine to use a sliding delay window, instead of a 15s delay. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 765a035..8981803 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7866,7 +7866,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) spin_unlock(&inode->i_lock); goto out_restart; } - if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) + if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN) goto out_restart; out: dprintk("<-- %s\n", __func__); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 570d630..11bbae4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -251,6 +251,7 @@ struct nfs4_layoutget { struct nfs4_layoutget_res res; struct rpc_cred *cred; gfp_t gfp_flags; + long timeout; }; struct nfs4_getdeviceinfo_args { -- cgit v0.10.2 From c68a027c05709330fe5b2f50c50d5fa02124b5d8 Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Fri, 20 Nov 2015 09:56:20 -0500 Subject: nfs4: start callback_ident at idr 1 If clp->cl_cb_ident is zero, then nfs_cb_idr_remove_locked() skips removing it when the nfs_client is freed. A decoding or server bug can then find and try to put that first nfs_client which would lead to a crash. Signed-off-by: Benjamin Coddington Fixes: d6870312659d ("nfs4client: convert to idr_alloc()") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 223bedd..10410e8 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) return ret; idr_preload(GFP_KERNEL); spin_lock(&nn->nfs_client_lock); - ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); + ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT); if (ret >= 0) clp->cl_cb_ident = ret; spin_unlock(&nn->nfs_client_lock); -- cgit v0.10.2 From 38b7631fbe42e6e247e9fc9879f961b14a687e3b Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Fri, 20 Nov 2015 09:55:30 -0500 Subject: nfs4: limit callback decoding to received bytes A truncated cb_compound request will cause the client to decode null or data from a previous callback for nfs4.1 backchannel case, or uninitialized data for the nfs4.0 case. This is because the path through svc_process_common() advances the request's iov_base and decrements iov_len without adjusting the overall xdr_buf's len field. That causes xdr_init_decode() to set up the xdr_stream with an incorrect length in nfs4_callback_compound(). Fixing this for the nfs4.1 backchannel case first requires setting the correct iov_len and page_len based on the length of received data in the same manner as the nfs4.0 case. Then the request's xdr_buf length can be adjusted for both cases based upon the remaining iov_len and page_len. Signed-off-by: Benjamin Coddington Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 646cdac..beac58b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -78,7 +78,8 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes) p = xdr_inline_decode(xdr, nbytes); if (unlikely(p == NULL)) - printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n"); + printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed " + "or truncated request.\n"); return p; } @@ -889,6 +890,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r struct cb_compound_hdr_arg hdr_arg = { 0 }; struct cb_compound_hdr_res hdr_res = { NULL }; struct xdr_stream xdr_in, xdr_out; + struct xdr_buf *rq_arg = &rqstp->rq_arg; __be32 *p, status; struct cb_process_state cps = { .drc_status = 0, @@ -900,7 +902,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r dprintk("%s: start\n", __func__); - xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); + rq_arg->len = rq_arg->head[0].iov_len + rq_arg->page_len; + xdr_init_decode(&xdr_in, rq_arg, rq_arg->head[0].iov_base); p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); xdr_init_encode(&xdr_out, &rqstp->rq_res, p); diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 229956b..95f82d8 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -353,12 +353,20 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) { struct rpc_xprt *xprt = req->rq_xprt; struct svc_serv *bc_serv = xprt->bc_serv; + struct xdr_buf *rq_rcv_buf = &req->rq_rcv_buf; spin_lock(&xprt->bc_pa_lock); list_del(&req->rq_bc_pa_list); xprt_dec_alloc_count(xprt, 1); spin_unlock(&xprt->bc_pa_lock); + if (copied <= rq_rcv_buf->head[0].iov_len) { + rq_rcv_buf->head[0].iov_len = copied; + rq_rcv_buf->page_len = 0; + } else { + rq_rcv_buf->page_len = copied - rq_rcv_buf->head[0].iov_len; + } + req->rq_private_buf.len = copied; set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index bc5b7b5..7fccf96 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1363,6 +1363,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); + rqstp->rq_arg.len = req->rq_private_buf.len; /* reset result send buffer "put" position */ resv->iov_len = 0; -- cgit v0.10.2 From 578270bfbd2803dc7b0b03fbc2ac119efbc73195 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 24 Nov 2015 10:35:29 +0800 Subject: block: fix segment split Inside blk_bio_segment_split(), previous bvec pointer(bvprvp) always points to the iterator local variable, which is obviously wrong, so fix it by pointing to the local variable of 'bvprv'. Fixes: 5014c311baa2b(block: fix bogus compiler warnings in blk-merge.c) Cc: stable@kernel.org #4.3 Reported-by: Michael Ellerman Reported-by: Mark Salter Tested-by: Laurent Dufour Tested-by: Mark Salter Signed-off-by: Ming Lei Signed-off-by: Jens Axboe diff --git a/block/blk-merge.c b/block/blk-merge.c index de5716d8..f2efe8a 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -98,7 +98,7 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, seg_size += bv.bv_len; bvprv = bv; - bvprvp = &bv; + bvprvp = &bvprv; sectors += bv.bv_len >> 9; continue; } @@ -108,7 +108,7 @@ new_segment: nsegs++; bvprv = bv; - bvprvp = &bv; + bvprvp = &bvprv; seg_size = bv.bv_len; sectors += bv.bv_len >> 9; } -- cgit v0.10.2 From 02e707424c2eadbcda68cd38876c9f4434ca8e1a Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 24 Nov 2015 10:35:30 +0800 Subject: blk-merge: fix blk_bio_segment_split Commit bdced438acd83a(block: setup bi_phys_segments after splitting) introduces function of computing bio->bi_phys_segments during bio splitting. Unfortunately both bio->bi_seg_front_size and bio->bi_seg_back_size arn't computed, so too many physical segments may be obtained for one request since both the two are used to check if one segment across two bios can be possible. This patch fixes the issue by computing the two variables in blk_bio_segment_split(). Fixes: bdced438acd83a(block: setup bi_phys_segments after splitting) Reported-by: Michael Ellerman Reported-by: Mark Salter Tested-by: Laurent Dufour Tested-by: Mark Salter Signed-off-by: Ming Lei Signed-off-by: Jens Axboe diff --git a/block/blk-merge.c b/block/blk-merge.c index f2efe8a..50793cd 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -76,6 +76,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, struct bio_vec bv, bvprv, *bvprvp = NULL; struct bvec_iter iter; unsigned seg_size = 0, nsegs = 0, sectors = 0; + unsigned front_seg_size = bio->bi_seg_front_size; + bool do_split = true; + struct bio *new = NULL; bio_for_each_segment(bv, bio, iter) { if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q)) @@ -111,13 +114,26 @@ new_segment: bvprvp = &bvprv; seg_size = bv.bv_len; sectors += bv.bv_len >> 9; + + if (nsegs == 1 && seg_size > front_seg_size) + front_seg_size = seg_size; } - *segs = nsegs; - return NULL; + do_split = false; split: *segs = nsegs; - return bio_split(bio, sectors, GFP_NOIO, bs); + + if (do_split) { + new = bio_split(bio, sectors, GFP_NOIO, bs); + if (new) + bio = new; + } + + bio->bi_seg_front_size = front_seg_size; + if (seg_size > bio->bi_seg_back_size) + bio->bi_seg_back_size = seg_size; + + return do_split ? new : NULL; } void blk_queue_split(struct request_queue *q, struct bio **bio, -- cgit v0.10.2 From 12e57f59ca3344a588531f68eeede45666e8a6e0 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 24 Nov 2015 10:35:31 +0800 Subject: blk-merge: warn if figured out segment number is bigger than nr_phys_segments We had seen lots of reports of this kind issue, so add one warnning in blk-merge, then it can be triggered easily and avoid to depend on warning/bug from drivers. Signed-off-by: Ming Lei Signed-off-by: Jens Axboe diff --git a/block/blk-merge.c b/block/blk-merge.c index 50793cd..41a55ba 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -428,6 +428,12 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, if (sg) sg_mark_end(sg); + /* + * Something must have been wrong if the figured number of + * segment is bigger than number of req's physical segments + */ + WARN_ON(nsegs > rq->nr_phys_segments); + return nsegs; } EXPORT_SYMBOL(blk_rq_map_sg); -- cgit v0.10.2 From 3c25a860d17b7378822f35d8c9141db9507e3beb Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 22 Nov 2015 01:08:54 +0200 Subject: broadcom: fix PHY_ID_BCM5481 entry in the id table Commit fcb26ec5b18d ("broadcom: move all PHY_ID's to header") updated broadcom_tbl to use PHY_IDs, but incorrectly replaced 0x0143bca0 with PHY_ID_BCM5482 (making a duplicate entry, and completely omitting the original). Fix that. Fixes: fcb26ec5b18d ("broadcom: move all PHY_ID's to header") Signed-off-by: Aaro Koskinen Signed-off-by: David S. Miller diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 07a6119..3ce5d95 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -614,7 +614,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = { { PHY_ID_BCM5461, 0xfffffff0 }, { PHY_ID_BCM54616S, 0xfffffff0 }, { PHY_ID_BCM5464, 0xfffffff0 }, - { PHY_ID_BCM5482, 0xfffffff0 }, + { PHY_ID_BCM5481, 0xfffffff0 }, { PHY_ID_BCM5482, 0xfffffff0 }, { PHY_ID_BCM50610, 0xfffffff0 }, { PHY_ID_BCM50610M, 0xfffffff0 }, -- cgit v0.10.2 From f4195d1eac954a67adf112dd53404560cc55b942 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Sun, 22 Nov 2015 15:46:05 +0800 Subject: tipc: avoid packets leaking on socket receive queue Even if we drain receive queue thoroughly in tipc_release() after tipc socket is removed from rhashtable, it is possible that some packets are in flight because some CPU runs receiver and did rhashtable lookup before we removed socket. They will achieve receive queue, but nobody delete them at all. To avoid this leak, we register a private socket destructor to purge receive queue, meaning releasing packets pending on receive queue will be delayed until the last reference of tipc socket will be released. Signed-off-by: Ying Xue Signed-off-by: David S. Miller diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 552dbab..b53246f 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -105,6 +105,7 @@ struct tipc_sock { static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); static void tipc_data_ready(struct sock *sk); static void tipc_write_space(struct sock *sk); +static void tipc_sock_destruct(struct sock *sk); static int tipc_release(struct socket *sock); static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p); @@ -381,6 +382,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, sk->sk_rcvbuf = sysctl_tipc_rmem[1]; sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; + sk->sk_destruct = tipc_sock_destruct; tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; tsk->sent_unacked = 0; atomic_set(&tsk->dupl_rcvcnt, 0); @@ -470,9 +472,6 @@ static int tipc_release(struct socket *sock) tipc_node_remove_conn(net, dnode, tsk->portid); } - /* Discard any remaining (connection-based) messages in receive queue */ - __skb_queue_purge(&sk->sk_receive_queue); - /* Reject any messages that accumulated in backlog queue */ sock->state = SS_DISCONNECTING; release_sock(sk); @@ -1515,6 +1514,11 @@ static void tipc_data_ready(struct sock *sk) rcu_read_unlock(); } +static void tipc_sock_destruct(struct sock *sk) +{ + __skb_queue_purge(&sk->sk_receive_queue); +} + /** * filter_connect - Handle all incoming messages for a connection-based socket * @tsk: TIPC socket -- cgit v0.10.2 From 8c69729b4439bbda88c3073df7243f755cc418ed Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 24 Nov 2015 11:08:18 +0800 Subject: ALSA: hda - Fix headphone noise after Dell XPS 13 resume back from S3 We have a machine Dell XPS 13 with the codec alc256, after resume back from S3, the headphone has noise when play sound. Through comparing with the coeff vaule before and after S3, we found restoring a coeff register will help remove noise. BugLink: https://bugs.launchpad.net/bugs/1519168 Cc: Kailang Yang Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 53f6a02..e4f80dc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4587,6 +4587,7 @@ enum { ALC292_FIXUP_DISABLE_AAMIX, ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC275_FIXUP_DELL_XPS, + ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, }; static const struct hda_fixup alc269_fixups[] = { @@ -5167,6 +5168,17 @@ static const struct hda_fixup alc269_fixups[] = { {} } }, + [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* Disable pass-through path for FRONT 14h */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x36}, + {0x20, AC_VERB_SET_PROC_COEF, 0x1737}, + {} + }, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5206,6 +5218,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC292_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), -- cgit v0.10.2 From f10750536fa783cafb2653f6fa349d6e62337e42 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 12 Nov 2015 12:59:00 -0800 Subject: x86/entry/64: Fix irqflag tracing wrt context tracking Paolo pointed out that enter_from_user_mode could be called while irqflags were traced as though IRQs were on. In principle, this could confuse lockdep. It doesn't cause any problems that I've seen in any configuration, but if I build with CONFIG_DEBUG_LOCKDEP=y, enable a nohz_full CPU, and add code like: if (irqs_disabled()) { spin_lock(&something); spin_unlock(&something); } to the top of enter_from_user_mode, then lockdep will complain without this fix. It seems that lockdep's irqflags sanity checks are too weak to detect this bug without forcing the issue. This patch adds one byte to normal kernels, and it's IMO a bit ugly. I haven't spotted a better way to do this yet, though. The issue is that we can't do TRACE_IRQS_OFF until after SWAPGS (if needed), but we're also supposed to do it before calling C code. An alternative approach would be to call trace_hardirqs_off in enter_from_user_mode. That would be less code and would not bloat normal kernels at all, but it would be harder to see how the code worked. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Frederic Weisbecker Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/86237e362390dfa6fec12de4d75a238acb0ae787.1447361906.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 53616ca..a55697d 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -509,6 +509,17 @@ END(irq_entries_start) * tracking that we're in kernel mode. */ SWAPGS + + /* + * We need to tell lockdep that IRQs are off. We can't do this until + * we fix gsbase, and we should do it before enter_from_user_mode + * (which can take locks). Since TRACE_IRQS_OFF idempotent, + * the simplest way to handle it is to just call it twice if + * we enter from user mode. There's no reason to optimize this since + * TRACE_IRQS_OFF is a no-op if lockdep is off. + */ + TRACE_IRQS_OFF + #ifdef CONFIG_CONTEXT_TRACKING call enter_from_user_mode #endif @@ -1049,12 +1060,18 @@ ENTRY(error_entry) SWAPGS .Lerror_entry_from_usermode_after_swapgs: + /* + * We need to tell lockdep that IRQs are off. We can't do this until + * we fix gsbase, and we should do it before enter_from_user_mode + * (which can take locks). + */ + TRACE_IRQS_OFF #ifdef CONFIG_CONTEXT_TRACKING call enter_from_user_mode #endif + ret .Lerror_entry_done: - TRACE_IRQS_OFF ret -- cgit v0.10.2 From df976f5d95028e26b4c967b24518fe340f8a726d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 3 Nov 2015 23:09:58 -0500 Subject: clk: ti: clkt_dpll: fix wrong do_div() usage do_div() is meant to be used with an unsigned dividend. Signed-off-by: Nicolas Pitre Signed-off-by: Tero Kristo diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c index 9023ca9..b5cc6f6 100644 --- a/drivers/clk/ti/clkt_dpll.c +++ b/drivers/clk/ti/clkt_dpll.c @@ -240,7 +240,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw) */ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) { - long long dpll_clk; + u64 dpll_clk; u32 dpll_mult, dpll_div, v; struct dpll_data *dd; @@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) dpll_div = v & dd->div1_mask; dpll_div >>= __ffs(dd->div1_mask); - dpll_clk = (long long)clk_get_rate(dd->clk_ref) * dpll_mult; + dpll_clk = (u64)clk_get_rate(dd->clk_ref) * dpll_mult; do_div(dpll_clk, dpll_div + 1); return dpll_clk; -- cgit v0.10.2 From c51185b45c43737faca4574d790489a1bd8cfd11 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 3 Nov 2015 23:17:11 -0500 Subject: clk: ti: fapll: fix wrong do_div() usage do_div() is meant to be used with an unsigned dividend. Signed-off-by: Nicolas Pitre Signed-off-by: Tero Kristo diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index f4b2e98..66a0d0e 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -168,7 +168,7 @@ static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw, { struct fapll_data *fd = to_fapll(hw); u32 fapll_n, fapll_p, v; - long long rate; + u64 rate; if (ti_fapll_clock_is_bypass(fd)) return parent_rate; @@ -314,7 +314,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw, { struct fapll_synth *synth = to_synth(hw); u32 synth_div_m; - long long rate; + u64 rate; /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */ if (!synth->div) -- cgit v0.10.2 From 3a5b1dc4a3237870cfb53d31bc4cbc2a9c7aa16e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 13 Nov 2015 17:29:58 +0100 Subject: clk: ti816x: Add missing dmtimer clkdev entries Add missing clkdev dmtimer related entries for dm816x. 32Khz and ext sources were missing. Signed-off-by: Neil Armstrong Cc: Brian Hutchinson Acked-by: Tony Lindgren Signed-off-by: Tero Kristo diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 1dfad0c..2a5d84f 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -20,6 +20,8 @@ static struct ti_dt_clk dm816x_clks[] = { DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "timer_32k_ck", "sysclk18_ck"), + DT_CLK(NULL, "timer_ext_ck", "tclkin_ck"), DT_CLK(NULL, "mpu_ck", "mpu_ck"), DT_CLK(NULL, "timer1_fck", "timer1_fck"), DT_CLK(NULL, "timer2_fck", "timer2_fck"), -- cgit v0.10.2 From 167af5ef2cdba14ff14a13c91e5532ed479083d8 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 1 Oct 2015 14:20:37 -0500 Subject: clk: ti: drop locking code from mux/divider drivers TI's mux and divider clock drivers do not require locking and they do not initialize internal spinlocks. This code was occasionally copy-posted from generic mux/divider drivers. So remove it. Signed-off-by: Grygorii Strashko Cc: Tony Lindgren Cc: Sekhar Nori Signed-off-by: Tero Kristo diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 5b17268..df25583 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -214,7 +214,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_divider *divider; unsigned int div, value; - unsigned long flags = 0; u32 val; if (!hw || !rate) @@ -228,9 +227,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (value > div_mask(divider)) value = div_mask(divider); - if (divider->lock) - spin_lock_irqsave(divider->lock, flags); - if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = div_mask(divider) << (divider->shift + 16); } else { @@ -240,9 +236,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, val |= value << divider->shift; ti_clk_ll_ops->clk_writel(val, divider->reg); - if (divider->lock) - spin_unlock_irqrestore(divider->lock, flags); - return 0; } @@ -256,8 +249,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, - const struct clk_div_table *table, - spinlock_t *lock) + const struct clk_div_table *table) { struct clk_divider *div; struct clk *clk; @@ -288,7 +280,6 @@ static struct clk *_register_divider(struct device *dev, const char *name, div->shift = shift; div->width = width; div->flags = clk_divider_flags; - div->lock = lock; div->hw.init = &init; div->table = table; @@ -421,7 +412,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup) clk = _register_divider(NULL, setup->name, div->parent, flags, (void __iomem *)reg, div->bit_shift, - width, div_flags, table, NULL); + width, div_flags, table); if (IS_ERR(clk)) kfree(table); @@ -584,8 +575,7 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) goto cleanup; clk = _register_divider(NULL, node->name, parent_name, flags, reg, - shift, width, clk_divider_flags, table, - NULL); + shift, width, clk_divider_flags, table); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 69f08a1..dab9ba8 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -69,7 +69,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) { struct clk_mux *mux = to_clk_mux(hw); u32 val; - unsigned long flags = 0; if (mux->table) { index = mux->table[index]; @@ -81,9 +80,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) index++; } - if (mux->lock) - spin_lock_irqsave(mux->lock, flags); - if (mux->flags & CLK_MUX_HIWORD_MASK) { val = mux->mask << (mux->shift + 16); } else { @@ -93,9 +89,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) val |= index << mux->shift; ti_clk_ll_ops->clk_writel(val, mux->reg); - if (mux->lock) - spin_unlock_irqrestore(mux->lock, flags); - return 0; } @@ -109,7 +102,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u32 mask, u8 clk_mux_flags, - u32 *table, spinlock_t *lock) + u32 *table) { struct clk_mux *mux; struct clk *clk; @@ -133,7 +126,6 @@ static struct clk *_register_mux(struct device *dev, const char *name, mux->shift = shift; mux->mask = mask; mux->flags = clk_mux_flags; - mux->lock = lock; mux->table = table; mux->hw.init = &init; @@ -175,7 +167,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup) return _register_mux(NULL, setup->name, mux->parents, mux->num_parents, flags, (void __iomem *)reg, mux->bit_shift, mask, - mux_flags, NULL, NULL); + mux_flags, NULL); } /** @@ -227,8 +219,7 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 << fls(mask)) - 1; clk = _register_mux(NULL, node->name, parent_names, num_parents, - flags, reg, shift, mask, clk_mux_flags, NULL, - NULL); + flags, reg, shift, mask, clk_mux_flags, NULL); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); -- cgit v0.10.2 From 897ed0ca5979f103b8de3c09bcca2ae4860eb5a5 Mon Sep 17 00:00:00 2001 From: Cory Tusar Date: Wed, 18 Nov 2015 22:54:39 -0500 Subject: ARM: dts: vfxxx: Fix dspi[01] spi-num-chipselects. Per the Vybrid Reference Manual (section 3.8.6.1), dspi0 has 6 chip select signals associated with it, while dspi1 has only 4. Signed-off-by: Cory Tusar Acked-by: Stefan Agner Cc: Signed-off-by: Shawn Guo diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index a64bfe1..0d5acc2 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -158,7 +158,7 @@ interrupts = <67 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_DSPI0>; clock-names = "dspi"; - spi-num-chipselects = <5>; + spi-num-chipselects = <6>; status = "disabled"; }; @@ -170,7 +170,7 @@ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks VF610_CLK_DSPI1>; clock-names = "dspi"; - spi-num-chipselects = <5>; + spi-num-chipselects = <4>; status = "disabled"; }; -- cgit v0.10.2 From 9832e8110256f3e4301d97c0c6559e5b63825751 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 13 Nov 2015 18:10:04 +0100 Subject: drm/imx: parallel-display: allow to determine bus format from the connected panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to commit 5e501ed7253b3 ("drm/imx: imx-ldb: allow to determine bus format from the connected panel"), if a panel is connected to the ldb output port via the of_graph bindings, the data mapping is determined from the display_info.bus_format field provided by the panel instead of from the optional interface_pix_fmt device tree property. Reported-by: Ulrich Ölmann Signed-off-by: Philipp Zabel Tested-by: Gary Bisson diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index b4deb9c..2e9b9f1 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) if (imxpd->panel && imxpd->panel->funcs && imxpd->panel->funcs->get_modes) { + struct drm_display_info *di = &connector->display_info; + num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); + if (!imxpd->bus_format && di->num_bus_formats) + imxpd->bus_format = di->bus_formats[0]; if (num_modes > 0) return num_modes; } -- cgit v0.10.2 From c3ede03c881ca8ad618ad52c82b44ecb72c6e408 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 9 Nov 2015 16:43:09 +0100 Subject: gpu: ipu-v3: drop unused dmfc field from client platform data This field is never used, drop it. Signed-off-by: Philipp Zabel diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 85dedca..eeba753 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -343,7 +343,6 @@ struct ipu_client_platformdata { int di; int dc; int dp; - int dmfc; int dma[2]; }; -- cgit v0.10.2 From 99ae78c37391ec308250e32dd64ad875f799808a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 12:47:38 +0200 Subject: gpu: ipu-v3: Remove reg_offset field This is not used, so remove it. Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index ba47b30..97a36e3 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -993,7 +993,6 @@ static void platform_device_unregister_children(struct platform_device *pdev) struct ipu_platform_reg { struct ipu_client_platformdata pdata; const char *name; - int reg_offset; }; static const struct ipu_platform_reg client_reg[] = { @@ -1021,7 +1020,6 @@ static const struct ipu_platform_reg client_reg[] = { .dma[0] = IPUV3_CHANNEL_CSI0, .dma[1] = -EINVAL, }, - .reg_offset = IPU_CM_CSI0_REG_OFS, .name = "imx-ipuv3-camera", }, { .pdata = { @@ -1029,7 +1027,6 @@ static const struct ipu_platform_reg client_reg[] = { .dma[0] = IPUV3_CHANNEL_CSI1, .dma[1] = -EINVAL, }, - .reg_offset = IPU_CM_CSI1_REG_OFS, .name = "imx-ipuv3-camera", }, }; @@ -1051,19 +1048,9 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) for (i = 0; i < ARRAY_SIZE(client_reg); i++) { const struct ipu_platform_reg *reg = &client_reg[i]; struct platform_device *pdev; - struct resource res; - - if (reg->reg_offset) { - memset(&res, 0, sizeof(res)); - res.flags = IORESOURCE_MEM; - res.start = ipu_base + ipu->devtype->cm_ofs + reg->reg_offset; - res.end = res.start + PAGE_SIZE - 1; - pdev = platform_device_register_resndata(dev, reg->name, - id++, &res, 1, ®->pdata, sizeof(reg->pdata)); - } else { - pdev = platform_device_register_data(dev, reg->name, - id++, ®->pdata, sizeof(reg->pdata)); - } + + pdev = platform_device_register_data(dev, reg->name, + id++, ®->pdata, sizeof(reg->pdata)); if (IS_ERR(pdev)) { ret = PTR_ERR(pdev); -- cgit v0.10.2 From 304e6be652e2ef2190adf9c23a2a1e5f9f39800d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 9 Nov 2015 16:35:12 +0100 Subject: gpu: ipu-v3: Assign of_node of child platform devices to corresponding ports The crtc child device driver shouldn't have to modify the of_node of its platform device in the probe function. Instead, let the IPU core driver set the of_node when the platform device is created. Also reorder the client_reg array so the elements are in port id order (CSIs first, then DIs). Suggested-by: Russell King Signed-off-by: Philipp Zabel Acked-by: Russell King diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 97a36e3..f2e13eb 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -995,9 +996,24 @@ struct ipu_platform_reg { const char *name; }; +/* These must be in the order of the corresponding device tree port nodes */ static const struct ipu_platform_reg client_reg[] = { { .pdata = { + .csi = 0, + .dma[0] = IPUV3_CHANNEL_CSI0, + .dma[1] = -EINVAL, + }, + .name = "imx-ipuv3-camera", + }, { + .pdata = { + .csi = 1, + .dma[0] = IPUV3_CHANNEL_CSI1, + .dma[1] = -EINVAL, + }, + .name = "imx-ipuv3-camera", + }, { + .pdata = { .di = 0, .dc = 5, .dp = IPU_DP_FLOW_SYNC_BG, @@ -1014,20 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = { .dma[1] = -EINVAL, }, .name = "imx-ipuv3-crtc", - }, { - .pdata = { - .csi = 0, - .dma[0] = IPUV3_CHANNEL_CSI0, - .dma[1] = -EINVAL, - }, - .name = "imx-ipuv3-camera", - }, { - .pdata = { - .csi = 1, - .dma[0] = IPUV3_CHANNEL_CSI1, - .dma[1] = -EINVAL, - }, - .name = "imx-ipuv3-camera", }, }; @@ -1049,11 +1051,29 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) const struct ipu_platform_reg *reg = &client_reg[i]; struct platform_device *pdev; - pdev = platform_device_register_data(dev, reg->name, - id++, ®->pdata, sizeof(reg->pdata)); + pdev = platform_device_alloc(reg->name, id++); + if (!pdev) { + ret = -ENOMEM; + goto err_register; + } + + pdev->dev.parent = dev; + + /* Associate subdevice with the corresponding port node */ + pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i); + if (!pdev->dev.of_node) { + dev_err(dev, "missing port@%d node in %s\n", i, + dev->of_node->full_name); + ret = -ENODEV; + goto err_register; + } - if (IS_ERR(pdev)) { - ret = PTR_ERR(pdev); + ret = platform_device_add_data(pdev, ®->pdata, + sizeof(reg->pdata)); + if (!ret) + ret = platform_device_add(pdev); + if (ret) { + platform_device_put(pdev); goto err_register; } } -- cgit v0.10.2 From 407c9eba789767feb68b42eb2d65db68584e06c0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 9 Nov 2015 16:35:12 +0100 Subject: drm/imx: Remove of_node assignment from ipuv3-crtc driver probe The crtc child device driver shouldn't modify the of_node of its platform device in the probe function. Instead, since the previous patch, the IPU core driver sets the of_node when the platform device is created. Drop the now unused custom imx_drm_get_port_by_id function. Suggested-by: Russell King Signed-off-by: Philipp Zabel Acked-by: Russell King diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 4cbc3df..67813ca 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -411,28 +411,6 @@ err_put_resources: return ret; } -static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent, - int port_id) -{ - struct device_node *port; - int id, ret; - - port = of_get_child_by_name(parent, "port"); - while (port) { - ret = of_property_read_u32(port, "reg", &id); - if (!ret && id == port_id) - return port; - - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (of_node_cmp(port->name, "port")); - } - - return NULL; -} - static int ipu_drm_bind(struct device *dev, struct device *master, void *data) { struct ipu_client_platformdata *pdata = dev->platform_data; @@ -474,23 +452,11 @@ static const struct component_ops ipu_crtc_ops = { static int ipu_drm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ipu_client_platformdata *pdata = dev->platform_data; int ret; if (!dev->platform_data) return -EINVAL; - if (!dev->of_node) { - /* Associate crtc device with the corresponding DI port node */ - dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node, - pdata->di + 2); - if (!dev->of_node) { - dev_err(dev, "missing port@%d node in %s\n", - pdata->di + 2, dev->parent->of_node->full_name); - return -ENODEV; - } - } - ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); if (ret) return ret; -- cgit v0.10.2 From 3f3a7280d4cafd28036378198280640dfc6492aa Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 5 Jul 2015 22:45:23 +0200 Subject: GPU-DRM-IMX: Delete an unnecessary check before drm_fbdev_cma_restore_mode() The drm_fbdev_cma_restore_mode() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 7b00ab8..7b990b4 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm) #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; - if (imxdrm->fbhelper) - drm_fbdev_cma_restore_mode(imxdrm->fbhelper); + drm_fbdev_cma_restore_mode(imxdrm->fbhelper); #endif } -- cgit v0.10.2 From b81f472a208d3e2b4392faa6d17037a89442f4ce Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Mon, 23 Nov 2015 10:35:36 -0500 Subject: ring-buffer: Update read stamp with first real commit on page Do not update the read stamp after swapping out the reader page from the write buffer. If the reader page is swapped out of the buffer before an event is written to it, then the read_stamp may get an out of date timestamp, as the page timestamp is updated on the first commit to that page. rb_get_reader_page() only returns a page if it has an event on it, otherwise it will return NULL. At that point, check if the page being returned has events and has not been read yet. Then at that point update the read_stamp to match the time stamp of the reader page. Cc: stable@vger.kernel.org # 2.6.30+ Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 75f1d05..4dd6d5b 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1887,12 +1887,6 @@ rb_event_index(struct ring_buffer_event *event) return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE; } -static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) -{ - cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp; - cpu_buffer->reader_page->read = 0; -} - static void rb_inc_iter(struct ring_buffer_iter *iter) { struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; @@ -3626,7 +3620,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) /* Finally update the reader page to the new head */ cpu_buffer->reader_page = reader; - rb_reset_reader_page(cpu_buffer); + cpu_buffer->reader_page->read = 0; if (overwrite != cpu_buffer->last_overrun) { cpu_buffer->lost_events = overwrite - cpu_buffer->last_overrun; @@ -3636,6 +3630,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) goto again; out: + /* Update the read_stamp on the first event */ + if (reader && reader->read == 0) + cpu_buffer->read_stamp = reader->page->time_stamp; + arch_spin_unlock(&cpu_buffer->lock); local_irq_restore(flags); -- cgit v0.10.2 From bd1b7cd360f529394936f28746eb4aaa12d6770a Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Mon, 23 Nov 2015 17:35:24 -0500 Subject: ring-buffer: Put back the length if crossed page with add_timestamp Commit fcc742eaad7c "ring-buffer: Add event descriptor to simplify passing data" added a descriptor that holds various data instead of passing around several variables through parameters. The problem was that one of the parameters was modified in a function and the code was designed not to have an effect on that modified parameter. Now that the parameter is a descriptor and any modifications to it are non-volatile, the size of the data could be unnecessarily expanded. Remove the extra space added if a timestamp was added and the event went across the page. Cc: stable@vger.kernel.org # 4.3+ Fixes: fcc742eaad7c "ring-buffer: Add event descriptor to simplify passing data" Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 4dd6d5b..9c6045a 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2797,8 +2797,11 @@ rb_reserve_next_event(struct ring_buffer *buffer, event = __rb_reserve_next(cpu_buffer, &info); - if (unlikely(PTR_ERR(event) == -EAGAIN)) + if (unlikely(PTR_ERR(event) == -EAGAIN)) { + if (info.add_timestamp) + info.length -= RB_LEN_TIME_EXTEND; goto again; + } if (!event) goto out_fail; -- cgit v0.10.2 From 7098356baca723513e97ca0020df4e18bc353be3 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 24 Nov 2015 13:57:57 +0800 Subject: tipc: fix error handling of expanding buffer headroom Coverity says: *** CID 1338065: Error handling issues (CHECKED_RETURN) /net/tipc/udp_media.c: 162 in tipc_udp_send_msg() 156 struct udp_media_addr *dst = (struct udp_media_addr *)&dest->value; 157 struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; 158 struct sk_buff *clone; 159 struct rtable *rt; 160 161 if (skb_headroom(skb) < UDP_MIN_HEADROOM) >>> CID 1338065: Error handling issues (CHECKED_RETURN) >>> Calling "pskb_expand_head" without checking return value (as is done elsewhere 51 out of 56 times). 162 pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); 163 164 clone = skb_clone(skb, GFP_ATOMIC); 165 skb_set_inner_protocol(clone, htons(ETH_P_TIPC)); 166 ub = rcu_dereference_rtnl(b->media_ptr); 167 if (!ub) { When expanding buffer headroom over udp tunnel with pskb_expand_head(), it's unfortunate that we don't check its return value. As a result, if the function returns an error code due to the lack of memory, it may cause unpredictable consequence as we unconditionally consider that it's always successful. Fixes: e53567948f82 ("tipc: conditionally expand buffer headroom over udp tunnel") Reported-by: Cc: Stephen Hemminger Signed-off-by: Ying Xue Signed-off-by: David S. Miller diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index ad2719a..70c0327 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -158,8 +158,11 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; struct rtable *rt; - if (skb_headroom(skb) < UDP_MIN_HEADROOM) - pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); + if (skb_headroom(skb) < UDP_MIN_HEADROOM) { + err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); + if (err) + goto tx_error; + } skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); ub = rcu_dereference_rtnl(b->media_ptr); -- cgit v0.10.2 From e6fab54423450d699a09ec2b899473a541f61971 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 10 Nov 2015 15:11:20 +0100 Subject: ARM/arm64: KVM: test properly for a PTE's uncachedness The open coded tests for checking whether a PTE maps a page as uncached use a flawed '(pte_val(xxx) & CONST) != CONST' pattern, which is not guaranteed to work since the type of a mapping is not a set of mutually exclusive bits For HYP mappings, the type is an index into the MAIR table (i.e, the index itself does not contain any information whatsoever about the type of the mapping), and for stage-2 mappings it is a bit field where normal memory and device types are defined as follows: #define MT_S2_NORMAL 0xf #define MT_S2_DEVICE_nGnRE 0x1 I.e., masking *and* comparing with the latter matches on the former, and we have been getting lucky merely because the S2 device mappings also have the PTE_UXN bit set, or we would misidentify memory mappings as device mappings. Since the unmap_range() code path (which contains one instance of the flawed test) is used both for HYP mappings and stage-2 mappings, and considering the difference between the two, it is non-trivial to fix this by rewriting the tests in place, as it would involve passing down the type of mapping through all the functions. However, since HYP mappings and stage-2 mappings both deal with host physical addresses, we can simply check whether the mapping is backed by memory that is managed by the host kernel, and only perform the D-cache maintenance if this is the case. Cc: stable@vger.kernel.org Signed-off-by: Ard Biesheuvel Tested-by: Pavel Fedin Reviewed-by: Christoffer Dall Signed-off-by: Christoffer Dall diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 6984342..7dace90 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -98,6 +98,11 @@ static void kvm_flush_dcache_pud(pud_t pud) __kvm_flush_dcache_pud(pud); } +static bool kvm_is_device_pfn(unsigned long pfn) +{ + return !pfn_valid(pfn); +} + /** * stage2_dissolve_pmd() - clear and flush huge PMD entry * @kvm: pointer to kvm structure. @@ -213,7 +218,7 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, kvm_tlb_flush_vmid_ipa(kvm, addr); /* No need to invalidate the cache for device mappings */ - if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE) + if (!kvm_is_device_pfn(__phys_to_pfn(addr))) kvm_flush_dcache_pte(old_pte); put_page(virt_to_page(pte)); @@ -305,8 +310,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, pte = pte_offset_kernel(pmd, addr); do { - if (!pte_none(*pte) && - (pte_val(*pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE) + if (!pte_none(*pte) && !kvm_is_device_pfn(__phys_to_pfn(addr))) kvm_flush_dcache_pte(*pte); } while (pte++, addr += PAGE_SIZE, addr != end); } @@ -1037,11 +1041,6 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu) return kvm_vcpu_dabt_iswrite(vcpu); } -static bool kvm_is_device_pfn(unsigned long pfn) -{ - return !pfn_valid(pfn); -} - /** * stage2_wp_ptes - write protect PMD range * @pmd: pointer to pmd entry -- cgit v0.10.2 From c0f0963464c24e034b858441205455bf2a5d93ad Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 16 Nov 2015 10:28:17 +0000 Subject: arm64: KVM: Fix AArch32 to AArch64 register mapping When running a 32bit guest under a 64bit hypervisor, the ARMv8 architecture defines a mapping of the 32bit registers in the 64bit space. This includes banked registers that are being demultiplexed over the 64bit ones. On exceptions caused by an operation involving a 32bit register, the HW exposes the register number in the ESR_EL2 register. It was so far understood that SW had to distinguish between AArch32 and AArch64 accesses (based on the current AArch32 mode and register number). It turns out that I misinterpreted the ARM ARM, and the clue is in D1.20.1: "For some exceptions, the exception syndrome given in the ESR_ELx identifies one or more register numbers from the issued instruction that generated the exception. Where the exception is taken from an Exception level using AArch32 these register numbers give the AArch64 view of the register." Which means that the HW is already giving us the translated version, and that we shouldn't try to interpret it at all (for example, doing an MMIO operation from the IRQ mode using the LR register leads to very unexpected behaviours). The fix is thus not to perform a call to vcpu_reg32() at all from vcpu_reg(), and use whatever register number is supplied directly. The only case we need to find out about the mapping is when we actively generate a register access, which only occurs when injecting a fault in a guest. Cc: stable@vger.kernel.org Reviewed-by: Robin Murphy Signed-off-by: Marc Zyngier Signed-off-by: Christoffer Dall diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 17e92f0..3ca894e 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -99,11 +99,13 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) *vcpu_cpsr(vcpu) |= COMPAT_PSR_T_BIT; } +/* + * vcpu_reg should always be passed a register number coming from a + * read of ESR_EL2. Otherwise, it may give the wrong result on AArch32 + * with banked registers. + */ static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num) { - if (vcpu_mode_is_32bit(vcpu)) - return vcpu_reg32(vcpu, reg_num); - return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num]; } diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 85c5715..648112e 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -48,7 +48,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset) /* Note: These now point to the banked copies */ *vcpu_spsr(vcpu) = new_spsr_value; - *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset; + *vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset; /* Branch to exception vector */ if (sctlr & (1 << 13)) -- cgit v0.10.2 From 498cd5c32be6e32bc0f8efcad48ab094bb2bfdf3 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 16 Nov 2015 10:28:18 +0000 Subject: arm64: KVM: Add workaround for Cortex-A57 erratum 834220 Cortex-A57 parts up to r1p2 can misreport Stage 2 translation faults when a Stage 1 permission fault or device alignment fault should have been reported. This patch implements the workaround (which is to validate that the Stage-1 translation actually succeeds) by using code patching. Cc: stable@vger.kernel.org Reviewed-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Christoffer Dall diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9ac16a4..e55848c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -316,6 +316,27 @@ config ARM64_ERRATUM_832075 If unsure, say Y. +config ARM64_ERRATUM_834220 + bool "Cortex-A57: 834220: Stage 2 translation fault might be incorrectly reported in presence of a Stage 1 fault" + depends on KVM + default y + help + This option adds an alternative code sequence to work around ARM + erratum 834220 on Cortex-A57 parts up to r1p2. + + Affected Cortex-A57 parts might report a Stage 2 translation + fault as the result of a Stage 1 fault for load crossing a + page boundary when there is a permission or device memory + alignment fault at Stage 1 and a translation fault at Stage 2. + + The workaround is to verify that the Stage 1 translation + doesn't generate a fault before handling the Stage 2 fault. + Please note that this does not necessarily enable the workaround, + as it depends on the alternative framework, which will only patch + the kernel if an affected CPU is detected. + + If unsure, say Y. + config ARM64_ERRATUM_845719 bool "Cortex-A53: 845719: a load might read incorrect data" depends on COMPAT diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 11d5bb0f..52722ee 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -29,8 +29,9 @@ #define ARM64_HAS_PAN 4 #define ARM64_HAS_LSE_ATOMICS 5 #define ARM64_WORKAROUND_CAVIUM_23154 6 +#define ARM64_WORKAROUND_834220 7 -#define ARM64_NCAPS 7 +#define ARM64_NCAPS 8 #ifndef __ASSEMBLY__ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 24926f2..feb6b4e 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -75,6 +75,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = { (1 << MIDR_VARIANT_SHIFT) | 2), }, #endif +#ifdef CONFIG_ARM64_ERRATUM_834220 + { + /* Cortex-A57 r0p0 - r1p2 */ + .desc = "ARM erratum 834220", + .capability = ARM64_WORKAROUND_834220, + MIDR_RANGE(MIDR_CORTEX_A57, 0x00, + (1 << MIDR_VARIANT_SHIFT) | 2), + }, +#endif #ifdef CONFIG_ARM64_ERRATUM_845719 { /* Cortex-A53 r0p[01234] */ diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 1599701..ff2e038 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -1015,9 +1015,15 @@ el1_trap: b.ne 1f // Not an abort we care about /* This is an abort. Check for permission fault */ +alternative_if_not ARM64_WORKAROUND_834220 and x2, x1, #ESR_ELx_FSC_TYPE cmp x2, #FSC_PERM b.ne 1f // Not a permission fault +alternative_else + nop // Use the permission fault path to + nop // check for a valid S1 translation, + nop // regardless of the ESR value. +alternative_endif /* * Check for Stage-1 page table walk, which is guaranteed -- cgit v0.10.2 From 7e16aa81f9f6a7cfe2287b788a7d62abc2880185 Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Tue, 24 Nov 2015 10:31:07 +0100 Subject: KVM: arm/arm64: Fix preemptible timer active state crazyness We were setting the physical active state on the GIC distributor in a preemptible section, which could cause us to set the active state on different physical CPU from the one we were actually going to run on, hacoc ensues. Since we are no longer descheduling/scheduling soft timers in the flush/sync timer functions, simply moving the timer flush into a non-preemptible section. Reviewed-by: Marc Zyngier Signed-off-by: Christoffer Dall diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index eab83b2..e06fd29 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -564,17 +564,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu_sleep(vcpu); /* - * Disarming the background timer must be done in a - * preemptible context, as this call may sleep. - */ - kvm_timer_flush_hwstate(vcpu); - - /* * Preparing the interrupts to be injected also * involves poking the GIC, which must be done in a * non-preemptible context. */ preempt_disable(); + kvm_timer_flush_hwstate(vcpu); kvm_vgic_flush_hwstate(vcpu); local_irq_disable(); -- cgit v0.10.2 From 0e3dfda91d9fe8e2c4d0b5d21434b173a241eeaf Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Tue, 24 Nov 2015 16:23:05 +0100 Subject: KVM: arm/arm64: arch_timer: Preserve physical dist. active state on LR.active We were incorrectly removing the active state from the physical distributor on the timer interrupt when the timer output level was deasserted. We shouldn't be doing this without considering the virtual interrupt's active state, because the architecture requires that when an LR has the HW bit set and the pending or active bits set, then the physical interrupt must also have the corresponding bits set. This addresses an issue where we have been observing an inconsistency between the LR state and the physical distributor state where the LR state was active and the physical distributor was not active, which shouldn't happen. Reviewed-by: Marc Zyngier Signed-off-by: Christoffer Dall diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 9c747cb..d2f4147 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -342,10 +342,10 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, struct irq_phys_map *map, bool level); void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); -int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu); struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int irq); int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map); +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map); #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) #define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus)) diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 21a0ab2..69bca18 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -221,17 +221,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) kvm_timer_update_state(vcpu); /* - * If we enter the guest with the virtual input level to the VGIC - * asserted, then we have already told the VGIC what we need to, and - * we don't need to exit from the guest until the guest deactivates - * the already injected interrupt, so therefore we should set the - * hardware active state to prevent unnecessary exits from the guest. - * - * Conversely, if the virtual input level is deasserted, then always - * clear the hardware active state to ensure that hardware interrupts - * from the timer triggers a guest exit. - */ - if (timer->irq.level) + * If we enter the guest with the virtual input level to the VGIC + * asserted, then we have already told the VGIC what we need to, and + * we don't need to exit from the guest until the guest deactivates + * the already injected interrupt, so therefore we should set the + * hardware active state to prevent unnecessary exits from the guest. + * + * Also, if we enter the guest with the virtual timer interrupt active, + * then it must be active on the physical distributor, because we set + * the HW bit and the guest must be able to deactivate the virtual and + * physical interrupt at the same time. + * + * Conversely, if the virtual input level is deasserted and the virtual + * interrupt is not active, then always clear the hardware active state + * to ensure that hardware interrupts from the timer triggers a guest + * exit. + */ + if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map)) phys_active = true; else phys_active = false; diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 5335383..97e2c08 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1096,6 +1096,27 @@ static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu) vgic_set_lr(vcpu, lr_nr, vlr); } +static bool dist_active_irq(struct kvm_vcpu *vcpu) +{ + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + + return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu); +} + +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map) +{ + int i; + + for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) { + struct vgic_lr vlr = vgic_get_lr(vcpu, i); + + if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE) + return true; + } + + return dist_active_irq(vcpu); +} + /* * An interrupt may have been disabled after being made pending on the * CPU interface (the classic case is a timer running while we're @@ -1248,7 +1269,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) * may have been serviced from another vcpu. In all cases, * move along. */ - if (!kvm_vgic_vcpu_pending_irq(vcpu) && !kvm_vgic_vcpu_active_irq(vcpu)) + if (!kvm_vgic_vcpu_pending_irq(vcpu) && !dist_active_irq(vcpu)) goto epilog; /* SGIs */ @@ -1479,17 +1500,6 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) return test_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu); } -int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu) -{ - struct vgic_dist *dist = &vcpu->kvm->arch.vgic; - - if (!irqchip_in_kernel(vcpu->kvm)) - return 0; - - return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu); -} - - void vgic_kick_vcpus(struct kvm *kvm) { struct kvm_vcpu *vcpu; -- cgit v0.10.2 From 9f958c11b780af74fc311b96d6124740aa21cc68 Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Tue, 24 Nov 2015 16:34:31 +0100 Subject: KVM: arm/arm64: vgic: Trust the LR state for HW IRQs We were probing the physial distributor state for the active state of a HW virtual IRQ, because we had seen evidence that the LR state was not cleared when the guest deactivated a virtual interrupted. However, this issue turned out to be a software bug in the GIC, which was solved by: 84aab5e68c2a5e1e18d81ae8308c3ce25d501b29 (KVM: arm/arm64: arch_timer: Preserve physical dist. active state on LR.active, 2015-11-24) Therefore, get rid of the complexities and just look at the LR. Reviewed-by: Marc Zyngier Signed-off-by: Christoffer Dall diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 97e2c08..65461f8 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1417,25 +1417,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) static bool vgic_sync_hwirq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr) { struct vgic_dist *dist = &vcpu->kvm->arch.vgic; - struct irq_phys_map *map; - bool phys_active; bool level_pending; - int ret; if (!(vlr.state & LR_HW)) return false; - map = vgic_irq_map_search(vcpu, vlr.irq); - BUG_ON(!map); - - ret = irq_get_irqchip_state(map->irq, - IRQCHIP_STATE_ACTIVE, - &phys_active); - - WARN_ON(ret); - - if (phys_active) - return 0; + if (vlr.state & LR_STATE_ACTIVE) + return false; spin_lock(&dist->lock); level_pending = process_queued_irq(vcpu, lr, vlr); -- cgit v0.10.2 From 1d7a4e313abbc7200982e5a68121483a3aa32295 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 16 Nov 2015 13:55:51 +0000 Subject: arm64: kvm: avoid %p in __kvm_hyp_panic Currently __kvm_hyp_panic uses %p for values which are not pointers, such as the ESR value. This can confusingly lead to "(null)" being printed for the value. Use %x instead, and only use %p for host pointers. Signed-off-by: Mark Rutland Acked-by: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Christoffer Dall diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index ff2e038..ce70817 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -914,7 +914,7 @@ __kvm_hyp_panic: ENDPROC(__kvm_hyp_panic) __hyp_panic_str: - .ascii "HYP panic:\nPS:%08x PC:%p ESR:%p\nFAR:%p HPFAR:%p PAR:%p\nVCPU:%p\n\0" + .ascii "HYP panic:\nPS:%08x PC:%016x ESR:%08x\nFAR:%016x HPFAR:%016x PAR:%016x\nVCPU:%p\n\0" .align 2 -- cgit v0.10.2 From fbb4574ce9a37e15a9872860bf202f2be5bdf6c4 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 16 Nov 2015 13:58:29 +0000 Subject: arm64: kvm: report original PAR_EL1 upon panic If we call __kvm_hyp_panic while a guest context is active, we call __restore_sysregs before acquiring the system register values for the panic, in the process throwing away the PAR_EL1 value at the point of the panic. This patch modifies __kvm_hyp_panic to stash the PAR_EL1 value prior to restoring host register values, enabling us to report the original values at the point of the panic. Acked-by: Marc Zyngier Signed-off-by: Mark Rutland Signed-off-by: Christoffer Dall diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index ce70817..86c2898 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -864,6 +864,10 @@ ENTRY(__kvm_flush_vm_context) ENDPROC(__kvm_flush_vm_context) __kvm_hyp_panic: + // Stash PAR_EL1 before corrupting it in __restore_sysregs + mrs x0, par_el1 + push x0, xzr + // Guess the context by looking at VTTBR: // If zero, then we're already a host. // Otherwise restore a minimal host context before panicing. @@ -898,7 +902,7 @@ __kvm_hyp_panic: mrs x3, esr_el2 mrs x4, far_el2 mrs x5, hpfar_el2 - mrs x6, par_el1 + pop x6, xzr // active context PAR_EL1 mrs x7, tpidr_el2 mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ -- cgit v0.10.2 From 4e7697ed79d0c0d5f869c87a6b3ce3d5cd1a07d6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2015 16:43:29 -0500 Subject: drm/radeon: make rv770_set_sw_state failures non-fatal On some cards it takes a relatively long time for the change to take place. Make a timeout non-fatal. bug: https://bugs.freedesktop.org/show_bug.cgi?id=76130 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index b9c7707..d24c58c 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -1418,7 +1418,7 @@ int rv770_resume_smc(struct radeon_device *rdev) int rv770_set_sw_state(struct radeon_device *rdev) { if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK) - return -EINVAL; + DRM_ERROR("rv770_set_sw_state failed\n"); return 0; } -- cgit v0.10.2 From 627b655336fb20c7fdbefa7125b4c4aeead9b5fb Mon Sep 17 00:00:00 2001 From: Eddie Huang Date: Fri, 13 Nov 2015 18:50:35 +0800 Subject: soc: Mediatek: Enable SCPSYS power domain driver by default If enable Mediatek 8173 SoC, it should also enable power domain driver. Otherwise access clk subsystem register will fail. Signed-off-by: Eddie Huang Acked-by: Matthias Brugger Signed-off-by: Kevin Hilman diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 9d50682..0a4ea80 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -23,6 +23,7 @@ config MTK_PMIC_WRAP config MTK_SCPSYS bool "MediaTek SCPSYS Support" depends on ARCH_MEDIATEK || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK select REGMAP select MTK_INFRACFG select PM_GENERIC_DOMAINS if PM -- cgit v0.10.2 From 3dcc8d39cf15fa3ceabedcffcbd3958fe953555a Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Mon, 9 Nov 2015 20:00:27 +0100 Subject: PCI: Prevent out of bounds access in numa_node override Commit 1266963170f5 ("PCI: Prevent out of bounds access in numa_node override") missed that the user-provided node could also be negative. Handle this case as well to avoid out-of-bounds accesses to the node_states[] array. However, allow the special value -1, i.e. NUMA_NO_NODE, to be able to set the 'no specific node' configuration. Fixes: 1266963170f5 ("PCI: Prevent out of bounds access in numa_node override") Fixes: 63692df103e9 ("PCI: Allow numa_node override via sysfs") Signed-off-by: Mathias Krause Signed-off-by: Bjorn Helgaas CC: Sasha Levin CC: Prarit Bhargava CC: stable@vger.kernel.org # v3.19+ diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 9261868..eead54c 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -216,7 +216,10 @@ static ssize_t numa_node_store(struct device *dev, if (ret) return ret; - if (node >= MAX_NUMNODES || !node_online(node)) + if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES) + return -EINVAL; + + if (node != NUMA_NO_NODE && !node_online(node)) return -EINVAL; add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); -- cgit v0.10.2 From f3bef67992e8698897b584616535803887c4a73e Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 23 Nov 2015 16:07:41 -0500 Subject: selinux: fix bug in conditional rules handling commit fa1aa143ac4a ("selinux: extended permissions for ioctls") introduced a bug into the handling of conditional rules, skipping the processing entirely when the caller does not provide an extended permissions (xperms) structure. Access checks from userspace using /sys/fs/selinux/access do not include such a structure since that interface does not presently expose extended permission information. As a result, conditional rules were being ignored entirely on userspace access requests, producing denials when access was allowed by conditional rules in the policy. Fix the bug by only skipping computation of extended permissions in this situation, not the entire conditional rules processing. Reported-by: Laurent Bigonville Signed-off-by: Stephen Smalley [PM: fixed long lines in patch description] Cc: stable@vger.kernel.org # 4.3 Signed-off-by: Paul Moore diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 18643bf..456e1a9 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -638,7 +638,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, { struct avtab_node *node; - if (!ctab || !key || !avd || !xperms) + if (!ctab || !key || !avd) return; for (node = avtab_search_node(ctab, key); node; @@ -657,7 +657,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) avd->auditallow |= node->datum.u.data; - if ((node->key.specified & AVTAB_ENABLED) && + if (xperms && (node->key.specified & AVTAB_ENABLED) && (node->key.specified & AVTAB_XPERMS)) services_compute_xperms_drivers(xperms, node); } -- cgit v0.10.2 From 0c25ad80408e95e0a4fbaf0056950206e95f726f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Nov 2015 20:02:12 +0100 Subject: ALSA: hda - Fix noise on Gigabyte Z170X mobo Gigabyte Z710X mobo with ALC1150 codec gets significant noises from the analog loopback routes even if their inputs are all muted. Simply kill the aamix for fixing it. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=108301 Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e4f80dc..9bedf7c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1759,6 +1759,7 @@ enum { ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, ALC887_FIXUP_BASS_CHMAP, + ALC882_FIXUP_DISABLE_AAMIX, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -1920,6 +1921,8 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, static void alc_fixup_bass_chmap(struct hda_codec *codec, const struct hda_fixup *fix, int action); +static void alc_fixup_disable_aamix(struct hda_codec *codec, + const struct hda_fixup *fix, int action); static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { @@ -2151,6 +2154,10 @@ static const struct hda_fixup alc882_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_bass_chmap, }, + [ALC882_FIXUP_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2218,6 +2225,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), + SND_PCI_QUIRK(0x1458, 0xa182, "Gigabyte Z170X-UD3", ALC882_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), -- cgit v0.10.2 From 6527f833bf3fa34ed53e10b8010760fff42169f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 23 Nov 2015 14:32:10 +0100 Subject: net: cdc_ncm: fix NULL pointer deref in cdc_ncm_bind_common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 77b0a099674a ("cdc-ncm: use common parser") added a dangerous new trust in the CDC functional descriptors presented by the device, unconditionally assuming that any device handled by the driver has a CDC Union descriptor. This descriptor is required by the NCM and MBIM specs, but crashing on non-compliant devices is still unacceptable. Not only will that allow malicious devices to crash the kernel, but in this case it is also well known that there are non-compliant real devices on the market - as shown by the comment accompanying the IAD workaround in the same function. The Sierra Wireless EM7305 is an example of such device, having a CDC header and a CDC MBIM descriptor but no CDC Union: 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 MBIM: bcdMBIMVersion 1.00 wMaxControlMessage 4096 bNumberFilters 16 bMaxFilterSize 128 wMaxSegmentSize 4064 bmNetworkCapabilities 0x20 8-byte ntb input size Endpoint Descriptor: .. The conversion to a common parser also left the local cdc_union variable untouched. This caused the IAD workaround code to be applied to all devices with an IAD descriptor, which was never intended. Finish the conversion by testing for hdr.usb_cdc_union_desc instead. Cc: Oliver Neukum Fixes: 77b0a099674a ("cdc-ncm: use common parser") Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index a187f08..3b1ba82 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -691,7 +691,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) { - const struct usb_cdc_union_desc *union_desc = NULL; struct cdc_ncm_ctx *ctx; struct usb_driver *driver; u8 *buf; @@ -725,15 +724,16 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ /* parse through descriptors associated with control interface */ cdc_parse_cdc_header(&hdr, intf, buf, len); - ctx->data = usb_ifnum_to_if(dev->udev, - hdr.usb_cdc_union_desc->bSlaveInterface0); + if (hdr.usb_cdc_union_desc) + ctx->data = usb_ifnum_to_if(dev->udev, + hdr.usb_cdc_union_desc->bSlaveInterface0); ctx->ether_desc = hdr.usb_cdc_ether_desc; ctx->func_desc = hdr.usb_cdc_ncm_desc; ctx->mbim_desc = hdr.usb_cdc_mbim_desc; ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc; /* some buggy devices have an IAD but no CDC Union */ - if (!union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) { + if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) { ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1); dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n"); } -- cgit v0.10.2 From a4dad1ae24f850410c4e60f22823cba1289b8d52 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 24 Nov 2015 14:34:37 -0500 Subject: ext4: Fix handling of extended tv_sec In ext4, the bottom two bits of {a,c,m}time_extra are used to extend the {a,c,m}time fields, deferring the year 2038 problem to the year 2446. When decoding these extended fields, for times whose bottom 32 bits would represent a negative number, sign extension causes the 64-bit extended timestamp to be negative as well, which is not what's intended. This patch corrects that issue, so that the only negative {a,c,m}times are those between 1901 and 1970 (as per 32-bit signed timestamps). Some older kernels might have written pre-1970 dates with 1,1 in the extra bits. This patch treats those incorrectly-encoded dates as pre-1970, instead of post-2311, until kernel 4.20 is released. Hopefully by then e2fsck will have fixed up the bad data. Also add a comment explaining the encoding of ext4's extra {a,c,m}time bits. Signed-off-by: David Turner Signed-off-by: Theodore Ts'o Reported-by: Mark Harris Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=23732 Cc: stable@vger.kernel.org diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 750063f..cc7ca4e 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -727,19 +728,55 @@ struct move_extent { <= (EXT4_GOOD_OLD_INODE_SIZE + \ (einode)->i_extra_isize)) \ +/* + * We use an encoding that preserves the times for extra epoch "00": + * + * extra msb of adjust for signed + * epoch 32-bit 32-bit tv_sec to + * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range + * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31 + * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19 + * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07 + * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25 + * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16 + * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04 + * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22 + * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10 + * + * Note that previous versions of the kernel on 64-bit systems would + * incorrectly use extra epoch bits 1,1 for dates between 1901 and + * 1970. e2fsck will correct this, assuming that it is run on the + * affected filesystem before 2242. + */ + static inline __le32 ext4_encode_extra_time(struct timespec *time) { - return cpu_to_le32((sizeof(time->tv_sec) > 4 ? - (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) | - ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK)); + u32 extra = sizeof(time->tv_sec) > 4 ? + ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0; + return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS)); } static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra) { - if (sizeof(time->tv_sec) > 4) - time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) - << 32; - time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; + if (unlikely(sizeof(time->tv_sec) > 4 && + (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0) + /* Handle legacy encoding of pre-1970 dates with epoch + * bits 1,1. We assume that by kernel version 4.20, + * everyone will have run fsck over the affected + * filesystems to correct the problem. (This + * backwards compatibility may be removed before this + * time, at the discretion of the ext4 developers.) + */ + u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK; + if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0) + extra_bits = 0; + time->tv_sec += extra_bits << 32; +#else + time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32; +#endif + } + time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; } #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \ -- cgit v0.10.2 From 81b1a832d79749058863cffe2c0ed4ef40f6e6ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 24 Nov 2015 11:39:54 -0800 Subject: pidns: fix NULL dereference in __task_pid_nr_ns() I got a crash during a "perf top" session that was caused by a race in __task_pid_nr_ns() : pid_nr_ns() was inlined, but apparently compiler chose to read task->pids[type].pid twice, and the pid->level dereference crashed because we got a NULL pointer at the second read : if (pid && ns->level <= pid->level) { // CRASH Just use RCU API properly to solve this race, and not worry about "perf top" crashing hosts :( get_task_pid() can benefit from same fix. Signed-off-by: Eric Dumazet Signed-off-by: Linus Torvalds diff --git a/kernel/pid.c b/kernel/pid.c index ca36879..78b3d9f 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -467,7 +467,7 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type) rcu_read_lock(); if (type != PIDTYPE_PID) task = task->group_leader; - pid = get_pid(task->pids[type].pid); + pid = get_pid(rcu_dereference(task->pids[type].pid)); rcu_read_unlock(); return pid; } @@ -528,7 +528,7 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, if (likely(pid_alive(task))) { if (type != PIDTYPE_PID) task = task->group_leader; - nr = pid_nr_ns(task->pids[type].pid, ns); + nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns); } rcu_read_unlock(); -- cgit v0.10.2 From 5228e39e3f709c82e6c4643402fc25de54391e32 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 24 Nov 2015 11:36:52 +0200 Subject: PCI: designware: Remove incorrect io_base assignment "pp->io" is an I/O resource, e.g., "[io 0x0000-0xffff]"; "pp->io_base" is the CPU physical address of a region where the host bridge converts CPU memory accesses into PCI I/O transactions. Corrupting pp->io_base by assigning pp->io->start to it breaks access to the PCI I/O space, as reported by Kishon. Remove the invalid assignment. [bhelgaas: changelog] Fixes: 0021d22b73d6 ("PCI: designware: Use of_pci_get_host_bridge_resources() to parse DT") Reported-and-tested-by: Kishon Vijay Abraham I Signed-off-by: Stanimir Varbanov Signed-off-by: Bjorn Helgaas Reviewed-by: Arnd Bergmann diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 540f077..02a7452 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -440,7 +440,6 @@ int dw_pcie_host_init(struct pcie_port *pp) ret, pp->io); continue; } - pp->io_base = pp->io->start; break; case IORESOURCE_MEM: pp->mem = win->res; -- cgit v0.10.2 From bc23f0c8d7ccd8d924c4e70ce311288cb3e61ea8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Nov 2015 15:34:35 -0500 Subject: jbd2: Fix unreclaimed pages after truncate in data=journal mode Ted and Namjae have reported that truncated pages don't get timely reclaimed after being truncated in data=journal mode. The following test triggers the issue easily: for (i = 0; i < 1000; i++) { pwrite(fd, buf, 1024*1024, 0); fsync(fd); fsync(fd); ftruncate(fd, 0); } The reason is that journal_unmap_buffer() finds that truncated buffers are not journalled (jh->b_transaction == NULL), they are part of checkpoint list of a transaction (jh->b_cp_transaction != NULL) and have been already written out (!buffer_dirty(bh)). We clean such buffers but we leave them in the checkpoint list. Since checkpoint transaction holds a reference to the journal head, these buffers cannot be released until the checkpoint transaction is cleaned up. And at that point we don't call release_buffer_page() anymore so pages detached from mapping are lingering in the system waiting for reclaim to find them and free them. Fix the problem by removing buffers from transaction checkpoint lists when journal_unmap_buffer() finds out they don't have to be there anymore. Reported-and-tested-by: Namjae Jeon Fixes: de1b794130b130e77ffa975bb58cb843744f9ae5 Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 6b8338e..b996212 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -2152,6 +2152,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, if (!buffer_dirty(bh)) { /* bdflush has written it. We can drop it now */ + __jbd2_journal_remove_checkpoint(jh); goto zap_buffer; } @@ -2181,6 +2182,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, /* The orphan record's transaction has * committed. We can cleanse this buffer */ clear_buffer_jbddirty(bh); + __jbd2_journal_remove_checkpoint(jh); goto zap_buffer; } } -- cgit v0.10.2 From aeb20b6b3f4e1f88ce6a2802dabc667b607412ef Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Mon, 23 Nov 2015 12:04:52 -0800 Subject: drivers: net: xgene: fix: ifconfig up/down crash Fixing kernel crash when doing ifconfig down and up in a loop, [ 124.028237] Call trace: [ 124.030670] [] memcpy+0x20/0x180 [ 124.035436] [] skb_clone+0x3c/0xa8 [ 124.040374] [] __skb_tstamp_tx+0xc0/0x118 [ 124.045918] [] skb_tstamp_tx+0x10/0x1c [ 124.051203] [] xgene_enet_start_xmit+0x2e4/0x33c [ 124.057352] [] dev_hard_start_xmit+0x2e8/0x400 [ 124.063327] [] sch_direct_xmit+0x90/0x1d4 [ 124.068870] [] __dev_queue_xmit+0x28c/0x498 [ 124.074585] [] dev_queue_xmit_sk+0x10/0x1c [ 124.080216] [] ip_finish_output2+0x3d0/0x438 [ 124.086017] [] ip_finish_output+0x198/0x1ac [ 124.091732] [] ip_output+0xec/0x164 [ 124.096755] [] ip_local_out_sk+0x38/0x48 [ 124.102211] [] ip_queue_xmit+0x288/0x330 [ 124.107668] [] tcp_transmit_skb+0x908/0x964 [ 124.113383] [] tcp_send_ack+0x128/0x138 [ 124.118753] [] __tcp_ack_snd_check+0x5c/0x94 [ 124.124555] [] tcp_rcv_established+0x554/0x68c [ 124.130530] [] tcp_v4_do_rcv+0xa4/0x37c [ 124.135900] [] release_sock+0xb4/0x150 [ 124.141184] [] tcp_recvmsg+0x448/0x9e0 [ 124.146468] [] inet_recvmsg+0xa0/0xc0 [ 124.151666] [] sock_recvmsg+0x10/0x1c [ 124.156863] [] SyS_recvfrom+0xa4/0xf8 [ 124.162061] Code: f2400c84 540001c0 cb040042 36000064 (38401423) [ 124.168133] ---[ end trace 7ab2550372e8a65b ]--- The fix was to reorder napi_enable, napi_disable, request_irq and free_irq calls, move register_netdev after dma_coerce_mask_and_coherent. Signed-off-by: Iyappan Subramanian Tested-by: Khuong Dinh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 991412c..1adfe70 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -688,10 +688,10 @@ static int xgene_enet_open(struct net_device *ndev) mac_ops->tx_enable(pdata); mac_ops->rx_enable(pdata); + xgene_enet_napi_enable(pdata); ret = xgene_enet_register_irq(ndev); if (ret) return ret; - xgene_enet_napi_enable(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) phy_start(pdata->phy_dev); @@ -715,13 +715,13 @@ static int xgene_enet_close(struct net_device *ndev) else cancel_delayed_work_sync(&pdata->link_work); - xgene_enet_napi_disable(pdata); - xgene_enet_free_irq(ndev); - xgene_enet_process_ring(pdata->rx_ring, -1); - mac_ops->tx_disable(pdata); mac_ops->rx_disable(pdata); + xgene_enet_free_irq(ndev); + xgene_enet_napi_disable(pdata); + xgene_enet_process_ring(pdata->rx_ring, -1); + return 0; } @@ -1474,15 +1474,15 @@ static int xgene_enet_probe(struct platform_device *pdev) } ndev->hw_features = ndev->features; - ret = register_netdev(ndev); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { - netdev_err(ndev, "Failed to register netdev\n"); + netdev_err(ndev, "No usable DMA configuration\n"); goto err; } - ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); + ret = register_netdev(ndev); if (ret) { - netdev_err(ndev, "No usable DMA configuration\n"); + netdev_err(ndev, "Failed to register netdev\n"); goto err; } @@ -1490,14 +1490,17 @@ static int xgene_enet_probe(struct platform_device *pdev) if (ret) goto err; - xgene_enet_napi_add(pdata); mac_ops = pdata->mac_ops; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ret = xgene_enet_mdio_config(pdata); - else + if (ret) + goto err; + } else { INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); + } - return ret; + xgene_enet_napi_add(pdata); + return 0; err: unregister_netdev(ndev); free_netdev(ndev); -- cgit v0.10.2 From 9f55cf5654fff70de8675ea128b53281edc794d3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 24 Nov 2015 15:38:07 -0600 Subject: PCI: hisi: Fix deferred probing The hisi_pcie_probe() function is incorrectly marked as __init, as Kconfig tells us: WARNING: drivers/pci/host/built-in.o(.data+0x7780): Section mismatch in reference from the variable hisi_pcie_driver to the function .init.text:hisi_pcie_probe() If the probe for this device gets deferred past the point where __init functions are removed, or the device is unbound and then reattached to the driver, we branch into uninitialized memory, which is bad. Remove the __init annotation from hisi_pcie_probe() and hisi_add_pcie_port(). Fixes: 500a1d9a43e0 ("PCI: hisi: Add HiSilicon SoC Hip05 PCIe driver") Signed-off-by: Arnd Bergmann Signed-off-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Acked-by: Zhou Wang diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 35457ec..163671a 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -111,7 +111,7 @@ static struct pcie_host_ops hisi_pcie_host_ops = { .link_up = hisi_pcie_link_up, }; -static int __init hisi_add_pcie_port(struct pcie_port *pp, +static int hisi_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) { int ret; @@ -139,7 +139,7 @@ static int __init hisi_add_pcie_port(struct pcie_port *pp, return 0; } -static int __init hisi_pcie_probe(struct platform_device *pdev) +static int hisi_pcie_probe(struct platform_device *pdev) { struct hisi_pcie *hisi_pcie; struct pcie_port *pp; -- cgit v0.10.2 From 264640fc2c5f4f913db5c73fa3eb1ead2c45e9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Tue, 24 Nov 2015 15:07:11 +0100 Subject: ipv6: distinguish frag queues by device for multicast and link-local packets If a fragmented multicast packet is received on an ethernet device which has an active macvlan on top of it, each fragment is duplicated and received both on the underlying device and the macvlan. If some fragments for macvlan are processed before the whole packet for the underlying device is reassembled, the "overlapping fragments" test in ip6_frag_queue() discards the whole fragment queue. To resolve this, add device ifindex to the search key and require it to match reassembling multicast packets and packets to link-local addresses. Note: similar patch has been already submitted by Yoshifuji Hideaki in http://patchwork.ozlabs.org/patch/220979/ but got lost and forgotten for some reason. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e1a10b0..ea5a13e 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -490,6 +490,7 @@ struct ip6_create_arg { u32 user; const struct in6_addr *src; const struct in6_addr *dst; + int iif; u8 ecn; }; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index d5efeb8..bab4441 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -190,7 +190,7 @@ static void nf_ct_frag6_expire(unsigned long data) /* Creation primitives. */ static inline struct frag_queue *fq_find(struct net *net, __be32 id, u32 user, struct in6_addr *src, - struct in6_addr *dst, u8 ecn) + struct in6_addr *dst, int iif, u8 ecn) { struct inet_frag_queue *q; struct ip6_create_arg arg; @@ -200,6 +200,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, arg.user = user; arg.src = src; arg.dst = dst; + arg.iif = iif; arg.ecn = ecn; local_bh_disable(); @@ -601,7 +602,7 @@ struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 use fhdr = (struct frag_hdr *)skb_transport_header(clone); fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, - ip6_frag_ecn(hdr)); + skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); if (fq == NULL) { pr_debug("Can't find and can't create new queue\n"); goto ret_orig; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 44e21a0..45f5ae5 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -108,7 +108,10 @@ bool ip6_frag_match(const struct inet_frag_queue *q, const void *a) return fq->id == arg->id && fq->user == arg->user && ipv6_addr_equal(&fq->saddr, arg->src) && - ipv6_addr_equal(&fq->daddr, arg->dst); + ipv6_addr_equal(&fq->daddr, arg->dst) && + (arg->iif == fq->iif || + !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST | + IPV6_ADDR_LINKLOCAL))); } EXPORT_SYMBOL(ip6_frag_match); @@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data) static struct frag_queue * fq_find(struct net *net, __be32 id, const struct in6_addr *src, - const struct in6_addr *dst, u8 ecn) + const struct in6_addr *dst, int iif, u8 ecn) { struct inet_frag_queue *q; struct ip6_create_arg arg; @@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, arg.user = IP6_DEFRAG_LOCAL_DELIVER; arg.src = src; arg.dst = dst; + arg.iif = iif; arg.ecn = ecn; hash = inet6_hash_frag(id, src, dst); @@ -551,7 +555,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) } fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, - ip6_frag_ecn(hdr)); + skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); if (fq) { int ret; -- cgit v0.10.2 From c5c9f25b98a568451d665afe4aeefe17bf9f2995 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Tue, 24 Nov 2015 09:55:05 -0700 Subject: NVMe: default to 4k device page size We received a bug report recently when DDW (64-bit direct DMA on Power) is not enabled for NVMe devices. In that case, we fall back to 32-bit DMA via the IOMMU, which is always done via 4K TCEs (Translation Control Entries). The NVMe device driver, though, assumes that the DMA alignment for the PRP entries will match the device's page size, and that the DMA aligment matches the kernel's page aligment. On Power, the the IOMMU page size, as mentioned above, can be 4K, while the device can have a page size of 8K, while the kernel has a page size of 64K. This eventually trips the BUG_ON in nvme_setup_prps(), as we have a 'dma_len' that is a multiple of 4K but not 8K (e.g., 0xF000). In this particular case of page sizes, we clearly want to use the IOMMU's page size in the driver. And generally, the NVMe driver in this function should be using the IOMMU's page size for the default device page size, rather than the kernel's page size. There is not currently an API to obtain the IOMMU's page size across all architectures and in the interest of a stop-gap fix to this functional issue, default the NVMe device page size to 4K, with the intent of adding such an API and implementation across all architectures in the next merge window. With the functionally equivalent v3 of this patch, our hardware test exerciser survives when using 32-bit DMA; without the patch, the kernel will BUG within a few minutes. Signed-off-by: Nishanth Aravamudan Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 930042fa..d9d6229 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1728,9 +1728,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) u32 aqa; u64 cap = lo_hi_readq(&dev->bar->cap); struct nvme_queue *nvmeq; - unsigned page_shift = PAGE_SHIFT; + /* + * default to a 4K page size, with the intention to update this + * path in the future to accomodate architectures with differing + * kernel and IO page sizes. + */ + unsigned page_shift = 12; unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12; - unsigned dev_page_max = NVME_CAP_MPSMAX(cap) + 12; if (page_shift < dev_page_min) { dev_err(dev->dev, @@ -1739,13 +1743,6 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) 1 << page_shift); return -ENODEV; } - if (page_shift > dev_page_max) { - dev_info(dev->dev, - "Device maximum page size (%u) smaller than " - "host (%u); enabling work-around\n", - 1 << dev_page_max, 1 << page_shift); - page_shift = dev_page_max; - } dev->subsystem = readl(&dev->bar->vs) >= NVME_VS(1, 1) ? NVME_CAP_NSSRC(cap) : 0; -- cgit v0.10.2 From 33c40e242ce681092ab778c238f3fff5a345ee0e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Nov 2015 14:41:59 +0000 Subject: rxrpc: Correctly handle ack at end of client call transmit phase Normally, the transmit phase of a client call is implicitly ack'd by the reception of the first data packet of the response being received. However, if a security negotiation happens, the transmit phase, if it is entirely contained in a single packet, may get an ack packet in response and then may get aborted due to security negotiation failure. Because the client has shifted state to RXRPC_CALL_CLIENT_AWAIT_REPLY due to having transmitted all the data, the code that handles processing of the received ack packet doesn't note the hard ack the data packet. The following abort packet in the case of security negotiation failure then incurs an assertion failure when it tries to drain the Tx queue because the hard ack state is out of sync (hard ack means the packets have been processed and can be discarded by the sender; a soft ack means that the packets are received but could still be discarded and rerequested by the receiver). To fix this, we should record the hard ack we received for the ack packet. The assertion failure looks like: RxRPC: Assertion failed 1 <= 0 is false 0x1 <= 0x0 is false ------------[ cut here ]------------ kernel BUG at ../net/rxrpc/ar-ack.c:431! ... RIP: 0010:[] [] rxrpc_rotate_tx_window+0xbc/0x131 [af_rxrpc] ... Signed-off-by: David Howells Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index e0547f5..adc555e 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -723,8 +723,10 @@ process_further: if ((call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY || call->state == RXRPC_CALL_SERVER_AWAIT_ACK) && - hard > tx) + hard > tx) { + call->acks_hard = tx; goto all_acked; + } smp_rmb(); rxrpc_rotate_tx_window(call, hard - 1); -- cgit v0.10.2 From fbdd29bfd2da979b7ac6a0084af56624156c1069 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 24 Nov 2015 17:09:30 +0100 Subject: net: ipmr, ip6mr: fix vif/tunnel failure race condition Since (at least) commit b17a7c179dd3 ("[NET]: Do sysfs registration as part of register_netdevice."), netdev_run_todo() deals only with unregistration, so we don't need to do the rtnl_unlock/lock cycle to finish registration when failing pimreg or dvmrp device creation. In fact that opens a race condition where someone can delete the device while rtnl is unlocked because it's fully registered. The problem gets worse when netlink support is introduced as there are more points of entry that can cause it and it also makes reusing that code correctly impossible. Signed-off-by: Nikolay Aleksandrov Reviewed-by: Cong Wang Signed-off-by: David S. Miller diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 292123b..c3a3835 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -441,10 +441,6 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) return dev; failure: - /* allow the register to be completed before unregistering. */ - rtnl_unlock(); - rtnl_lock(); - unregister_netdevice(dev); return NULL; } @@ -540,10 +536,6 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) return dev; failure: - /* allow the register to be completed before unregistering. */ - rtnl_unlock(); - rtnl_lock(); - unregister_netdevice(dev); return NULL; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 7a4a1b8..a10e771 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -765,10 +765,6 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt) return dev; failure: - /* allow the register to be completed before unregistering. */ - rtnl_unlock(); - rtnl_lock(); - unregister_netdevice(dev); return NULL; } -- cgit v0.10.2 From 20f795666d3accbb75969730019aeb03f50ef0ec Mon Sep 17 00:00:00 2001 From: Aaron Conole Date: Tue, 24 Nov 2015 13:51:53 -0500 Subject: net: openvswitch: Remove invalid comment During pre-upstream development, the openvswitch datapath used a custom hashtable to store vports that could fail on delete due to lack of memory. However, prior to upstream submission, this code was reworked to use an hlist based hastable with flexible-array based buckets. As such the failure condition was eliminated from the vport_del path, rendering this comment invalid. Signed-off-by: Aaron Conole Signed-off-by: David S. Miller diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 0ac0fd0..e194c10a 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -256,8 +256,8 @@ int ovs_vport_set_options(struct vport *vport, struct nlattr *options) * * @vport: vport to delete. * - * Detaches @vport from its datapath and destroys it. It is possible to fail - * for reasons such as lack of memory. ovs_mutex must be held. + * Detaches @vport from its datapath and destroys it. ovs_mutex must + * be held. */ void ovs_vport_del(struct vport *vport) { -- cgit v0.10.2 From 8c7188b23474cca017b3ef354c4a58456f68303a Mon Sep 17 00:00:00 2001 From: Quentin Casasnovas Date: Tue, 24 Nov 2015 17:13:21 -0500 Subject: RDS: fix race condition when sending a message on unbound socket Sasha's found a NULL pointer dereference in the RDS connection code when sending a message to an apparently unbound socket. The problem is caused by the code checking if the socket is bound in rds_sendmsg(), which checks the rs_bound_addr field without taking a lock on the socket. This opens a race where rs_bound_addr is temporarily set but where the transport is not in rds_bind(), leading to a NULL pointer dereference when trying to dereference 'trans' in __rds_conn_create(). Vegard wrote a reproducer for this issue, so kindly ask him to share if you're interested. I cannot reproduce the NULL pointer dereference using Vegard's reproducer with this patch, whereas I could without. Complete earlier incomplete fix to CVE-2015-6937: 74e98eb08588 ("RDS: verify the underlying transport exists before creating a connection") Cc: David S. Miller Cc: stable@vger.kernel.org Reviewed-by: Vegard Nossum Reviewed-by: Sasha Levin Acked-by: Santosh Shilimkar Signed-off-by: Quentin Casasnovas Signed-off-by: David S. Miller diff --git a/net/rds/connection.c b/net/rds/connection.c index d456403..e3b118c 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -186,12 +186,6 @@ static struct rds_connection *__rds_conn_create(struct net *net, } } - if (trans == NULL) { - kmem_cache_free(rds_conn_slab, conn); - conn = ERR_PTR(-ENODEV); - goto out; - } - conn->c_trans = trans; ret = trans->conn_alloc(conn, gfp); diff --git a/net/rds/send.c b/net/rds/send.c index 827155c..c9cdb35 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1013,11 +1013,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) release_sock(sk); } - /* racing with another thread binding seems ok here */ + lock_sock(sk); if (daddr == 0 || rs->rs_bound_addr == 0) { + release_sock(sk); ret = -ENOTCONN; /* XXX not a great errno */ goto out; } + release_sock(sk); if (payload_len > rds_sk_sndbuf(rs)) { ret = -EMSGSIZE; -- cgit v0.10.2 From bf508e910b02a6107a5aa054e03c6fc8a65dae1e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 16 Oct 2015 07:58:31 +0200 Subject: nvme: add missing unmaps in nvme_queue_rq When we fail various metadata related operations in nvme_queue_rq we need to unmap the data SGL. Cc: stable@vger.kernel.org Signed-off-by: Christoph Hellwig Signed-off-by: Keith Busch Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d9d6229..f3b53af 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -896,19 +896,28 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, goto retry_cmd; } if (blk_integrity_rq(req)) { - if (blk_rq_count_integrity_sg(req->q, req->bio) != 1) + if (blk_rq_count_integrity_sg(req->q, req->bio) != 1) { + dma_unmap_sg(dev->dev, iod->sg, iod->nents, + dma_dir); goto error_cmd; + } sg_init_table(iod->meta_sg, 1); if (blk_rq_map_integrity_sg( - req->q, req->bio, iod->meta_sg) != 1) + req->q, req->bio, iod->meta_sg) != 1) { + dma_unmap_sg(dev->dev, iod->sg, iod->nents, + dma_dir); goto error_cmd; + } if (rq_data_dir(req)) nvme_dif_remap(req, nvme_dif_prep); - if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir)) + if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir)) { + dma_unmap_sg(dev->dev, iod->sg, iod->nents, + dma_dir); goto error_cmd; + } } } -- cgit v0.10.2 From 55ce0da1da287822e5ffb5fcd6e357180d5ba4cd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Oct 2015 20:47:04 +0800 Subject: block: fix blk_abort_request for blk-mq drivers We only added the request to the request list for the !blk-mq case, so we should only delete it in that case as well. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 246dfb1..aa40aa9 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -158,11 +158,13 @@ void blk_abort_request(struct request *req) { if (blk_mark_rq_complete(req)) return; - blk_delete_timer(req); - if (req->q->mq_ops) + + if (req->q->mq_ops) { blk_mq_rq_timed_out(req, false); - else + } else { + blk_delete_timer(req); blk_rq_timed_out(req); + } } EXPORT_SYMBOL_GPL(blk_abort_request); -- cgit v0.10.2 From 07687c031d14a1f36613231c0ea13ce3c4025615 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Thu, 29 Oct 2015 14:39:56 -0500 Subject: fpga manager: remove label Remove implementation of 'label' DT binding. Signed-off-by: Alan Tull Reviewed-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index a24f5cb..bfbf8aa 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -256,7 +256,6 @@ int fpga_mgr_register(struct device *dev, const char *name, void *priv) { struct fpga_manager *mgr; - const char *dt_label; int id, ret; if (!mops || !mops->write_init || !mops->write || @@ -300,11 +299,9 @@ int fpga_mgr_register(struct device *dev, const char *name, mgr->dev.id = id; dev_set_drvdata(dev, mgr); - dt_label = of_get_property(mgr->dev.of_node, "label", NULL); - if (dt_label) - ret = dev_set_name(&mgr->dev, "%s", dt_label); - else - ret = dev_set_name(&mgr->dev, "fpga%d", id); + ret = dev_set_name(&mgr->dev, "fpga%d", id); + if (ret) + goto error_device; ret = device_add(&mgr->dev); if (ret) -- cgit v0.10.2 From e8c77bda05e5d93cce6f38cfdde4192307951dea Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 18 Nov 2015 10:48:16 +0100 Subject: fpga manager: Fix firmware resource leak on error If fpga_mgr_buf_load() fails, the firmware resource previously allocated by request_firmware() is leaked. Fix it by calling release_firmware() regardless of the return value of fpga_mgr_buf_load(). Found by the Coverity scanner (CID 1339653). Fixes: 6a8c3be7ec8e ("add FPGA manager core") Signed-off-by: Tobias Klauser Acked-by: Alan Tull Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index bfbf8aa..953dc91 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -122,12 +122,10 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, } ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size); - if (ret) - return ret; release_firmware(fw); - return 0; + return ret; } EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load); -- cgit v0.10.2 From 096fe9eaea40a17e125569f9e657e34cdb6d73bd Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Nov 2015 21:36:31 +0000 Subject: KEYS: Fix handling of stored error in a negatively instantiated user key If a user key gets negatively instantiated, an error code is cached in the payload area. A negatively instantiated key may be then be positively instantiated by updating it with valid data. However, the ->update key type method must be aware that the error code may be there. The following may be used to trigger the bug in the user key type: keyctl request2 user user "" @u keyctl add user user "a" @u which manifests itself as: BUG: unable to handle kernel paging request at 00000000ffffff8a IP: [] __call_rcu.constprop.76+0x1f/0x280 kernel/rcu/tree.c:3046 PGD 7cc30067 PUD 0 Oops: 0002 [#1] SMP Modules linked in: CPU: 3 PID: 2644 Comm: a.out Not tainted 4.3.0+ #49 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 task: ffff88003ddea700 ti: ffff88003dd88000 task.ti: ffff88003dd88000 RIP: 0010:[] [] __call_rcu.constprop.76+0x1f/0x280 [] __call_rcu.constprop.76+0x1f/0x280 kernel/rcu/tree.c:3046 RSP: 0018:ffff88003dd8bdb0 EFLAGS: 00010246 RAX: 00000000ffffff82 RBX: 0000000000000000 RCX: 0000000000000001 RDX: ffffffff81e3fe40 RSI: 0000000000000000 RDI: 00000000ffffff82 RBP: ffff88003dd8bde0 R08: ffff88007d2d2da0 R09: 0000000000000000 R10: 0000000000000000 R11: ffff88003e8073c0 R12: 00000000ffffff82 R13: ffff88003dd8be68 R14: ffff88007d027600 R15: ffff88003ddea700 FS: 0000000000b92880(0063) GS:ffff88007fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000000ffffff8a CR3: 000000007cc5f000 CR4: 00000000000006e0 Stack: ffff88003dd8bdf0 ffffffff81160a8a 0000000000000000 00000000ffffff82 ffff88003dd8be68 ffff88007d027600 ffff88003dd8bdf0 ffffffff810a39e5 ffff88003dd8be20 ffffffff812a31ab ffff88007d027600 ffff88007d027620 Call Trace: [] kfree_call_rcu+0x15/0x20 kernel/rcu/tree.c:3136 [] user_update+0x8b/0xb0 security/keys/user_defined.c:129 [< inline >] __key_update security/keys/key.c:730 [] key_create_or_update+0x291/0x440 security/keys/key.c:908 [< inline >] SYSC_add_key security/keys/keyctl.c:125 [] SyS_add_key+0x101/0x1e0 security/keys/keyctl.c:60 [] entry_SYSCALL_64_fastpath+0x12/0x6a arch/x86/entry/entry_64.S:185 Note the error code (-ENOKEY) in EDX. A similar bug can be tripped by: keyctl request2 trusted user "" @u keyctl add trusted user "a" @u This should also affect encrypted keys - but that has to be correctly parameterised or it will fail with EINVAL before getting to the bit that will crashes. Reported-by: Dmitry Vyukov Signed-off-by: David Howells Acked-by: Mimi Zohar Signed-off-by: James Morris diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 927db9f..696ccfa 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -845,6 +845,8 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) size_t datalen = prep->datalen; int ret = 0; + if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + return -ENOKEY; if (datalen <= 0 || datalen > 32767 || !prep->data) return -EINVAL; diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 903dace..16dec53 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -1007,13 +1007,16 @@ static void trusted_rcu_free(struct rcu_head *rcu) */ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) { - struct trusted_key_payload *p = key->payload.data[0]; + struct trusted_key_payload *p; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; size_t datalen = prep->datalen; char *datablob; int ret = 0; + if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + return -ENOKEY; + p = key->payload.data[0]; if (!p->migratable) return -EPERM; if (datalen <= 0 || datalen > 32767 || !prep->data) diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 28cb30f..8705d79 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -120,7 +120,10 @@ int user_update(struct key *key, struct key_preparsed_payload *prep) if (ret == 0) { /* attach the new data, displacing the old */ - zap = key->payload.data[0]; + if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) + zap = key->payload.data[0]; + else + zap = NULL; rcu_assign_keypointer(key, upayload); key->expiry = 0; } -- cgit v0.10.2 From 269249e17499ef7e431601a80ea552ff0695f290 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Tue, 3 Nov 2015 23:16:04 +0100 Subject: drm/nouveau/pci: enable c800 magic for Clevo P157SM this is needed for my gpu Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index e3c783d..d506e02 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -689,6 +689,12 @@ nvkm_device_pci_10de_1199[] = { }; static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_11e0[] = { + { 0x1558, 0x5106, NULL, { .War00C800_0 = true } }, + {} +}; + +static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_11e3[] = { { 0x17aa, 0x3683, "GeForce GTX 760A" }, {} @@ -1485,7 +1491,7 @@ nvkm_device_pci_10de[] = { { 0x11c6, "GeForce GTX 650 Ti" }, { 0x11c8, "GeForce GTX 650" }, { 0x11cb, "GeForce GT 740" }, - { 0x11e0, "GeForce GTX 770M" }, + { 0x11e0, "GeForce GTX 770M", nvkm_device_pci_10de_11e0 }, { 0x11e1, "GeForce GTX 765M" }, { 0x11e2, "GeForce GTX 765M" }, { 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 }, -- cgit v0.10.2 From c294a052f8b446c7a36adfa587e9f2c6ff425279 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 5 Nov 2015 11:00:29 +1000 Subject: drm/nouveau/pci: enable c800 magic for some unknown Samsung laptop fdo#70354 - comment #88. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index d506e02..caf22b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -279,6 +279,12 @@ nvkm_device_pci_10de_0fe3[] = { }; static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0fe4[] = { + { 0x144d, 0xc740, NULL, { .War00C800_0 = true } }, + {} +}; + +static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_104b[] = { { 0x1043, 0x844c, "GeForce GT 625" }, { 0x1043, 0x846b, "GeForce GT 625" }, @@ -1376,7 +1382,7 @@ nvkm_device_pci_10de[] = { { 0x0fe1, "GeForce GT 730M" }, { 0x0fe2, "GeForce GT 745M" }, { 0x0fe3, "GeForce GT 745M", nvkm_device_pci_10de_0fe3 }, - { 0x0fe4, "GeForce GT 750M" }, + { 0x0fe4, "GeForce GT 750M", nvkm_device_pci_10de_0fe4 }, { 0x0fe9, "GeForce GT 750M" }, { 0x0fea, "GeForce GT 755M" }, { 0x0fec, "GeForce 710A" }, -- cgit v0.10.2 From 950950327bd63b7f54808c7028839a37899035f9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Nov 2015 09:48:13 +1000 Subject: drm/nouveau/instmem: protect instobj list with a spinlock No locking is required for the traversal of this list, as it only happens during suspend/resume where nothing else can be executing. Fixes some of the issues noticed during parallel piglit runs. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index 28bc202..40f845e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -7,6 +7,7 @@ struct nvkm_instmem { const struct nvkm_instmem_func *func; struct nvkm_subdev subdev; + spinlock_t lock; struct list_head list; u32 reserved; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 895ba74..1d7dd38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -97,7 +97,9 @@ static void * nvkm_instobj_dtor(struct nvkm_memory *memory) { struct nvkm_instobj *iobj = nvkm_instobj(memory); + spin_lock(&iobj->imem->lock); list_del(&iobj->head); + spin_unlock(&iobj->imem->lock); nvkm_memory_del(&iobj->parent); return iobj; } @@ -190,7 +192,9 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, nvkm_memory_ctor(&nvkm_instobj_func_slow, &iobj->memory); iobj->parent = memory; iobj->imem = imem; + spin_lock(&iobj->imem->lock); list_add_tail(&iobj->head, &imem->list); + spin_unlock(&iobj->imem->lock); memory = &iobj->memory; } @@ -309,5 +313,6 @@ nvkm_instmem_ctor(const struct nvkm_instmem_func *func, { nvkm_subdev_ctor(&nvkm_instmem, device, index, 0, &imem->subdev); imem->func = func; + spin_lock_init(&imem->lock); INIT_LIST_HEAD(&imem->list); } -- cgit v0.10.2 From 954329412ea45ad6b509aa26f1441941fd432823 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 19 Nov 2015 13:18:34 +1000 Subject: drm/nouveau/bios: return actual size of the buffer retrieved via _ROM Fixes detection of a failed attempt at fetching the entire ROM image in one-shot (a violation of the spec, that works a lot of the time). Tested on a HP Zbook 15 G2. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 8b8332e..d5e6938 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -367,6 +367,7 @@ static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, return -ENODEV; } obj = (union acpi_object *)buffer.pointer; + len = min(len, (int)obj->buffer.length); memcpy(bios+offset, obj->buffer.pointer, len); kfree(buffer.pointer); return len; -- cgit v0.10.2 From 7028156a91326fda29cf972f0d148badbf5ae078 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Nov 2015 05:24:32 +1000 Subject: drm/nouveau/gr/gf100-: split out per-gpc address calculation macro There's a few places where we need to access a GPC register from ucode, but outside of the falcon's io address space. To do this we need to calculate the offset based on which GPC we're executing on. This used to be done manually, but we've since found a "base" offset that can be added by the hardware. To use this, an extra bit needs to be set in the register address, which is what this macro achieves. There should be no functional change from this commit. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc index 194afe9..19d7517 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc @@ -52,10 +52,12 @@ mmio_list_base: #endif #ifdef INCLUDE_CODE +#define gpc_addr(reg,addr) /* +*/ imm32(reg,addr) /* +*/ or reg NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE #define gpc_wr32(addr,reg) /* +*/ gpc_addr($r14,addr) /* */ mov b32 $r15 reg /* -*/ imm32($r14, addr) /* -*/ or $r14 NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE /* */ call(nv_wr32) // reports an exception to the host diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h index 51f5c3c..f09afe6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h @@ -356,33 +356,33 @@ uint32_t gm107_grgpc_code[] = { 0x02687e2f, 0x002fbb00, 0x0f003fbb, - 0x8effb23f, - 0xf0501d60, - 0x8f7e01e5, + 0x1d608e3f, + 0x01e5f050, + 0x8f7effb2, 0x0c0f0000, - 0xa88effb2, - 0xe5f0501d, - 0x008f7e01, + 0x501da88e, + 0xb201e5f0, + 0x008f7eff, 0x03147e00, - 0xb23f0f00, - 0x1d608eff, - 0x01e5f050, + 0x8e3f0f00, + 0xf0501d60, + 0xffb201e5, 0x00008f7e, - 0xffb2000f, - 0x501d9c8e, - 0x7e01e5f0, + 0x9c8e000f, + 0xe5f0501d, + 0x7effb201, 0x0f00008f, 0x03147e01, - 0x8effb200, - 0xf0501da8, - 0x8f7e01e5, - 0xff0f0000, - 0x988effb2, - 0xe5f0501d, - 0x008f7e01, - 0xb2020f00, - 0x1da88eff, + 0x1da88e00, 0x01e5f050, + 0x8f7effb2, + 0xff0f0000, + 0x501d988e, + 0xb201e5f0, + 0x008f7eff, + 0x8e020f00, + 0xf0501da8, + 0xffb201e5, 0x00008f7e, 0x0003147e, 0x85050498, @@ -414,13 +414,13 @@ uint32_t gm107_grgpc_code[] = { 0x0050b7bf, 0x0142b608, 0x0fa81bf4, - 0x8effb23f, - 0xf0501d60, - 0x8f7e01e5, + 0x1d608e3f, + 0x01e5f050, + 0x8f7effb2, 0x0d0f0000, - 0xa88effb2, - 0xe5f0501d, - 0x008f7e01, + 0x501da88e, + 0xb201e5f0, + 0x008f7eff, 0x03147e00, 0x01008000, 0x0003f602, @@ -491,9 +491,9 @@ uint32_t gm107_grgpc_code[] = { 0x8000f804, 0xf6028100, 0x04bd000f, - 0xc48effb2, - 0xe5f0501d, - 0x008f7e01, + 0x501dc48e, + 0xb201e5f0, + 0x008f7eff, 0x0711f400, 0x0006217e, /* 0x0664: ctx_xfer_not_load */ @@ -505,23 +505,23 @@ uint32_t gm107_grgpc_code[] = { 0x4afc8003, 0x0002f602, 0x0c0f04bd, - 0xa88effb2, - 0xe5f0501d, - 0x008f7e01, + 0x501da88e, + 0xb201e5f0, + 0x008f7eff, 0x03147e00, - 0xb23f0f00, - 0x1d608eff, - 0x01e5f050, + 0x8e3f0f00, + 0xf0501d60, + 0xffb201e5, 0x00008f7e, - 0xffb2000f, - 0x501d9c8e, - 0x7e01e5f0, + 0x9c8e000f, + 0xe5f0501d, + 0x7effb201, 0x0f00008f, 0x03147e01, 0x01fcf000, - 0xb203f0b6, - 0x1da88eff, - 0x01e5f050, + 0x8e03f0b6, + 0xf0501da8, + 0xffb201e5, 0x00008f7e, 0xf001acf0, 0x008b02a5, @@ -553,9 +553,9 @@ uint32_t gm107_grgpc_code[] = { 0x1a12f406, /* 0x073c: ctx_xfer_post */ 0x0002277e, - 0xffb20d0f, - 0x501da88e, - 0x7e01e5f0, + 0xa88e0d0f, + 0xe5f0501d, + 0x7effb201, 0x7e00008f, /* 0x0753: ctx_xfer_done */ 0x7e000314, -- cgit v0.10.2 From ccb7b6ba076c66e1746b87ed0575e387bb2bce13 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Nov 2015 05:31:51 +1000 Subject: drm/nouveau/gr/gf117-: read NV_PGRAPH_GPC_GPM_PD_PES_TPC_ID_MASK from correct GPC Each GPCCS unit was reading the mask from GPC0, which causes problems on boards where some GPCs are missing PPCs. Part of the fix for fdo#92761. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc index 19d7517..7dacb3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc @@ -163,7 +163,7 @@ init: #if NV_PGRAPH_GPCX_UNK__SIZE > 0 // figure out which, and how many, UNKs are actually present - imm32($r14, 0x500c30) + gpc_addr($r14, 0x500c30) clear b32 $r2 clear b32 $r3 clear b32 $r4 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h index 64d07df..bb820ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h @@ -314,7 +314,7 @@ uint32_t gf117_grgpc_code[] = { 0x03f01200, 0x0002d000, 0x17f104bd, - 0x10fe0542, + 0x10fe0545, 0x0007f100, 0x0003f007, 0xbd0000d0, @@ -338,184 +338,184 @@ uint32_t gf117_grgpc_code[] = { 0x02d00103, 0xf104bd00, 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0430: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0445: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40126, -/* 0x0451: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, - 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x2fbb02d3, - 0x003fbb00, - 0x010007f1, - 0xd00203f0, + 0xe5f050e3, + 0xbd24bd01, +/* 0x0433: init_unk_loop */ + 0xf444bd34, + 0xf6b06821, + 0x0f0bf400, + 0xbb01f7f0, + 0x4ffd04f2, + 0x0130b605, +/* 0x0448: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf401, +/* 0x0454: init_unk_done */ + 0x80070380, + 0x27f10804, + 0x23f00100, + 0x0022cf02, + 0x259534bd, + 0x0007f108, + 0x0103f0c0, + 0xbd0005d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0005d0, + 0x000e9804, + 0xf5010f98, + 0xbb015021, + 0x3fbb002f, + 0x010e9800, + 0xf5020f98, + 0x98015021, + 0xeffd050e, + 0x002ebb00, + 0x98003ebb, + 0x0f98020e, + 0x5021f503, + 0x070e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0235b600, + 0xd30007f1, + 0xd00103f0, 0x04bd0003, - 0x29f024bd, - 0x0007f11f, - 0x0203f008, - 0xbd0002d0, -/* 0x0505: main */ - 0x0031f404, - 0xf00028f4, - 0x21f424d7, - 0xf401f439, - 0xf404e4b0, - 0x81fe1e18, - 0x0627f001, - 0x12fd20bd, - 0x01e4b604, - 0xfe051efd, - 0x21f50018, - 0x0ef405fa, -/* 0x0535: main_not_ctx_xfer */ - 0x10ef94d3, - 0xf501f5f0, - 0xf4037e21, -/* 0x0542: ih */ - 0x80f9c60e, - 0xf90188fe, - 0xf990f980, - 0xf9b0f9a0, - 0xf9e0f9d0, - 0xf104bdf0, - 0xf00200a7, - 0xaacf00a3, - 0x04abc400, - 0xf02c0bf4, - 0xe7f124d7, - 0xe3f01a00, - 0x00eecf00, - 0x1900f7f1, - 0xcf00f3f0, - 0x21f400ff, - 0x01e7f004, - 0x1d0007f1, - 0xd00003f0, - 0x04bd000e, -/* 0x0590: ih_no_fifo */ - 0x010007f1, - 0xd00003f0, - 0x04bd000a, - 0xe0fcf0fc, - 0xb0fcd0fc, - 0x90fca0fc, - 0x88fe80fc, - 0xf480fc00, - 0x01f80032, -/* 0x05b4: hub_barrier_done */ - 0x9801f7f0, - 0xfebb040e, - 0x02ffb904, - 0x9418e7f1, - 0xf440e3f0, - 0x00f89d21, -/* 0x05cc: ctx_redswitch */ - 0xf120f7f0, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb90834, + 0xd321f502, + 0x002fbb02, + 0xf1003fbb, + 0xf0010007, + 0x03d00203, + 0xbd04bd00, + 0x1f29f024, + 0x080007f1, + 0xd00203f0, + 0x04bd0002, +/* 0x0508: main */ + 0xf40031f4, + 0xd7f00028, + 0x3921f424, + 0xb0f401f4, + 0x18f404e4, + 0x0181fe1e, + 0xbd0627f0, + 0x0412fd20, + 0xfd01e4b6, + 0x18fe051e, + 0xfd21f500, + 0xd30ef405, +/* 0x0538: main_not_ctx_xfer */ + 0xf010ef94, + 0x21f501f5, + 0x0ef4037e, +/* 0x0545: ih */ + 0xfe80f9c6, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0xa7f104bd, + 0xa3f00200, + 0x00aacf00, + 0xf404abc4, + 0xd7f02c0b, + 0x00e7f124, + 0x00e3f01a, + 0xf100eecf, + 0xf01900f7, + 0xffcf00f3, + 0x0421f400, + 0xf101e7f0, + 0xf01d0007, + 0x0ed00003, +/* 0x0593: ih_no_fifo */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x05b7: hub_barrier_done */ + 0xf001f800, + 0x0e9801f7, + 0x04febb04, + 0xf102ffb9, + 0xf09418e7, + 0x21f440e3, +/* 0x05cf: ctx_redswitch */ + 0xf000f89d, + 0x07f120f7, + 0x03f08500, + 0x000fd001, + 0xe7f004bd, +/* 0x05e1: ctx_redswitch_delay */ + 0x01e2b608, + 0xf1fd1bf4, + 0xf10800f5, + 0xf10200f5, 0xf0850007, 0x0fd00103, - 0xf004bd00, -/* 0x05de: ctx_redswitch_delay */ - 0xe2b608e7, - 0xfd1bf401, - 0x0800f5f1, - 0x0200f5f1, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05fa: ctx_xfer */ - 0x07f100f8, - 0x03f08100, - 0x000fd002, - 0x11f404bd, - 0xcc21f507, -/* 0x060d: ctx_xfer_not_load */ - 0x6a21f505, - 0xf124bd02, - 0xf047fc07, - 0x02d00203, - 0xf004bd00, - 0x20b6012c, - 0xfc07f103, - 0x0203f04a, - 0xbd0002d0, - 0x01acf004, - 0xf102a5f0, - 0xf00000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98000c, - 0x00e7f001, - 0x016f21f5, - 0xf101acf0, - 0xf04000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98010c, - 0x060f9802, - 0x0800e7f1, - 0x016f21f5, + 0xf804bd00, +/* 0x05fd: ctx_xfer */ + 0x0007f100, + 0x0203f081, + 0xbd000fd0, + 0x0711f404, + 0x05cf21f5, +/* 0x0610: ctx_xfer_not_load */ + 0x026a21f5, + 0x07f124bd, + 0x03f047fc, + 0x0002d002, + 0x2cf004bd, + 0x0320b601, + 0x4afc07f1, + 0xd00203f0, + 0x04bd0002, 0xf001acf0, - 0xb7f104a5, - 0xb3f03000, + 0xb7f102a5, + 0xb3f00000, 0x040c9850, 0xbb0fc4b6, 0x0c9800bc, - 0x030d9802, - 0xf1080f98, - 0xf50200e7, - 0xf5016f21, - 0xf4025e21, - 0x12f40601, -/* 0x06a9: ctx_xfer_post */ - 0x7f21f507, -/* 0x06ad: ctx_xfer_done */ - 0xb421f502, - 0x0000f805, - 0x00000000, + 0x010d9800, + 0xf500e7f0, + 0xf0016f21, + 0xb7f101ac, + 0xb3f04000, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0xf1060f98, + 0xf50800e7, + 0xf0016f21, + 0xa5f001ac, + 0x00b7f104, + 0x50b3f030, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0xe7f1080f, + 0x21f50200, + 0x21f5016f, + 0x01f4025e, + 0x0712f406, +/* 0x06ac: ctx_xfer_post */ + 0x027f21f5, +/* 0x06b0: ctx_xfer_done */ + 0x05b721f5, + 0x000000f8, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h index 2f59643..911976d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h @@ -314,7 +314,7 @@ uint32_t gk104_grgpc_code[] = { 0x03f01200, 0x0002d000, 0x17f104bd, - 0x10fe0542, + 0x10fe0545, 0x0007f100, 0x0003f007, 0xbd0000d0, @@ -338,184 +338,184 @@ uint32_t gk104_grgpc_code[] = { 0x02d00103, 0xf104bd00, 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0430: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0445: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40126, -/* 0x0451: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, - 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x2fbb02d3, - 0x003fbb00, - 0x010007f1, - 0xd00203f0, + 0xe5f050e3, + 0xbd24bd01, +/* 0x0433: init_unk_loop */ + 0xf444bd34, + 0xf6b06821, + 0x0f0bf400, + 0xbb01f7f0, + 0x4ffd04f2, + 0x0130b605, +/* 0x0448: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf401, +/* 0x0454: init_unk_done */ + 0x80070380, + 0x27f10804, + 0x23f00100, + 0x0022cf02, + 0x259534bd, + 0x0007f108, + 0x0103f0c0, + 0xbd0005d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0005d0, + 0x000e9804, + 0xf5010f98, + 0xbb015021, + 0x3fbb002f, + 0x010e9800, + 0xf5020f98, + 0x98015021, + 0xeffd050e, + 0x002ebb00, + 0x98003ebb, + 0x0f98020e, + 0x5021f503, + 0x070e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0235b600, + 0xd30007f1, + 0xd00103f0, 0x04bd0003, - 0x29f024bd, - 0x0007f11f, - 0x0203f008, - 0xbd0002d0, -/* 0x0505: main */ - 0x0031f404, - 0xf00028f4, - 0x21f424d7, - 0xf401f439, - 0xf404e4b0, - 0x81fe1e18, - 0x0627f001, - 0x12fd20bd, - 0x01e4b604, - 0xfe051efd, - 0x21f50018, - 0x0ef405fa, -/* 0x0535: main_not_ctx_xfer */ - 0x10ef94d3, - 0xf501f5f0, - 0xf4037e21, -/* 0x0542: ih */ - 0x80f9c60e, - 0xf90188fe, - 0xf990f980, - 0xf9b0f9a0, - 0xf9e0f9d0, - 0xf104bdf0, - 0xf00200a7, - 0xaacf00a3, - 0x04abc400, - 0xf02c0bf4, - 0xe7f124d7, - 0xe3f01a00, - 0x00eecf00, - 0x1900f7f1, - 0xcf00f3f0, - 0x21f400ff, - 0x01e7f004, - 0x1d0007f1, - 0xd00003f0, - 0x04bd000e, -/* 0x0590: ih_no_fifo */ - 0x010007f1, - 0xd00003f0, - 0x04bd000a, - 0xe0fcf0fc, - 0xb0fcd0fc, - 0x90fca0fc, - 0x88fe80fc, - 0xf480fc00, - 0x01f80032, -/* 0x05b4: hub_barrier_done */ - 0x9801f7f0, - 0xfebb040e, - 0x02ffb904, - 0x9418e7f1, - 0xf440e3f0, - 0x00f89d21, -/* 0x05cc: ctx_redswitch */ - 0xf120f7f0, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb90834, + 0xd321f502, + 0x002fbb02, + 0xf1003fbb, + 0xf0010007, + 0x03d00203, + 0xbd04bd00, + 0x1f29f024, + 0x080007f1, + 0xd00203f0, + 0x04bd0002, +/* 0x0508: main */ + 0xf40031f4, + 0xd7f00028, + 0x3921f424, + 0xb0f401f4, + 0x18f404e4, + 0x0181fe1e, + 0xbd0627f0, + 0x0412fd20, + 0xfd01e4b6, + 0x18fe051e, + 0xfd21f500, + 0xd30ef405, +/* 0x0538: main_not_ctx_xfer */ + 0xf010ef94, + 0x21f501f5, + 0x0ef4037e, +/* 0x0545: ih */ + 0xfe80f9c6, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0xa7f104bd, + 0xa3f00200, + 0x00aacf00, + 0xf404abc4, + 0xd7f02c0b, + 0x00e7f124, + 0x00e3f01a, + 0xf100eecf, + 0xf01900f7, + 0xffcf00f3, + 0x0421f400, + 0xf101e7f0, + 0xf01d0007, + 0x0ed00003, +/* 0x0593: ih_no_fifo */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x05b7: hub_barrier_done */ + 0xf001f800, + 0x0e9801f7, + 0x04febb04, + 0xf102ffb9, + 0xf09418e7, + 0x21f440e3, +/* 0x05cf: ctx_redswitch */ + 0xf000f89d, + 0x07f120f7, + 0x03f08500, + 0x000fd001, + 0xe7f004bd, +/* 0x05e1: ctx_redswitch_delay */ + 0x01e2b608, + 0xf1fd1bf4, + 0xf10800f5, + 0xf10200f5, 0xf0850007, 0x0fd00103, - 0xf004bd00, -/* 0x05de: ctx_redswitch_delay */ - 0xe2b608e7, - 0xfd1bf401, - 0x0800f5f1, - 0x0200f5f1, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05fa: ctx_xfer */ - 0x07f100f8, - 0x03f08100, - 0x000fd002, - 0x11f404bd, - 0xcc21f507, -/* 0x060d: ctx_xfer_not_load */ - 0x6a21f505, - 0xf124bd02, - 0xf047fc07, - 0x02d00203, - 0xf004bd00, - 0x20b6012c, - 0xfc07f103, - 0x0203f04a, - 0xbd0002d0, - 0x01acf004, - 0xf102a5f0, - 0xf00000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98000c, - 0x00e7f001, - 0x016f21f5, - 0xf101acf0, - 0xf04000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98010c, - 0x060f9802, - 0x0800e7f1, - 0x016f21f5, + 0xf804bd00, +/* 0x05fd: ctx_xfer */ + 0x0007f100, + 0x0203f081, + 0xbd000fd0, + 0x0711f404, + 0x05cf21f5, +/* 0x0610: ctx_xfer_not_load */ + 0x026a21f5, + 0x07f124bd, + 0x03f047fc, + 0x0002d002, + 0x2cf004bd, + 0x0320b601, + 0x4afc07f1, + 0xd00203f0, + 0x04bd0002, 0xf001acf0, - 0xb7f104a5, - 0xb3f03000, + 0xb7f102a5, + 0xb3f00000, 0x040c9850, 0xbb0fc4b6, 0x0c9800bc, - 0x030d9802, - 0xf1080f98, - 0xf50200e7, - 0xf5016f21, - 0xf4025e21, - 0x12f40601, -/* 0x06a9: ctx_xfer_post */ - 0x7f21f507, -/* 0x06ad: ctx_xfer_done */ - 0xb421f502, - 0x0000f805, - 0x00000000, + 0x010d9800, + 0xf500e7f0, + 0xf0016f21, + 0xb7f101ac, + 0xb3f04000, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0xf1060f98, + 0xf50800e7, + 0xf0016f21, + 0xa5f001ac, + 0x00b7f104, + 0x50b3f030, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0xe7f1080f, + 0x21f50200, + 0x21f5016f, + 0x01f4025e, + 0x0712f406, +/* 0x06ac: ctx_xfer_post */ + 0x027f21f5, +/* 0x06b0: ctx_xfer_done */ + 0x05b721f5, + 0x000000f8, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h index ee8e54d..1c6e11b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h @@ -314,7 +314,7 @@ uint32_t gk110_grgpc_code[] = { 0x03f01200, 0x0002d000, 0x17f104bd, - 0x10fe0542, + 0x10fe0545, 0x0007f100, 0x0003f007, 0xbd0000d0, @@ -338,184 +338,184 @@ uint32_t gk110_grgpc_code[] = { 0x02d00103, 0xf104bd00, 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0430: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0445: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40226, -/* 0x0451: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, - 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x2fbb02d3, - 0x003fbb00, - 0x010007f1, - 0xd00203f0, + 0xe5f050e3, + 0xbd24bd01, +/* 0x0433: init_unk_loop */ + 0xf444bd34, + 0xf6b06821, + 0x0f0bf400, + 0xbb01f7f0, + 0x4ffd04f2, + 0x0130b605, +/* 0x0448: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf402, +/* 0x0454: init_unk_done */ + 0x80070380, + 0x27f10804, + 0x23f00100, + 0x0022cf02, + 0x259534bd, + 0x0007f108, + 0x0103f0c0, + 0xbd0005d0, + 0x0007f104, + 0x0103f0c1, + 0xbd0005d0, + 0x000e9804, + 0xf5010f98, + 0xbb015021, + 0x3fbb002f, + 0x010e9800, + 0xf5020f98, + 0x98015021, + 0xeffd050e, + 0x002ebb00, + 0x98003ebb, + 0x0f98020e, + 0x5021f503, + 0x070e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0235b600, + 0xd30007f1, + 0xd00103f0, 0x04bd0003, - 0x29f024bd, - 0x0007f11f, - 0x0203f030, - 0xbd0002d0, -/* 0x0505: main */ - 0x0031f404, - 0xf00028f4, - 0x21f424d7, - 0xf401f439, - 0xf404e4b0, - 0x81fe1e18, - 0x0627f001, - 0x12fd20bd, - 0x01e4b604, - 0xfe051efd, - 0x21f50018, - 0x0ef405fa, -/* 0x0535: main_not_ctx_xfer */ - 0x10ef94d3, - 0xf501f5f0, - 0xf4037e21, -/* 0x0542: ih */ - 0x80f9c60e, - 0xf90188fe, - 0xf990f980, - 0xf9b0f9a0, - 0xf9e0f9d0, - 0xf104bdf0, - 0xf00200a7, - 0xaacf00a3, - 0x04abc400, - 0xf02c0bf4, - 0xe7f124d7, - 0xe3f01a00, - 0x00eecf00, - 0x1900f7f1, - 0xcf00f3f0, - 0x21f400ff, - 0x01e7f004, - 0x1d0007f1, - 0xd00003f0, - 0x04bd000e, -/* 0x0590: ih_no_fifo */ - 0x010007f1, - 0xd00003f0, - 0x04bd000a, - 0xe0fcf0fc, - 0xb0fcd0fc, - 0x90fca0fc, - 0x88fe80fc, - 0xf480fc00, - 0x01f80032, -/* 0x05b4: hub_barrier_done */ - 0x9801f7f0, - 0xfebb040e, - 0x02ffb904, - 0x9418e7f1, - 0xf440e3f0, - 0x00f89d21, -/* 0x05cc: ctx_redswitch */ - 0xf120f7f0, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb90834, + 0xd321f502, + 0x002fbb02, + 0xf1003fbb, + 0xf0010007, + 0x03d00203, + 0xbd04bd00, + 0x1f29f024, + 0x300007f1, + 0xd00203f0, + 0x04bd0002, +/* 0x0508: main */ + 0xf40031f4, + 0xd7f00028, + 0x3921f424, + 0xb0f401f4, + 0x18f404e4, + 0x0181fe1e, + 0xbd0627f0, + 0x0412fd20, + 0xfd01e4b6, + 0x18fe051e, + 0xfd21f500, + 0xd30ef405, +/* 0x0538: main_not_ctx_xfer */ + 0xf010ef94, + 0x21f501f5, + 0x0ef4037e, +/* 0x0545: ih */ + 0xfe80f9c6, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0xa7f104bd, + 0xa3f00200, + 0x00aacf00, + 0xf404abc4, + 0xd7f02c0b, + 0x00e7f124, + 0x00e3f01a, + 0xf100eecf, + 0xf01900f7, + 0xffcf00f3, + 0x0421f400, + 0xf101e7f0, + 0xf01d0007, + 0x0ed00003, +/* 0x0593: ih_no_fifo */ + 0xf104bd00, + 0xf0010007, + 0x0ad00003, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x05b7: hub_barrier_done */ + 0xf001f800, + 0x0e9801f7, + 0x04febb04, + 0xf102ffb9, + 0xf09418e7, + 0x21f440e3, +/* 0x05cf: ctx_redswitch */ + 0xf000f89d, + 0x07f120f7, + 0x03f08500, + 0x000fd001, + 0xe7f004bd, +/* 0x05e1: ctx_redswitch_delay */ + 0x01e2b608, + 0xf1fd1bf4, + 0xf10800f5, + 0xf10200f5, 0xf0850007, 0x0fd00103, - 0xf004bd00, -/* 0x05de: ctx_redswitch_delay */ - 0xe2b608e7, - 0xfd1bf401, - 0x0800f5f1, - 0x0200f5f1, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05fa: ctx_xfer */ - 0x07f100f8, - 0x03f08100, - 0x000fd002, - 0x11f404bd, - 0xcc21f507, -/* 0x060d: ctx_xfer_not_load */ - 0x6a21f505, - 0xf124bd02, - 0xf047fc07, - 0x02d00203, - 0xf004bd00, - 0x20b6012c, - 0xfc07f103, - 0x0203f04a, - 0xbd0002d0, - 0x01acf004, - 0xf102a5f0, - 0xf00000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98000c, - 0x00e7f001, - 0x016f21f5, - 0xf101acf0, - 0xf04000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98010c, - 0x060f9802, - 0x0800e7f1, - 0x016f21f5, + 0xf804bd00, +/* 0x05fd: ctx_xfer */ + 0x0007f100, + 0x0203f081, + 0xbd000fd0, + 0x0711f404, + 0x05cf21f5, +/* 0x0610: ctx_xfer_not_load */ + 0x026a21f5, + 0x07f124bd, + 0x03f047fc, + 0x0002d002, + 0x2cf004bd, + 0x0320b601, + 0x4afc07f1, + 0xd00203f0, + 0x04bd0002, 0xf001acf0, - 0xb7f104a5, - 0xb3f03000, + 0xb7f102a5, + 0xb3f00000, 0x040c9850, 0xbb0fc4b6, 0x0c9800bc, - 0x030d9802, - 0xf1080f98, - 0xf50200e7, - 0xf5016f21, - 0xf4025e21, - 0x12f40601, -/* 0x06a9: ctx_xfer_post */ - 0x7f21f507, -/* 0x06ad: ctx_xfer_done */ - 0xb421f502, - 0x0000f805, - 0x00000000, + 0x010d9800, + 0xf500e7f0, + 0xf0016f21, + 0xb7f101ac, + 0xb3f04000, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0xf1060f98, + 0xf50800e7, + 0xf0016f21, + 0xa5f001ac, + 0x00b7f104, + 0x50b3f030, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0xe7f1080f, + 0x21f50200, + 0x21f5016f, + 0x01f4025e, + 0x0712f406, +/* 0x06ac: ctx_xfer_post */ + 0x027f21f5, +/* 0x06b0: ctx_xfer_done */ + 0x05b721f5, + 0x000000f8, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h index fbcc342..84af7ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h @@ -276,7 +276,7 @@ uint32_t gk208_grgpc_code[] = { 0x02020014, 0xf6120040, 0x04bd0002, - 0xfe048141, + 0xfe048441, 0x00400010, 0x0000f607, 0x040204bd, @@ -295,165 +295,165 @@ uint32_t gk208_grgpc_code[] = { 0x01c90080, 0xbd0002f6, 0x0c308e04, - 0xbd24bd50, -/* 0x0383: init_unk_loop */ - 0x7e44bd34, - 0xb0000065, - 0x0bf400f6, - 0xbb010f0e, - 0x4ffd04f2, - 0x0130b605, -/* 0x0398: init_unk_next */ - 0xb60120b6, - 0x26b004e0, - 0xe21bf401, -/* 0x03a4: init_unk_done */ - 0xb50703b5, - 0x00820804, - 0x22cf0201, - 0x9534bd00, - 0x00800825, - 0x05f601c0, - 0x8004bd00, - 0xf601c100, - 0x04bd0005, - 0x98000e98, - 0x207e010f, - 0x2fbb0001, - 0x003fbb00, - 0x98010e98, - 0x207e020f, - 0x0e980001, - 0x00effd05, - 0xbb002ebb, - 0x0e98003e, - 0x030f9802, - 0x0001207e, - 0xfd070e98, - 0x2ebb00ef, - 0x003ebb00, - 0x800235b6, - 0xf601d300, - 0x04bd0003, - 0xb60825b6, - 0x20b60635, - 0x0130b601, - 0xb60824b6, - 0x2fb20834, - 0x0002687e, - 0xbb002fbb, - 0x0080003f, - 0x03f60201, - 0xbd04bd00, - 0x1f29f024, - 0x02300080, - 0xbd0002f6, -/* 0x0445: main */ - 0x0031f404, - 0x0d0028f4, - 0x00377e24, - 0xf401f400, - 0xf404e4b0, - 0x81fe1d18, - 0xbd060201, - 0x0412fd20, - 0xfd01e4b6, - 0x18fe051e, - 0x05187e00, - 0xd40ef400, -/* 0x0474: main_not_ctx_xfer */ - 0xf010ef94, - 0xf87e01f5, - 0x0ef40002, -/* 0x0481: ih */ - 0xfe80f9c7, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x004a04bd, - 0x00aacf02, - 0xf404abc4, - 0x240d1f0b, - 0xcf1a004e, - 0x004f00ee, - 0x00ffcf19, - 0x0000047e, - 0x0040010e, - 0x000ef61d, -/* 0x04be: ih_no_fifo */ - 0x004004bd, - 0x000af601, - 0xf0fc04bd, - 0xd0fce0fc, - 0xa0fcb0fc, - 0x80fc90fc, - 0xfc0088fe, - 0x0032f480, -/* 0x04de: hub_barrier_done */ - 0x010f01f8, - 0xbb040e98, - 0xffb204fe, - 0x4094188e, - 0x00008f7e, -/* 0x04f2: ctx_redswitch */ - 0x200f00f8, + 0x01e5f050, + 0x34bd24bd, +/* 0x0386: init_unk_loop */ + 0x657e44bd, + 0xf6b00000, + 0x0e0bf400, + 0xf2bb010f, + 0x054ffd04, +/* 0x039b: init_unk_next */ + 0xb60130b6, + 0xe0b60120, + 0x0126b004, +/* 0x03a7: init_unk_done */ + 0xb5e21bf4, + 0x04b50703, + 0x01008208, + 0x0022cf02, + 0x259534bd, + 0xc0008008, + 0x0005f601, + 0x008004bd, + 0x05f601c1, + 0x9804bd00, + 0x0f98000e, + 0x01207e01, + 0x002fbb00, + 0x98003fbb, + 0x0f98010e, + 0x01207e02, + 0x050e9800, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0x7e030f98, + 0x98000120, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x00800235, + 0x03f601d3, + 0xb604bd00, + 0x35b60825, + 0x0120b606, + 0xb60130b6, + 0x34b60824, + 0x7e2fb208, + 0xbb000268, + 0x3fbb002f, + 0x01008000, + 0x0003f602, + 0x24bd04bd, + 0x801f29f0, + 0xf6023000, + 0x04bd0002, +/* 0x0448: main */ + 0xf40031f4, + 0x240d0028, + 0x0000377e, + 0xb0f401f4, + 0x18f404e4, + 0x0181fe1d, + 0x20bd0602, + 0xb60412fd, + 0x1efd01e4, + 0x0018fe05, + 0x00051b7e, +/* 0x0477: main_not_ctx_xfer */ + 0x94d40ef4, + 0xf5f010ef, + 0x02f87e01, + 0xc70ef400, +/* 0x0484: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x02004a04, + 0xc400aacf, + 0x0bf404ab, + 0x4e240d1f, + 0xeecf1a00, + 0x19004f00, + 0x7e00ffcf, + 0x0e000004, + 0x1d004001, + 0xbd000ef6, +/* 0x04c1: ih_no_fifo */ + 0x01004004, + 0xbd000af6, + 0xfcf0fc04, + 0xfcd0fce0, + 0xfca0fcb0, + 0xfe80fc90, + 0x80fc0088, + 0xf80032f4, +/* 0x04e1: hub_barrier_done */ + 0x98010f01, + 0xfebb040e, + 0x8effb204, + 0x7e409418, + 0xf800008f, +/* 0x04f5: ctx_redswitch */ + 0x80200f00, + 0xf6018500, + 0x04bd000f, +/* 0x0502: ctx_redswitch_delay */ + 0xe2b6080e, + 0xfd1bf401, + 0x0800f5f1, + 0x0200f5f1, 0x01850080, 0xbd000ff6, -/* 0x04ff: ctx_redswitch_delay */ - 0xb6080e04, - 0x1bf401e2, - 0x00f5f1fd, - 0x00f5f108, - 0x85008002, - 0x000ff601, - 0x00f804bd, -/* 0x0518: ctx_xfer */ - 0x02810080, - 0xbd000ff6, - 0x0711f404, - 0x0004f27e, -/* 0x0528: ctx_xfer_not_load */ - 0x0002167e, - 0xfc8024bd, - 0x02f60247, - 0xf004bd00, - 0x20b6012c, - 0x4afc8003, +/* 0x051b: ctx_xfer */ + 0x8000f804, + 0xf6028100, + 0x04bd000f, + 0x7e0711f4, +/* 0x052b: ctx_xfer_not_load */ + 0x7e0004f5, + 0xbd000216, + 0x47fc8024, 0x0002f602, - 0xacf004bd, - 0x02a5f001, - 0x5000008b, - 0xb6040c98, - 0xbcbb0fc4, - 0x000c9800, - 0x0e010d98, - 0x013d7e00, - 0x01acf000, - 0x5040008b, - 0xb6040c98, - 0xbcbb0fc4, - 0x010c9800, - 0x98020d98, - 0x004e060f, - 0x013d7e08, - 0x01acf000, - 0x8b04a5f0, - 0x98503000, + 0x2cf004bd, + 0x0320b601, + 0x024afc80, + 0xbd0002f6, + 0x01acf004, + 0x8b02a5f0, + 0x98500000, 0xc4b6040c, 0x00bcbb0f, - 0x98020c98, - 0x0f98030d, - 0x02004e08, + 0x98000c98, + 0x000e010d, 0x00013d7e, - 0x00020a7e, - 0xf40601f4, -/* 0x05b2: ctx_xfer_post */ - 0x277e0712, -/* 0x05b6: ctx_xfer_done */ - 0xde7e0002, - 0x00f80004, - 0x00000000, + 0x8b01acf0, + 0x98504000, + 0xc4b6040c, + 0x00bcbb0f, + 0x98010c98, + 0x0f98020d, + 0x08004e06, + 0x00013d7e, + 0xf001acf0, + 0x008b04a5, + 0x0c985030, + 0x0fc4b604, + 0x9800bcbb, + 0x0d98020c, + 0x080f9803, + 0x7e02004e, + 0x7e00013d, + 0xf400020a, + 0x12f40601, +/* 0x05b5: ctx_xfer_post */ + 0x02277e07, +/* 0x05b9: ctx_xfer_done */ + 0x04e17e00, + 0x0000f800, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h index f09afe6..11bf363 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h @@ -289,7 +289,7 @@ uint32_t gm107_grgpc_code[] = { 0x020014fe, 0x12004002, 0xbd0002f6, - 0x05b04104, + 0x05b34104, 0x400010fe, 0x00f60700, 0x0204bd00, @@ -308,259 +308,259 @@ uint32_t gm107_grgpc_code[] = { 0xc900800f, 0x0002f601, 0x308e04bd, - 0x24bd500c, - 0x44bd34bd, -/* 0x03b0: init_unk_loop */ - 0x0000657e, - 0xf400f6b0, - 0x010f0e0b, - 0xfd04f2bb, - 0x30b6054f, -/* 0x03c5: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40226, -/* 0x03d1: init_unk_done */ - 0x0703b5e2, - 0x820804b5, - 0xcf020100, - 0x34bd0022, - 0x80082595, - 0xf601c000, + 0xe5f0500c, + 0xbd24bd01, +/* 0x03b3: init_unk_loop */ + 0x7e44bd34, + 0xb0000065, + 0x0bf400f6, + 0xbb010f0e, + 0x4ffd04f2, + 0x0130b605, +/* 0x03c8: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf402, +/* 0x03d4: init_unk_done */ + 0xb50703b5, + 0x00820804, + 0x22cf0201, + 0x9534bd00, + 0x00800825, + 0x05f601c0, + 0x8004bd00, + 0xf601c100, 0x04bd0005, - 0x01c10080, - 0xbd0005f6, - 0x000e9804, - 0x7e010f98, - 0xbb000120, - 0x3fbb002f, - 0x010e9800, - 0x7e020f98, - 0x98000120, - 0xeffd050e, - 0x002ebb00, - 0x98003ebb, - 0x0f98020e, - 0x01207e03, - 0x070e9800, - 0xbb00effd, - 0x3ebb002e, - 0x0235b600, - 0x01d30080, - 0xbd0003f6, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb20834b6, - 0x02687e2f, - 0x002fbb00, - 0x0f003fbb, - 0x1d608e3f, - 0x01e5f050, - 0x8f7effb2, - 0x0c0f0000, - 0x501da88e, + 0x98000e98, + 0x207e010f, + 0x2fbb0001, + 0x003fbb00, + 0x98010e98, + 0x207e020f, + 0x0e980001, + 0x00effd05, + 0xbb002ebb, + 0x0e98003e, + 0x030f9802, + 0x0001207e, + 0xfd070e98, + 0x2ebb00ef, + 0x003ebb00, + 0x800235b6, + 0xf601d300, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb20834, + 0x0002687e, + 0xbb002fbb, + 0x3f0f003f, + 0x501d608e, 0xb201e5f0, 0x008f7eff, - 0x03147e00, - 0x8e3f0f00, - 0xf0501d60, + 0x8e0c0f00, + 0xf0501da8, 0xffb201e5, 0x00008f7e, - 0x9c8e000f, + 0x0003147e, + 0x608e3f0f, 0xe5f0501d, 0x7effb201, 0x0f00008f, - 0x03147e01, - 0x1da88e00, + 0x1d9c8e00, 0x01e5f050, 0x8f7effb2, - 0xff0f0000, - 0x501d988e, + 0x010f0000, + 0x0003147e, + 0x501da88e, 0xb201e5f0, 0x008f7eff, - 0x8e020f00, - 0xf0501da8, + 0x8eff0f00, + 0xf0501d98, 0xffb201e5, 0x00008f7e, - 0x0003147e, - 0x85050498, - 0x98504000, - 0x64b60406, - 0x0056bb0f, -/* 0x04e0: tpc_strand_init_tpc_loop */ - 0x05705eb8, - 0x00657e00, - 0xbdf6b200, -/* 0x04ed: tpc_strand_init_idx_loop */ - 0x605eb874, - 0x7fb20005, - 0x00008f7e, - 0x05885eb8, - 0x082f9500, - 0x00008f7e, - 0x058c5eb8, - 0x082f9500, - 0x00008f7e, - 0x05905eb8, - 0x00657e00, - 0x06f5b600, - 0xb601f0b6, - 0x2fbb08f4, - 0x003fbb00, - 0xb60170b6, - 0x1bf40162, - 0x0050b7bf, - 0x0142b608, - 0x0fa81bf4, - 0x1d608e3f, - 0x01e5f050, - 0x8f7effb2, - 0x0d0f0000, - 0x501da88e, + 0xa88e020f, + 0xe5f0501d, + 0x7effb201, + 0x7e00008f, + 0x98000314, + 0x00850504, + 0x06985040, + 0x0f64b604, +/* 0x04e3: tpc_strand_init_tpc_loop */ + 0xb80056bb, + 0x0005705e, + 0x0000657e, + 0x74bdf6b2, +/* 0x04f0: tpc_strand_init_idx_loop */ + 0x05605eb8, + 0x7e7fb200, + 0xb800008f, + 0x0005885e, + 0x7e082f95, + 0xb800008f, + 0x00058c5e, + 0x7e082f95, + 0xb800008f, + 0x0005905e, + 0x0000657e, + 0xb606f5b6, + 0xf4b601f0, + 0x002fbb08, + 0xb6003fbb, + 0x62b60170, + 0xbf1bf401, + 0x080050b7, + 0xf40142b6, + 0x3f0fa81b, + 0x501d608e, 0xb201e5f0, 0x008f7eff, - 0x03147e00, - 0x01008000, - 0x0003f602, - 0x24bd04bd, - 0x801f29f0, - 0xf6023000, - 0x04bd0002, -/* 0x0574: main */ - 0xf40031f4, - 0x240d0028, - 0x0000377e, - 0xb0f401f4, - 0x18f404e4, - 0x0181fe1d, - 0x20bd0602, - 0xb60412fd, - 0x1efd01e4, - 0x0018fe05, - 0x0006477e, -/* 0x05a3: main_not_ctx_xfer */ - 0x94d40ef4, - 0xf5f010ef, - 0x02f87e01, - 0xc70ef400, -/* 0x05b0: ih */ - 0x88fe80f9, - 0xf980f901, - 0xf9a0f990, - 0xf9d0f9b0, - 0xbdf0f9e0, - 0x02004a04, - 0xc400aacf, - 0x0bf404ab, - 0x4e240d1f, - 0xeecf1a00, - 0x19004f00, - 0x7e00ffcf, - 0x0e000004, - 0x1d004001, - 0xbd000ef6, -/* 0x05ed: ih_no_fifo */ - 0x01004004, - 0xbd000af6, - 0xfcf0fc04, - 0xfcd0fce0, - 0xfca0fcb0, - 0xfe80fc90, - 0x80fc0088, - 0xf80032f4, -/* 0x060d: hub_barrier_done */ - 0x98010f01, - 0xfebb040e, - 0x8effb204, - 0x7e409418, - 0xf800008f, -/* 0x0621: ctx_redswitch */ - 0x80200f00, + 0x8e0d0f00, + 0xf0501da8, + 0xffb201e5, + 0x00008f7e, + 0x0003147e, + 0x02010080, + 0xbd0003f6, + 0xf024bd04, + 0x00801f29, + 0x02f60230, +/* 0x0577: main */ + 0xf404bd00, + 0x28f40031, + 0x7e240d00, + 0xf4000037, + 0xe4b0f401, + 0x1d18f404, + 0x020181fe, + 0xfd20bd06, + 0xe4b60412, + 0x051efd01, + 0x7e0018fe, + 0xf400064a, +/* 0x05a6: main_not_ctx_xfer */ + 0xef94d40e, + 0x01f5f010, + 0x0002f87e, +/* 0x05b3: ih */ + 0xf9c70ef4, + 0x0188fe80, + 0x90f980f9, + 0xb0f9a0f9, + 0xe0f9d0f9, + 0x04bdf0f9, + 0xcf02004a, + 0xabc400aa, + 0x1f0bf404, + 0x004e240d, + 0x00eecf1a, + 0xcf19004f, + 0x047e00ff, + 0x010e0000, + 0xf61d0040, + 0x04bd000e, +/* 0x05f0: ih_no_fifo */ + 0xf6010040, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x0610: hub_barrier_done */ + 0x0e98010f, + 0x04febb04, + 0x188effb2, + 0x8f7e4094, + 0x00f80000, +/* 0x0624: ctx_redswitch */ + 0x0080200f, + 0x0ff60185, + 0x0e04bd00, +/* 0x0631: ctx_redswitch_delay */ + 0x01e2b608, + 0xf1fd1bf4, + 0xf10800f5, + 0x800200f5, 0xf6018500, 0x04bd000f, -/* 0x062e: ctx_redswitch_delay */ - 0xe2b6080e, - 0xfd1bf401, - 0x0800f5f1, - 0x0200f5f1, - 0x01850080, - 0xbd000ff6, -/* 0x0647: ctx_xfer */ - 0x8000f804, - 0xf6028100, - 0x04bd000f, - 0x501dc48e, - 0xb201e5f0, - 0x008f7eff, - 0x0711f400, - 0x0006217e, -/* 0x0664: ctx_xfer_not_load */ - 0x0002167e, - 0xfc8024bd, - 0x02f60247, - 0xf004bd00, - 0x20b6012c, - 0x4afc8003, +/* 0x064a: ctx_xfer */ + 0x008000f8, + 0x0ff60281, + 0x8e04bd00, + 0xf0501dc4, + 0xffb201e5, + 0x00008f7e, + 0x7e0711f4, +/* 0x0667: ctx_xfer_not_load */ + 0x7e000624, + 0xbd000216, + 0x47fc8024, 0x0002f602, - 0x0c0f04bd, - 0x501da88e, - 0xb201e5f0, - 0x008f7eff, - 0x03147e00, - 0x8e3f0f00, - 0xf0501d60, + 0x2cf004bd, + 0x0320b601, + 0x024afc80, + 0xbd0002f6, + 0x8e0c0f04, + 0xf0501da8, 0xffb201e5, 0x00008f7e, - 0x9c8e000f, + 0x0003147e, + 0x608e3f0f, 0xe5f0501d, 0x7effb201, 0x0f00008f, - 0x03147e01, - 0x01fcf000, - 0x8e03f0b6, - 0xf0501da8, - 0xffb201e5, - 0x00008f7e, - 0xf001acf0, - 0x008b02a5, - 0x0c985000, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98000c, - 0x7e000e01, - 0xf000013d, - 0x008b01ac, - 0x0c985040, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98010c, - 0x060f9802, - 0x7e08004e, - 0xf000013d, + 0x1d9c8e00, + 0x01e5f050, + 0x8f7effb2, + 0x010f0000, + 0x0003147e, + 0xb601fcf0, + 0xa88e03f0, + 0xe5f0501d, + 0x7effb201, + 0xf000008f, 0xa5f001ac, - 0x30008b04, + 0x00008b02, 0x040c9850, 0xbb0fc4b6, 0x0c9800bc, - 0x030d9802, - 0x4e080f98, - 0x3d7e0200, - 0x0a7e0001, - 0x147e0002, - 0x01f40003, - 0x1a12f406, -/* 0x073c: ctx_xfer_post */ - 0x0002277e, - 0xa88e0d0f, - 0xe5f0501d, - 0x7effb201, - 0x7e00008f, -/* 0x0753: ctx_xfer_done */ - 0x7e000314, - 0xf800060d, - 0x00000000, + 0x010d9800, + 0x3d7e000e, + 0xacf00001, + 0x40008b01, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0x4e060f98, + 0x3d7e0800, + 0xacf00001, + 0x04a5f001, + 0x5030008b, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0x004e080f, + 0x013d7e02, + 0x020a7e00, + 0x03147e00, + 0x0601f400, +/* 0x073f: ctx_xfer_post */ + 0x7e1a12f4, + 0x0f000227, + 0x1da88e0d, + 0x01e5f050, + 0x8f7effb2, + 0x147e0000, +/* 0x0756: ctx_xfer_done */ + 0x107e0003, + 0x00f80006, 0x00000000, 0x00000000, 0x00000000, -- cgit v0.10.2 From 2fb2b3c6e49a9dc1ed39631ae977b62a273b5a57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Nov 2015 05:47:19 +1000 Subject: drm/nouveau/gr/gf117-: assume no PPC if NV_PGRAPH_GPC_GPM_PD_PES_TPC_ID_MASK is zero fdo#92761 Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index b5b8759..74de7a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -207,6 +207,8 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) const u32 b = beta * gr->ppc_tpc_nr[gpc][ppc]; const u32 t = timeslice_mode; const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) + continue; mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index dda7a7d..7cdea77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1530,6 +1530,8 @@ gf100_gr_oneinit(struct nvkm_gr *base) gr->ppc_nr[i] = gr->func->ppc_nr; for (j = 0; j < gr->ppc_nr[i]; j++) { u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); + if (mask) + gr->ppc_mask[i] |= (1 << j); gr->ppc_tpc_nr[i][j] = hweight8(mask); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 4611961..02e78b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -97,6 +97,7 @@ struct gf100_gr { u8 tpc_nr[GPC_MAX]; u8 tpc_total; u8 ppc_nr[GPC_MAX]; + u8 ppc_mask[GPC_MAX]; u8 ppc_tpc_nr[GPC_MAX][4]; struct nvkm_memory *unk4188b4; -- cgit v0.10.2 From 0d7fc24616d3aa7b6d4aad03bac25ec23a74b9a6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Nov 2015 12:39:01 +1000 Subject: drm/nouveau/gr/gf100-: fix oops when calling zbc methods Somehow missed these two when removing dodgy void casts during the rework. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 7cdea77..9f5dfc8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -143,7 +143,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, static int gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr *gr = (void *)object->engine; + struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine)); union { struct fermi_a_zbc_color_v0 v0; } *args = data; @@ -189,7 +189,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) static int gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr *gr = (void *)object->engine; + struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine)); union { struct fermi_a_zbc_depth_v0 v0; } *args = data; -- cgit v0.10.2 From f5e551873e5eaf506b2aa870f56a7ba10a51221b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 24 Nov 2015 15:34:51 +1000 Subject: drm/nouveau/nvif: allow userspace access to its own client object Regression from "abi16: implement limited interoperability with usif/nvif". Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 3050042e..a02813e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -39,6 +39,7 @@ #include #include +#include #include @@ -65,9 +66,10 @@ struct nouveau_drm_tile { }; enum nouveau_drm_object_route { - NVDRM_OBJECT_NVIF = 0, + NVDRM_OBJECT_NVIF = NVIF_IOCTL_V0_OWNER_NVIF, NVDRM_OBJECT_USIF, NVDRM_OBJECT_ABI16, + NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY, }; enum nouveau_drm_notify_route { diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c index 89dc4ce..6ae1b34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_usif.c +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c @@ -313,7 +313,10 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) if (nvif_unpack(argv->v0, 0, 0, true)) { /* block access to objects not created via this interface */ owner = argv->v0.owner; - argv->v0.owner = NVDRM_OBJECT_USIF; + if (argv->v0.object == 0ULL) + argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */ + else + argv->v0.owner = NVDRM_OBJECT_USIF; } else goto done; -- cgit v0.10.2 From ef0e9f551899d10834da3d262f20f84db61d64b3 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Thu, 5 Nov 2015 09:07:38 +0100 Subject: drm/nouveau/volt/pwm/gk104: fix an off-by-one resulting in the voltage not being set Reported-by: Ilia Mirkin Signed-off-by: Martin Peres diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c index b61509e..b735173 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c @@ -59,7 +59,7 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv) duty = (uv - bios->base) * div / bios->pwm_range; nvkm_wr32(device, 0x20340, div); - nvkm_wr32(device, 0x20344, 0x8000000 | duty); + nvkm_wr32(device, 0x20344, 0x80000000 | duty); return 0; } -- cgit v0.10.2 From 69d21fc0a21196e9c5b259505c0135a88002f9d2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 25 Nov 2015 10:25:39 +0000 Subject: drm: imx: convert to drm_crtc_send_vblank_event() ipu_crtc_handle_pageflip() was calling drm_send_vblank_event() with a pipe argument of -1. Commit cc1ef118fc09 ("drm/irq: Make pipe unsigned and name consistent") now makes this error obvious, as we now may get a warning from: if (WARN_ON(pipe >= dev->num_crtcs)) in drm_vblank_count_and_time(). Prior to this change, we would end up making out-of-bounds array accesses via: struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; and *vblanktime = vblanktimestamp(dev, pipe, cur_vblank); So, this has been broken for a very long time, and is not a result of the above commit. Since we don't care about the staging versions, I've tagged this with the earliest mainline commit where we do care, even though this commit did not introduce the bug. Fixes: 6556f7f82b9c ("drm: imx: Move imx-drm driver out of staging") Signed-off-by: Russell King Signed-off-by: Philipp Zabel diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 67813ca..4ab841e 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) spin_lock_irqsave(&drm->event_lock, flags); if (ipu_crtc->page_flip_event) - drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event); + drm_crtc_send_vblank_event(&ipu_crtc->base, + ipu_crtc->page_flip_event); ipu_crtc->page_flip_event = NULL; imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); spin_unlock_irqrestore(&drm->event_lock, flags); -- cgit v0.10.2 From 51c4cfef568fe8ebac06761ed7c754fac1f9b5a8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 11 Nov 2015 10:11:01 -0600 Subject: rtc: ds1307: fix kernel splat due to wakeup irq handling Since commit 3fffd1283927 ("i2c: allow specifying separate wakeup interrupt in device tree") we have automatic wakeup irq support for i2c devices. That commit missed the fact that rtc-1307 had its own wakeup irq handling and ended up introducing a kernel splat for at least Beagle x15 boards. Fix that by reverting original commit _and_ passing correct interrupt names on DTS so i2c-core can choose correct IRQ as wakeup. Now that we have automatic wakeirq support, we can revert the original commit which did it manually. Fixes the following warning: [ 10.346582] WARNING: CPU: 1 PID: 263 at linux/drivers/base/power/wakeirq.c:43 dev_pm_attach_wake_irq+0xbc/0xd4() [ 10.359244] rtc-ds1307 2-006f: wake irq already initialized Cc: Tony Lindgren Cc: Nishanth Menon Signed-off-by: Felipe Balbi Acked-by: Tony Lindgren Acked-by: Arnd Bergmann Signed-off-by: Alexandre Belloni diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts index d9ba6b8..00352e7 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15.dts +++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts @@ -604,6 +604,7 @@ reg = <0x6f>; interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>, <&dra7_pmx_core 0x424>; + interrupt-names = "irq", "wakeup"; pinctrl-names = "default"; pinctrl-0 = <&mcp79410_pins_default>; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 188006c..3258368 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -15,9 +15,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -117,7 +114,6 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - int wakeirq; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -1146,8 +1142,6 @@ read_rtc: } if (want_irq) { - struct device_node *node = client->dev.of_node; - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, IRQF_SHARED | IRQF_ONESHOT, @@ -1155,34 +1149,13 @@ read_rtc: if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); - goto no_irq; - } - - set_bit(HAS_ALARM, &ds1307->flags); - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); - - /* Currently supported by OF code only! */ - if (!node) - goto no_irq; - - err = of_irq_get(node, 1); - if (err <= 0) { - if (err == -EPROBE_DEFER) - goto exit; - goto no_irq; - } - ds1307->wakeirq = err; + } else { - err = dev_pm_set_dedicated_wake_irq(&client->dev, - ds1307->wakeirq); - if (err) { - dev_err(&client->dev, "unable to setup wakeIRQ %d!\n", - err); - goto exit; + set_bit(HAS_ALARM, &ds1307->flags); + dev_dbg(&client->dev, "got IRQ %d\n", client->irq); } } -no_irq: if (chip->nvram_size) { ds1307->nvram = devm_kzalloc(&client->dev, @@ -1226,9 +1199,6 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (ds1307->wakeirq) - dev_pm_clear_wake_irq(&client->dev); - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); -- cgit v0.10.2 From ab07eaedb7ada83cc6341894dff9cd54f1af7f8b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 24 Nov 2015 23:21:10 +0100 Subject: ASoC: fsl: clarify ac97 dependency A new randconfig build failure shows that the fsl-asoc-card module must not be built-in when the AC97 driver is a loadable module: sound/built-in.o: In function `fsl_asoc_card_late_probe': :(.text+0x571d8): undefined reference to `snd_ac97_update_bits' I couldn't come up with a nice solution, so this adds another dependency on "X || !X", which is the Kconfig way of saying that we have an optional dependency on something that might be a loadable module. Fixes: 50760cad9de9 ("ASoC: fsl-asoc-card: add AC'97 support") Signed-off-by: Arnd Bergmann Acked-by: Nicolin Chen Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 19c302b..14dfdee 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -283,6 +283,8 @@ config SND_SOC_IMX_MC13783 config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C + # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m: + depends on SND_AC97_CODEC || SND_AC97_CODEC=n select SND_SOC_IMX_AUDMUX select SND_SOC_IMX_PCM_DMA select SND_SOC_FSL_ESAI -- cgit v0.10.2 From 18a9d7486ad28d68920128720514f9555a4c1869 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Wed, 25 Nov 2015 09:54:11 +0100 Subject: ASoC: rockchip: Fix incorrect VDW value for 24 bit Correct valid data word register value for 24 bit data width. The bit value should be 10 (aka 0x2), not 0x10. This fixes playback of 24 bit audio. Signed-off-by: Sjoerd Simons Reviewed-by: Caesar Wang Signed-off-by: Mark Brown diff --git a/sound/soc/rockchip/rockchip_spdif.h b/sound/soc/rockchip/rockchip_spdif.h index 07f86a2..921b409 100644 --- a/sound/soc/rockchip/rockchip_spdif.h +++ b/sound/soc/rockchip/rockchip_spdif.h @@ -28,9 +28,9 @@ #define SPDIF_CFGR_VDW(x) (x << SPDIF_CFGR_VDW_SHIFT) #define SDPIF_CFGR_VDW_MASK (0xf << SPDIF_CFGR_VDW_SHIFT) -#define SPDIF_CFGR_VDW_16 SPDIF_CFGR_VDW(0x00) -#define SPDIF_CFGR_VDW_20 SPDIF_CFGR_VDW(0x01) -#define SPDIF_CFGR_VDW_24 SPDIF_CFGR_VDW(0x10) +#define SPDIF_CFGR_VDW_16 SPDIF_CFGR_VDW(0x0) +#define SPDIF_CFGR_VDW_20 SPDIF_CFGR_VDW(0x1) +#define SPDIF_CFGR_VDW_24 SPDIF_CFGR_VDW(0x2) /* * DMACR -- cgit v0.10.2 From 6b3cecd11539178978e1f54fe1363c39fe0db045 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 24 Nov 2015 10:55:29 +0800 Subject: ASoC: rt5645: Add dmi_system_id "Google Terra" Add platform specific data for Terra project. Signed-off-by: Luke_Yin@asus.com Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 5af9023..ef76940 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3392,6 +3392,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"), }, }, + { + .ident = "Google Terra", + .callback = strago_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Terra"), + }, + }, { } }; -- cgit v0.10.2 From 7142392dcac240b37cce8a246225bb11213246cc Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Fri, 20 Nov 2015 17:45:40 +0000 Subject: arm64: early_alloc: Fix check for allocation failure In early_alloc we check if the memblock_alloc failed by checking the virtual address of the result, which will never fail. This patch fixes it to check the actual result for failure. Acked-by: Will Deacon Signed-off-by: Suzuki K. Poulose Signed-off-by: Catalin Marinas diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index abb66f8..78d91b1 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -64,8 +64,12 @@ EXPORT_SYMBOL(phys_mem_access_prot); static void __init *early_alloc(unsigned long sz) { - void *ptr = __va(memblock_alloc(sz, sz)); - BUG_ON(!ptr); + phys_addr_t phys; + void *ptr; + + phys = memblock_alloc(sz, sz); + BUG_ON(!phys); + ptr = __va(phys); memset(ptr, 0, sz); return ptr; } -- cgit v0.10.2 From 9a11ef7ff00e08825ac970a6bda56a3ea8ab0321 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 23 Nov 2015 17:37:54 -0800 Subject: ASoC: fix kernel-doc warnings in sound/soc/soc-ops.c Fix kernel-doc warnings in soc-ops.c: ..//sound/soc/soc-ops.c:415: warning: No description found for parameter 'ucontrol' ..//sound/soc/soc-ops.c:415: warning: Excess function parameter 'uinfo' description in 'snd_soc_put_volsw_sx' Signed-off-by: Randy Dunlap Cc: Liam Girdwood Cc: Mark Brown Signed-off-by: Mark Brown diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index ecd38e5..2f67ba6 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); /** * snd_soc_put_volsw_sx - double mixer set callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a double mixer control that spans 2 registers. * -- cgit v0.10.2 From 1a7aaa58ec7aaa389cd6b200809908ec472d316b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 23 Nov 2015 21:22:31 +0530 Subject: ASoC: core: Change power state before rechecking endpoint For DAPM resume, we should first change the power state of the card and then recheck the endpoints. This ensures the dapm is resumed first and then userspace can resume the streams. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 24b0960..a1305f8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -795,12 +795,12 @@ static void soc_resume_deferred(struct work_struct *work) dev_dbg(card->dev, "ASoC: resume work completed\n"); - /* userspace can access us now we are back as we were before */ - snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); - /* Recheck all endpoints too, their state is affected by suspend */ dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); + + /* userspace can access us now we are back as we were before */ + snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); } /* powers up audio subsystem after a suspend */ -- cgit v0.10.2 From 9dcbeed4d7e11e1dcf5e55475de3754f0855d1c2 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 9 Nov 2015 11:44:45 +0100 Subject: btrfs: fix signed overflows in btrfs_sync_file The calculation of range length in btrfs_sync_file leads to signed overflow. This was caught by PaX gcc SIZE_OVERFLOW plugin. https://forums.grsecurity.net/viewtopic.php?f=1&t=4284 The fsync call passes 0 and LLONG_MAX, the range length does not fit to loff_t and overflows, but the value is converted to u64 so it silently works as expected. The minimal fix is a typecast to u64, switching functions to take (start, end) instead of (start, len) would be more intrusive. Coccinelle script found that there's one more opencoded calculation of the length. @@ loff_t start, end; @@ * end - start CC: stable@vger.kernel.org Signed-off-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3009d45..8eb1f3c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1882,8 +1882,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct btrfs_log_ctx ctx; int ret = 0; bool full_sync = 0; - const u64 len = end - start + 1; + u64 len; + /* + * The range length can be represented by u64, we have to do the typecasts + * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync() + */ + len = (u64)end - (u64)start + 1; trace_btrfs_sync_file(file, datasync); /* @@ -2071,8 +2076,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } } if (!full_sync) { - ret = btrfs_wait_ordered_range(inode, start, - end - start + 1); + ret = btrfs_wait_ordered_range(inode, start, len); if (ret) { btrfs_end_transaction(trans, root); goto out; -- cgit v0.10.2 From 89b6c8d1e4a178a347b94f339b959f02710e7060 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 10 Nov 2015 12:10:03 +0300 Subject: Btrfs: tests: checking for NULL instead of IS_ERR() btrfs_alloc_dummy_root() return an error pointer on failure, it never returns NULL. Signed-off-by: Dan Carpenter Reviewed-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/tests/free-space-tests.c b/fs/btrfs/tests/free-space-tests.c index c8c3d70..8b72b00 100644 --- a/fs/btrfs/tests/free-space-tests.c +++ b/fs/btrfs/tests/free-space-tests.c @@ -898,8 +898,10 @@ int btrfs_test_free_space_cache(void) } root = btrfs_alloc_dummy_root(); - if (!root) + if (IS_ERR(root)) { + ret = PTR_ERR(root); goto out; + } root->fs_info = btrfs_alloc_dummy_fs_info(); if (!root->fs_info) -- cgit v0.10.2 From 8eab77ff167b62760d878f1d19312eb9f7d4c176 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 13 Nov 2015 23:57:16 +0000 Subject: Btrfs: use global reserve when deleting unused block group after ENOSPC It's possible to reach a state where the cleaner kthread isn't able to start a transaction to delete an unused block group due to lack of enough free metadata space and due to lack of unallocated device space to allocate a new metadata block group as well. If this happens try to use space from the global block group reserve just like we do for unlink operations, so that we don't reach a permanent state where starting a transaction for filesystem operations (file creation, renames, etc) keeps failing with -ENOSPC. Such an unfortunate state was observed on a machine where over a dozen unused data block groups existed and the cleaner kthread was failing to delete them due to ENOSPC error when attempting to start a transaction, and even running balance with a -dusage=0 filter failed with ENOSPC as well. Also unmounting and mounting again the filesystem didn't help. Allowing the cleaner kthread to use the global block reserve to delete the unused data block groups fixed the problem. Signed-off-by: Filipe Manana Signed-off-by: Jeff Mahoney Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index a2e73f6..1573be6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3479,6 +3479,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytes_used, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size); +struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( + struct btrfs_fs_info *fs_info); int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 group_start, struct extent_map *em); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index acf3ed1..7820093 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10256,6 +10256,17 @@ out: return ret; } +struct btrfs_trans_handle * +btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info) +{ + /* + * 1 unit for adding the free space inode's orphan (located in the tree + * of tree roots). + */ + return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root, + 1, 1); +} + /* * Process the unused_bgs list and remove any that don't have any allocated * space inside of them. @@ -10322,8 +10333,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) * Want to do this before we do anything else so we can recover * properly if we fail to join the transaction. */ - /* 1 for btrfs_orphan_reserve_metadata() */ - trans = btrfs_start_transaction(root, 1); + trans = btrfs_start_trans_remove_block_group(fs_info); if (IS_ERR(trans)) { btrfs_dec_block_group_ro(root, block_group); ret = PTR_ERR(trans); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6e93349..f82d1f4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4046,9 +4046,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans, */ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir) { - struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(dir)->root; - int ret; /* * 1 for the possible orphan item @@ -4057,27 +4055,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir) * 1 for the inode ref * 1 for the inode */ - trans = btrfs_start_transaction(root, 5); - if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) - return trans; - - if (PTR_ERR(trans) == -ENOSPC) { - u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5); - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) - return trans; - ret = btrfs_cond_migrate_bytes(root->fs_info, - &root->fs_info->trans_block_rsv, - num_bytes, 5); - if (ret) { - btrfs_end_transaction(trans, root); - return ERR_PTR(ret); - } - trans->block_rsv = &root->fs_info->trans_block_rsv; - trans->bytes_reserved = num_bytes; - } - return trans; + return btrfs_start_transaction_fallback_global_rsv(root, 5, 5); } static int btrfs_unlink(struct inode *dir, struct dentry *dentry) diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 418c6a2..3367a3c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -592,6 +592,38 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, return start_transaction(root, num_items, TRANS_START, BTRFS_RESERVE_FLUSH_ALL); } +struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( + struct btrfs_root *root, + unsigned int num_items, + int min_factor) +{ + struct btrfs_trans_handle *trans; + u64 num_bytes; + int ret; + + trans = btrfs_start_transaction(root, num_items); + if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) + return trans; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) + return trans; + + num_bytes = btrfs_calc_trans_metadata_size(root, num_items); + ret = btrfs_cond_migrate_bytes(root->fs_info, + &root->fs_info->trans_block_rsv, + num_bytes, + min_factor); + if (ret) { + btrfs_end_transaction(trans, root); + return ERR_PTR(ret); + } + + trans->block_rsv = &root->fs_info->trans_block_rsv; + trans->bytes_reserved = num_bytes; + + return trans; +} struct btrfs_trans_handle *btrfs_start_transaction_lflush( struct btrfs_root *root, diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index b05b2f6..0da21ca 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -185,6 +185,10 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root); struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, unsigned int num_items); +struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( + struct btrfs_root *root, + unsigned int num_items, + int min_factor); struct btrfs_trans_handle *btrfs_start_transaction_lflush( struct btrfs_root *root, unsigned int num_items); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d198dd3..e0bd364 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2853,7 +2853,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset) if (ret) return ret; - trans = btrfs_start_transaction(root, 0); + trans = btrfs_start_trans_remove_block_group(root->fs_info); if (IS_ERR(trans)) { ret = PTR_ERR(trans); btrfs_std_error(root->fs_info, ret, NULL); -- cgit v0.10.2 From 7fd01182d1a1412cd44a5474b9aa93548d4a73ae Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 13 Nov 2015 23:57:17 +0000 Subject: Btrfs: fix the number of transaction units needed to remove a block group We were using only 1 transaction unit when attempting to delete an unused block group but in reality we need 3 + N units, where N corresponds to the number of stripes. We were accounting only for the addition of the orphan item (for the block group's free space cache inode) but we were not accounting that we need to delete one block group item from the extent tree, one free space item from the tree of tree roots and N device extent items from the device tree. While one unit is not enough, it worked most of the time because for each single unit we are too pessimistic and assume an entire tree path, with the highest possible heigth (8), needs to be COWed with eventual node splits at every possible level in the tree, so there was usually enough reserved space for removing all the items and adding the orphan item. However after adding the orphan item, writepages() can by called by the VM subsystem against the btree inode when we are under memory pressure, which causes writeback to start for the nodes we COWed before, this forces the operation to remove the free space item to COW again some (or all of) the same nodes (in the tree of tree roots). Even without writepages() being called, we could fail with ENOSPC because these items are located in multiple trees and one of them might have a higher heigth and require node/leaf splits at many levels, exhausting all the reserved space before removing all the items and adding the orphan. In the kernel 4.0 release, commit 3d84be799194 ("Btrfs: fix BUG_ON in btrfs_orphan_add() when delete unused block group"), we attempted to fix a BUG_ON due to ENOSPC when trying to add the orphan item by making the cleaner kthread reserve one transaction unit before attempting to remove the block group, but this was not enough. We had a couple user reports still hitting the same BUG_ON after 4.0, like Stefan Priebe's report on a 4.2-rc6 kernel for example: http://www.spinics.net/lists/linux-btrfs/msg46070.html So fix this by reserving all the necessary units of metadata. Reported-by: Stefan Priebe Fixes: 3d84be799194 ("Btrfs: fix BUG_ON in btrfs_orphan_add() when delete unused block group") Signed-off-by: Filipe Manana Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1573be6..d88994f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3480,7 +3480,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size); struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( - struct btrfs_fs_info *fs_info); + struct btrfs_fs_info *fs_info, + const u64 chunk_offset); int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 group_start, struct extent_map *em); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7820093..e97d6d6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10257,14 +10257,44 @@ out: } struct btrfs_trans_handle * -btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info) +btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info, + const u64 chunk_offset) { + struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; + struct extent_map *em; + struct map_lookup *map; + unsigned int num_items; + + read_lock(&em_tree->lock); + em = lookup_extent_mapping(em_tree, chunk_offset, 1); + read_unlock(&em_tree->lock); + ASSERT(em && em->start == chunk_offset); + /* + * We need to reserve 3 + N units from the metadata space info in order + * to remove a block group (done at btrfs_remove_chunk() and at + * btrfs_remove_block_group()), which are used for: + * * 1 unit for adding the free space inode's orphan (located in the tree * of tree roots). + * 1 unit for deleting the block group item (located in the extent + * tree). + * 1 unit for deleting the free space item (located in tree of tree + * roots). + * N units for deleting N device extent items corresponding to each + * stripe (located in the device tree). + * + * In order to remove a block group we also need to reserve units in the + * system space info in order to update the chunk tree (update one or + * more device items and remove one chunk item), but this is done at + * btrfs_remove_chunk() through a call to check_system_chunk(). */ + map = (struct map_lookup *)em->bdev; + num_items = 3 + map->num_stripes; + free_extent_map(em); + return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root, - 1, 1); + num_items, 1); } /* @@ -10333,7 +10363,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) * Want to do this before we do anything else so we can recover * properly if we fail to join the transaction. */ - trans = btrfs_start_trans_remove_block_group(fs_info); + trans = btrfs_start_trans_remove_block_group(fs_info, + block_group->key.objectid); if (IS_ERR(trans)) { btrfs_dec_block_group_ro(root, block_group); ret = PTR_ERR(trans); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e0bd364..45f2025 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2853,7 +2853,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset) if (ret) return ret; - trans = btrfs_start_trans_remove_block_group(root->fs_info); + trans = btrfs_start_trans_remove_block_group(root->fs_info, + chunk_offset); if (IS_ERR(trans)) { ret = PTR_ERR(trans); btrfs_std_error(root->fs_info, ret, NULL); -- cgit v0.10.2 From da02c6898952a2bc251dd51ed9f897e0a72a853e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 16 Nov 2015 16:50:13 +0100 Subject: btrfs: fix clashing number of the enhanced balance usage filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've accidentally picked an already used number for the enhanced usage filter represented by BTRFS_BALANCE_ARGS_USAGE_RANGE, clashing with BTRFS_BALANCE_ARGS_CONVERT. Introduced during the development phase, no backward compatibility issues. Reported-by: Holger Hoffstätte Reported-by: Dan Carpenter Fixes: bc3094673f22 ("btrfs: extend balance filter usage to take minimum and maximum") Signed-off-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index ec57123..d5c84f6 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -382,7 +382,7 @@ struct map_lookup { #define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) #define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6) #define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7) -#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 8) +#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10) #define BTRFS_BALANCE_ARGS_MASK \ (BTRFS_BALANCE_ARGS_PROFILES | \ -- cgit v0.10.2 From 76a8efa171bf6cf37ffb83d3f62fed2e47e2abc8 Mon Sep 17 00:00:00 2001 From: Zhaolei Date: Tue, 17 Nov 2015 18:46:17 +0800 Subject: btrfs: Continue replace when set_block_ro failed xfstests/011 failed in node with small_size filesystem. Can be reproduced by following script: DEV_LIST="/dev/vdd /dev/vde" DEV_REPLACE="/dev/vdf" do_test() { local mkfs_opt="$1" local size="$2" dmesg -c >/dev/null umount $SCRATCH_MNT &>/dev/null echo mkfs.btrfs -f $mkfs_opt "${DEV_LIST[*]}" mkfs.btrfs -f $mkfs_opt "${DEV_LIST[@]}" || return 1 mount "${DEV_LIST[0]}" $SCRATCH_MNT echo -n "Writing big files" dd if=/dev/urandom of=$SCRATCH_MNT/t0 bs=1M count=1 >/dev/null 2>&1 for ((i = 1; i <= size; i++)); do echo -n . /bin/cp $SCRATCH_MNT/t0 $SCRATCH_MNT/t$i || return 1 done echo echo Start replace btrfs replace start -Bf "${DEV_LIST[0]}" "$DEV_REPLACE" $SCRATCH_MNT || { dmesg return 1 } return 0 } # Set size to value near fs size # for example, 1897 can trigger this bug in 2.6G device. # ./do_test "-d raid1 -m raid1" 1897 System will report replace fail with following warning in dmesg: [ 134.710853] BTRFS: dev_replace from /dev/vdd (devid 1) to /dev/vdf started [ 135.542390] BTRFS: btrfs_scrub_dev(/dev/vdd, 1, /dev/vdf) failed -28 [ 135.543505] ------------[ cut here ]------------ [ 135.544127] WARNING: CPU: 0 PID: 4080 at fs/btrfs/dev-replace.c:428 btrfs_dev_replace_start+0x398/0x440() [ 135.545276] Modules linked in: [ 135.545681] CPU: 0 PID: 4080 Comm: btrfs Not tainted 4.3.0 #256 [ 135.546439] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 [ 135.547798] ffffffff81c5bfcf ffff88003cbb3d28 ffffffff817fe7b5 0000000000000000 [ 135.548774] ffff88003cbb3d60 ffffffff810a88f1 ffff88002b030000 00000000ffffffe4 [ 135.549774] ffff88003c080000 ffff88003c082588 ffff88003c28ab60 ffff88003cbb3d70 [ 135.550758] Call Trace: [ 135.551086] [] dump_stack+0x44/0x55 [ 135.551737] [] warn_slowpath_common+0x81/0xc0 [ 135.552487] [] warn_slowpath_null+0x15/0x20 [ 135.553211] [] btrfs_dev_replace_start+0x398/0x440 [ 135.554051] [] btrfs_ioctl+0x1d2e/0x25c0 [ 135.554722] [] ? __audit_syscall_entry+0xaa/0xf0 [ 135.555506] [] ? current_kernel_time64+0x56/0xa0 [ 135.556304] [] do_vfs_ioctl+0x30d/0x580 [ 135.557009] [] ? __audit_syscall_entry+0xaa/0xf0 [ 135.557855] [] ? do_audit_syscall_entry+0x61/0x70 [ 135.558669] [] ? __fget_light+0x61/0x90 [ 135.559374] [] SyS_ioctl+0x74/0x80 [ 135.559987] [] entry_SYSCALL_64_fastpath+0x12/0x6f [ 135.560842] ---[ end trace 2a5c1fc3205abbdd ]--- Reason: When big data writen to fs, the whole free space will be allocated for data chunk. And operation as scrub need to set_block_ro(), and when there is only one metadata chunk in system(or other metadata chunks are all full), the function will try to allocate a new chunk, and failed because no space in device. Fix: When set_block_ro failed for metadata chunk, it is not a problem because scrub_lock paused commit_trancaction in same time, and metadata are always cowed, so the on-the-fly writepages will not write data into same place with scrub/replace. Let replace continue in this case is no problem. Tested by above script, and xfstests/011, plus 100 times xfstests/070. Changelog v1->v2: 1: Add detail comments in source and commit-message. 2: Add dmesg detail into commit-message. 3: Limit return value of -ENOSPC to be passed. All suggested by: Filipe Manana Suggested-by: Filipe Manana Signed-off-by: Zhao Lei Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 2907a77..6b3fd51 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3483,6 +3483,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 length; u64 chunk_offset; int ret = 0; + int ro_set; int slot; struct extent_buffer *l; struct btrfs_key key; @@ -3568,7 +3569,21 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, scrub_pause_on(fs_info); ret = btrfs_inc_block_group_ro(root, cache); scrub_pause_off(fs_info); - if (ret) { + + if (ret == 0) { + ro_set = 1; + } else if (ret == -ENOSPC) { + /* + * btrfs_inc_block_group_ro return -ENOSPC when it + * failed in creating new chunk for metadata. + * It is not a problem for scrub/replace, because + * metadata are always cowed, and our scrub paused + * commit_transactions. + */ + ro_set = 0; + } else { + btrfs_warn(fs_info, "failed setting block group ro, ret=%d\n", + ret); btrfs_put_block_group(cache); break; } @@ -3611,7 +3626,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, scrub_pause_off(fs_info); - btrfs_dec_block_group_ro(root, cache); + if (ro_set) + btrfs_dec_block_group_ro(root, cache); btrfs_put_block_group(cache); if (ret) -- cgit v0.10.2 From 31388ab2edac833defa4193172edc1d409868bfb Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 19 Nov 2015 11:35:17 +0100 Subject: btrfs: fix rcu warning during device replace The test btrfs/011 triggers a rcu warning Reviewed-by: Anand Jain =============================== [ INFO: suspicious RCU usage. ] 4.4.0-rc1-default+ #286 Tainted: G W ------------------------------- fs/btrfs/volumes.c:1977 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 4 locks held by btrfs/28786: 0: (&fs_info->dev_replace.lock_finishing_cancel_unmount){+.+...}, at: [] btrfs_dev_replace_finishing+0x45/0xa00 [btrfs] 1: (uuid_mutex){+.+.+.}, at: [] btrfs_dev_replace_finishing+0x10f/0xa00 [btrfs] 2: (&fs_devs->device_list_mutex){+.+.+.}, at: [] btrfs_dev_replace_finishing+0x128/0xa00 [btrfs] 3: (&fs_info->chunk_mutex){+.+...}, at: [] btrfs_dev_replace_finishing+0x13d/0xa00 [btrfs] stack backtrace: CPU: 0 PID: 28786 Comm: btrfs Tainted: G W 4.4.0-rc1-default+ #286 Hardware name: Intel Corporation SandyBridge Platform/To be filled by O.E.M., BIOS ASNBCPT1.86C.0031.B00.1006301607 06/30/2010 0000000000000001 ffff8800a07dfb48 ffffffff8141d47b 0000000000000001 0000000000000001 0000000000000000 ffff8801464a4f00 ffff8800a07dfb78 ffffffff810cd883 ffff880146eb9400 ffff8800a3698600 ffff8800a33fe220 Call Trace: [] dump_stack+0x4f/0x74 [] lockdep_rcu_suspicious+0x103/0x140 [] btrfs_rm_dev_replace_remove_srcdev+0x111/0x130 [btrfs] [] ? trace_hardirqs_on+0xd/0x10 [] ? __percpu_counter_sum+0x66/0x80 [] btrfs_dev_replace_finishing+0x4d5/0xa00 [btrfs] [] ? btrfs_dev_replace_finishing+0x22e/0xa00 [btrfs] [] ? btrfs_scrub_dev+0x415/0x6d0 [btrfs] [] ? btrfs_start_transaction+0x9/0x20 [btrfs] [] btrfs_dev_replace_start+0x339/0x590 [btrfs] [] ? __might_fault+0x95/0xa0 [] btrfs_ioctl_dev_replace+0x118/0x160 [btrfs] [] ? stack_trace_call+0x46/0x70 [] ? btrfs_ioctl+0x24/0x1770 [btrfs] [] btrfs_ioctl+0x553/0x1770 [btrfs] [] ? stack_trace_call+0x46/0x70 [] ? do_vfs_ioctl+0x21/0x5a0 [] do_vfs_ioctl+0x8c/0x5a0 [] ? __fget_light+0x86/0xb0 [] ? __fdget+0x9/0x20 [] ? SyS_ioctl+0x21/0x80 [] SyS_ioctl+0x53/0x80 [] entry_SYSCALL_64_fastpath+0x12/0x6f This is because of unprotected use of rcu_dereference in btrfs_scratch_superblocks. We can't add rcu locks around the whole function because we read the superblock. The fix will use the rcu string buffer directly without the rcu locking. Thi is safe as the device will not go away in the meantime. We're holding the device list mutexes. Restructuring the code to narrow down the rcu section turned out to be impossible, we need to call filp_open (through update_dev_time) on the buffer and this could call kmalloc/__might_sleep. We could call kstrdup with GFP_ATOMIC but it's not absolutely necessary. Fixes: 12b1c2637b6e (Btrfs: enhance btrfs_scratch_superblock to scratch all superblocks) Signed-off-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 45f2025..f95493b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1973,8 +1973,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, if (srcdev->writeable) { fs_devices->rw_devices--; /* zero out the old super if it is writable */ - btrfs_scratch_superblocks(srcdev->bdev, - rcu_str_deref(srcdev->name)); + btrfs_scratch_superblocks(srcdev->bdev, srcdev->name->str); } if (srcdev->bdev) @@ -2024,8 +2023,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, btrfs_sysfs_rm_device_link(fs_info->fs_devices, tgtdev); if (tgtdev->bdev) { - btrfs_scratch_superblocks(tgtdev->bdev, - rcu_str_deref(tgtdev->name)); + btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str); fs_info->fs_devices->open_devices--; } fs_info->fs_devices->num_devices--; -- cgit v0.10.2 From 020d5b7366fc03e4bf84142ae6f63031ac504e33 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 19 Nov 2015 10:57:20 +0000 Subject: Btrfs: fix race between scrub and block group deletion Scrub can race with the cleaner kthread deleting block groups that are unused (and with relocation too) leading to a failure with error -EINVAL that gets returned to user space. The following diagram illustrates how it happens: CPU 1 CPU 2 cleaner kthread btrfs_delete_unused_bgs() gets block group X from fs_info->unused_bgs sets block group to RO btrfs_remove_chunk(bg X) deletes device extents scrub_enumerate_chunks() searches device tree using its commit root finds device extent for block group X gets block group X from the tree fs_info->block_group_cache_tree (via btrfs_lookup_block_group()) sets bg X to RO (again) btrfs_remove_block_group(bg X) deletes block group from fs_info->block_group_cache_tree removes extent map from fs_info->mapping_tree scrub_chunk(offset X) searches fs_info->mapping_tree for extent map starting at offset X --> doesn't find any such extent map --> returns -EINVAL and scrub errors out to userspace with -EINVAL Fix this by dealing with an extent map lookup failure as an indicator of block group deletion. Issue reproduced with fstest btrfs/071. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 6b3fd51..68af316 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3432,7 +3432,9 @@ out: static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, struct btrfs_device *scrub_dev, u64 chunk_offset, u64 length, - u64 dev_offset, int is_dev_replace) + u64 dev_offset, + struct btrfs_block_group_cache *cache, + int is_dev_replace) { struct btrfs_mapping_tree *map_tree = &sctx->dev_root->fs_info->mapping_tree; @@ -3445,8 +3447,18 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1); read_unlock(&map_tree->map_tree.lock); - if (!em) - return -EINVAL; + if (!em) { + /* + * Might have been an unused block group deleted by the cleaner + * kthread or relocation. + */ + spin_lock(&cache->lock); + if (!cache->removed) + ret = -EINVAL; + spin_unlock(&cache->lock); + + return ret; + } map = (struct map_lookup *)em->bdev; if (em->start != chunk_offset) @@ -3592,7 +3604,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, dev_replace->cursor_left = found_key.offset; dev_replace->item_needs_writeback = 1; ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, - found_key.offset, is_dev_replace); + found_key.offset, cache, is_dev_replace); /* * flush, submit all pending read and write bios, afterwards -- cgit v0.10.2 From 758f2dfcf8a249b1f1510aa32e625c2ec20642a3 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 19 Nov 2015 11:45:48 +0000 Subject: Btrfs: fix scrub preventing unused block groups from being deleted Currently scrub can race with the cleaner kthread when the later attempts to delete an unused block group, and the result is preventing the cleaner kthread from ever deleting later the block group - unless the block group becomes used and unused again. The following diagram illustrates that race: CPU 1 CPU 2 cleaner kthread btrfs_delete_unused_bgs() gets block group X from fs_info->unused_bgs and removes it from that list scrub_enumerate_chunks() searches device tree using its commit root finds device extent for block group X gets block group X from the tree fs_info->block_group_cache_tree (via btrfs_lookup_block_group()) sets bg X to RO sees the block group is already RO and therefore doesn't delete it nor adds it back to unused list So fix this by making scrub add the block group again to the list of unused block groups if the block group is still unused when it finished scrubbing it and it hasn't been removed already. Signed-off-by: Filipe Manana Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d88994f..a0165c6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3416,6 +3416,7 @@ int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, struct btrfs_block_group_cache *btrfs_lookup_block_group( struct btrfs_fs_info *info, u64 bytenr); +void btrfs_get_block_group(struct btrfs_block_group_cache *cache); void btrfs_put_block_group(struct btrfs_block_group_cache *cache); int get_block_group_index(struct btrfs_block_group_cache *cache); struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e97d6d6..8fd14b6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -124,7 +124,7 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) return (cache->flags & bits) == bits; } -static void btrfs_get_block_group(struct btrfs_block_group_cache *cache) +void btrfs_get_block_group(struct btrfs_block_group_cache *cache) { atomic_inc(&cache->count); } diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 68af316..b091d94 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3641,6 +3641,28 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, if (ro_set) btrfs_dec_block_group_ro(root, cache); + /* + * We might have prevented the cleaner kthread from deleting + * this block group if it was already unused because we raced + * and set it to RO mode first. So add it back to the unused + * list, otherwise it might not ever be deleted unless a manual + * balance is triggered or it becomes used and unused again. + */ + spin_lock(&cache->lock); + if (!cache->removed && !cache->ro && cache->reserved == 0 && + btrfs_block_group_used(&cache->item) == 0) { + spin_unlock(&cache->lock); + spin_lock(&fs_info->unused_bgs_lock); + if (list_empty(&cache->bg_list)) { + btrfs_get_block_group(cache); + list_add_tail(&cache->bg_list, + &fs_info->unused_bgs); + } + spin_unlock(&fs_info->unused_bgs_lock); + } else { + spin_unlock(&cache->lock); + } + btrfs_put_block_group(cache); if (ret) break; -- cgit v0.10.2 From 036a9348dcd0060e3df8f5b5db2a59e7d7eaf1f5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 23 Nov 2015 15:25:16 +0000 Subject: Btrfs: fix race between cleaner kthread and space cache writeout When a block group becomes unused and the cleaner kthread is currently running, we can end up getting the current transaction aborted with error -ENOENT when we try to commit the transaction, leading to the following trace: [59779.258768] WARNING: CPU: 3 PID: 5990 at fs/btrfs/extent-tree.c:3740 btrfs_write_dirty_block_groups+0x17c/0x214 [btrfs]() [59779.272594] BTRFS: Transaction aborted (error -2) (...) [59779.291137] Call Trace: [59779.291621] [] dump_stack+0x4e/0x79 [59779.292543] [] warn_slowpath_common+0x9f/0xb8 [59779.293435] [] ? btrfs_write_dirty_block_groups+0x17c/0x214 [btrfs] [59779.295000] [] warn_slowpath_fmt+0x48/0x50 [59779.296138] [] ? write_one_cache_group.isra.32+0x77/0x82 [btrfs] [59779.297663] [] btrfs_write_dirty_block_groups+0x17c/0x214 [btrfs] [59779.299141] [] commit_cowonly_roots+0x1de/0x261 [btrfs] [59779.300359] [] btrfs_commit_transaction+0x4c4/0x99c [btrfs] [59779.301805] [] btrfs_sync_fs+0x145/0x1ad [btrfs] [59779.302893] [] sync_filesystem+0x7f/0x93 (...) [59779.318186] ---[ end trace 577e2daff90da33a ]--- The following diagram illustrates a sequence of steps leading to this problem: CPU 1 CPU 2 adds bg A to list fs_info->unused_bgs adds bg B to list fs_info->unused_bgs cleaner kthread delete_unused_bgs() sees bg A in list fs_info->unused_bgs btrfs_start_transaction() deletes bg A update_block_group(bg C) --> adds bg C to list fs_info->unused_bgs deletes bg B sees bg C in the list fs_info->unused_bgs btrfs_remove_chunk(bg C) btrfs_remove_block_group(bg C) --> checks if the block group is in a dirty list, and because it isn't now, it does nothing --> the block group item is deleted from the extent tree --> adds bg C to list transaction->dirty_bgs some task calls btrfs_commit_transaction(t N + 1) commit_cowonly_roots() btrfs_write_dirty_block_groups() --> sees bg C in cur_trans->dirty_bgs --> calls write_one_cache_group() which returns -ENOENT because it did not find the block group item in the extent tree --> transaction aborte with -ENOENT because write_one_cache_group() returned that error So fix this by adding a block group to the list of dirty block groups before adding it to the list of unused block groups. This happened on a stress test using fsstress plus concurrent calls to fallocate 20G and truncate (releasing part of the space allocated with fallocate). Signed-off-by: Filipe Manana Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 8fd14b6..e563e5a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5915,19 +5915,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, set_extent_dirty(info->pinned_extents, bytenr, bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL); - /* - * No longer have used bytes in this block group, queue - * it for deletion. - */ - if (old_val == 0) { - spin_lock(&info->unused_bgs_lock); - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - list_add_tail(&cache->bg_list, - &info->unused_bgs); - } - spin_unlock(&info->unused_bgs_lock); - } } spin_lock(&trans->transaction->dirty_bgs_lock); @@ -5939,6 +5926,22 @@ static int update_block_group(struct btrfs_trans_handle *trans, } spin_unlock(&trans->transaction->dirty_bgs_lock); + /* + * No longer have used bytes in this block group, queue it for + * deletion. We do this after adding the block group to the + * dirty list to avoid races between cleaner kthread and space + * cache writeout. + */ + if (!alloc && old_val == 0) { + spin_lock(&info->unused_bgs_lock); + if (list_empty(&cache->bg_list)) { + btrfs_get_block_group(cache); + list_add_tail(&cache->bg_list, + &info->unused_bgs); + } + spin_unlock(&info->unused_bgs_lock); + } + btrfs_put_block_group(cache); total -= num_bytes; bytenr += num_bytes; -- cgit v0.10.2 From 967ef5131e42d6e3bb216c44161d893048a49957 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Fri, 6 Nov 2015 10:36:42 -0800 Subject: btrfs: qgroup: fix quota disable during rescan There's a race condition that leads to a NULL pointer dereference if you disable quotas while a quota rescan is running. To fix this, we just need to wait for the quota rescan worker to actually exit before tearing down the quota structures. Signed-off-by: Justin Maggard Signed-off-by: Chris Mason diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 93e12c1..fd0a196 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -993,9 +993,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) goto out; - spin_lock(&fs_info->qgroup_lock); fs_info->quota_enabled = 0; fs_info->pending_quota_state = 0; + btrfs_qgroup_wait_for_completion(fs_info); + spin_lock(&fs_info->qgroup_lock); quota_root = fs_info->quota_root; fs_info->quota_root = NULL; fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; -- cgit v0.10.2 From 2d9e97761087b46192c18181dfd1e7a930defcfd Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 5 Nov 2015 14:37:58 -0800 Subject: Btrfs: use btrfs_get_fs_root in resolve_indirect_ref The backref code will look up the fs_root we're trying to resolve our indirect refs for, unfortunately we use btrfs_read_fs_root_no_name, which returns -ENOENT if the ref is 0. This isn't helpful for the qgroup stuff with snapshot delete as it won't be able to search down the snapshot we are deleting, which will cause us to miss roots. So use btrfs_get_fs_root and send false for check_ref so we can always get the root we're looking for. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Mark Fasheh Signed-off-by: Chris Mason diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 6dcdb2e..d453d62 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -355,7 +355,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, index = srcu_read_lock(&fs_info->subvol_srcu); - root = btrfs_read_fs_root_no_name(fs_info, &root_key); + root = btrfs_get_fs_root(fs_info, &root_key, false); if (IS_ERR(root)) { srcu_read_unlock(&fs_info->subvol_srcu, index); ret = PTR_ERR(root); -- cgit v0.10.2 From 82bd101b5240d3d1c4078a8017917a40c0dcc514 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 5 Nov 2015 14:38:00 -0800 Subject: btrfs: qgroup: account shared subtree during snapshot delete Commit 0ed4792 ('btrfs: qgroup: Switch to new extent-oriented qgroup mechanism.') removed our qgroup accounting during btrfs_drop_snapshot(). Predictably, this results in qgroup numbers going bad shortly after a snapshot is removed. Fix this by adding a dirty extent record when we encounter extents during our shared subtree walk. This effectively restores the functionality we had with the original shared subtree walking code in 1152651 (btrfs: qgroup: account shared subtrees during snapshot delete). The idea with the original patch (and this one) is that shared subtrees can get skipped during drop_snapshot. The shared subtree walk then allows us a chance to visit those extents and add them to the qgroup work for later processing. This ultimately makes the accounting for drop snapshot work. The new qgroup code nicely handles all the other extents during the tree walk via the ref dec/inc functions so we don't have to add actions beyond what we had originally. Signed-off-by: Mark Fasheh Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e563e5a..4b89680a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8108,21 +8108,47 @@ reada: } /* - * TODO: Modify related function to add related node/leaf to dirty_extent_root, - * for later qgroup accounting. - * - * Current, this function does nothing. + * These may not be seen by the usual inc/dec ref code so we have to + * add them here. */ +static int record_one_subtree_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, + u64 num_bytes) +{ + struct btrfs_qgroup_extent_record *qrecord; + struct btrfs_delayed_ref_root *delayed_refs; + + qrecord = kmalloc(sizeof(*qrecord), GFP_NOFS); + if (!qrecord) + return -ENOMEM; + + qrecord->bytenr = bytenr; + qrecord->num_bytes = num_bytes; + qrecord->old_roots = NULL; + + delayed_refs = &trans->transaction->delayed_refs; + spin_lock(&delayed_refs->lock); + if (btrfs_qgroup_insert_dirty_extent(delayed_refs, qrecord)) + kfree(qrecord); + spin_unlock(&delayed_refs->lock); + + return 0; +} + static int account_leaf_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb) { int nr = btrfs_header_nritems(eb); - int i, extent_type; + int i, extent_type, ret; struct btrfs_key key; struct btrfs_file_extent_item *fi; u64 bytenr, num_bytes; + /* We can be called directly from walk_up_proc() */ + if (!root->fs_info->quota_enabled) + return 0; + for (i = 0; i < nr; i++) { btrfs_item_key_to_cpu(eb, &key, i); @@ -8141,6 +8167,10 @@ static int account_leaf_items(struct btrfs_trans_handle *trans, continue; num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); + + ret = record_one_subtree_extent(trans, root, bytenr, num_bytes); + if (ret) + return ret; } return 0; } @@ -8209,8 +8239,6 @@ static int adjust_slots_upwards(struct btrfs_root *root, /* * root_eb is the subtree root and is locked before this function is called. - * TODO: Modify this function to mark all (including complete shared node) - * to dirty_extent_root to allow it get accounted in qgroup. */ static int account_shared_subtree(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -8288,6 +8316,11 @@ walk_down: btrfs_tree_read_lock(eb); btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); path->locks[level] = BTRFS_READ_LOCK_BLOCKING; + + ret = record_one_subtree_extent(trans, root, child_bytenr, + root->nodesize); + if (ret) + goto out; } if (level == 0) { diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index fd0a196..5279fda 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1462,6 +1462,8 @@ struct btrfs_qgroup_extent_record struct btrfs_qgroup_extent_record *entry; u64 bytenr = record->bytenr; + assert_spin_locked(&delayed_refs->lock); + while (*p) { parent_node = *p; entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record, -- cgit v0.10.2 From dba72cb30b6a4811038128c8a98b268d18ca60fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= Date: Tue, 17 Nov 2015 12:29:32 +0100 Subject: btrfs: fix balance range usage filters in 4.4-rc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a regression in 4.4-rc since commit bc3094673f22 (btrfs: extend balance filter usage to take minimum and maximum) in that existing (non-ranged) balance with -dusage=x no longer works; all chunks are skipped. After staring at the code for a while and wondering why a non-ranged balance would even need min and max thresholds (..which then were not set correctly, leading to the bug) I realized that the only problem was the fact that the filter functions were named wrong, thanks to patching copypasta. Simply renaming both functions lets the existing btrfs-progs call balance with -dusage=x and now the non-ranged filter function is invoked, properly using only a single chunk limit. Signed-off-by: Holger Hoffstätte Fixes: bc3094673f22 ("btrfs: extend balance filter usage to take minimum and maximum") Reviewed-by: Filipe Manana Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f95493b..750285e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3122,7 +3122,7 @@ static int chunk_profiles_filter(u64 chunk_type, return 1; } -static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, +static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, struct btrfs_balance_args *bargs) { struct btrfs_block_group_cache *cache; @@ -3155,7 +3155,7 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, return ret; } -static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, +static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, struct btrfs_balance_args *bargs) { struct btrfs_block_group_cache *cache; -- cgit v0.10.2 From b2467e744f89fcb2e723143c2b78bcbaf391828a Mon Sep 17 00:00:00 2001 From: Haozhong Zhang Date: Wed, 25 Nov 2015 17:21:39 +0800 Subject: KVM: nVMX: remove incorrect vpid check in nested invvpid emulation This patch removes the vpid check when emulating nested invvpid instruction of type all-contexts invalidation. The existing code is incorrect because: (1) According to Intel SDM Vol 3, Section "INVVPID - Invalidate Translations Based on VPID", invvpid instruction does not check vpid in the invvpid descriptor when its type is all-contexts invalidation. (2) According to the same document, invvpid of type all-contexts invalidation does not require there is an active VMCS, so/and get_vmcs12() in the existing code may result in a NULL-pointer dereference. In practice, it can crash both KVM itself and L1 hypervisors that use invvpid (e.g. Xen). Signed-off-by: Haozhong Zhang Signed-off-by: Paolo Bonzini diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 87acc52..af823a3 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7394,11 +7394,6 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) switch (type) { case VMX_VPID_EXTENT_ALL_CONTEXT: - if (get_vmcs12(vcpu)->virtual_processor_id == 0) { - nested_vmx_failValid(vcpu, - VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); - return 1; - } __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02); nested_vmx_succeed(vcpu); break; -- cgit v0.10.2 From c1c90728efa49eab81ae816718d84116a22b790e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 22 Nov 2015 22:40:03 -0500 Subject: ARM: dove: Fix legacy get_irqnr_and_base Commit 5d6bed2a9c ("ARM: dove: fix legacy dove IRQ numbers") shifted IRQ numbers by one but didn't update the get_irqnr_and_base macro accordingly. This macro is involved when CONFIG_MULTI_IRQ_HANDLER is not defined. [jac: 5d6bed2a9c went in to v4.2, but was backported to v3.18] Signed-off-by: Nicolas Pitre Fixes: 5d6bed2a9c ("ARM: dove: fix legacy dove IRQ numbers") Cc: # v3.18+ Signed-off-by: Jason Cooper diff --git a/arch/arm/mach-dove/include/mach/entry-macro.S b/arch/arm/mach-dove/include/mach/entry-macro.S index 72d622b..df1d44b 100644 --- a/arch/arm/mach-dove/include/mach/entry-macro.S +++ b/arch/arm/mach-dove/include/mach/entry-macro.S @@ -18,13 +18,13 @@ @ check low interrupts ldr \irqstat, [\base, #IRQ_CAUSE_LOW_OFF] ldr \tmp, [\base, #IRQ_MASK_LOW_OFF] - mov \irqnr, #31 + mov \irqnr, #32 ands \irqstat, \irqstat, \tmp @ if no low interrupts set, check high interrupts ldreq \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF] ldreq \tmp, [\base, #IRQ_MASK_HIGH_OFF] - moveq \irqnr, #63 + moveq \irqnr, #64 andeqs \irqstat, \irqstat, \tmp @ find first active interrupt source -- cgit v0.10.2 From 4d2ec7e206ae03a51dfbdedc120ce88d403ec926 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sun, 22 Nov 2015 22:44:19 -0500 Subject: ARM: orion5x: Fix legacy get_irqnr_and_base Commit 5be9fc23cd ("ARM: orion5x: fix legacy orion5x IRQ numbers") shifted IRQ numbers by one but didn't update the get_irqnr_and_base macro accordingly. This macro is involved when CONFIG_MULTI_IRQ_HANDLER is not defined. [jac: 5d6bed2a9c went in to v4.2, but was backported to v3.18] Signed-off-by: Nicolas Pitre Fixes: 5be9fc23cd ("ARM: orion5x: fix legacy orion5x IRQ numbers") Cc: # v3.18+ Signed-off-by: Jason Cooper diff --git a/arch/arm/mach-orion5x/include/mach/entry-macro.S b/arch/arm/mach-orion5x/include/mach/entry-macro.S index 79eb502..73919a3 100644 --- a/arch/arm/mach-orion5x/include/mach/entry-macro.S +++ b/arch/arm/mach-orion5x/include/mach/entry-macro.S @@ -21,5 +21,5 @@ @ find cause bits that are unmasked ands \irqstat, \irqstat, \tmp @ clear Z flag if any clzne \irqnr, \irqstat @ calc irqnr - rsbne \irqnr, \irqnr, #31 + rsbne \irqnr, \irqnr, #32 .endm -- cgit v0.10.2 From 13b13dfaaa39ab52b0f433c6744f4638793cbf7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Nov 2015 15:26:47 +0100 Subject: drm/i915: Don't compare has_drrs strictly in pipe config The commit [cfb23ed622d0: drm/i915: Allow fuzzy matching in pipe_config_compare, v2] relaxed the way to compare the pipe configurations, but one new comparison sneaked in there: it added the strict has_drrs value check. This causes a regression on many machines, typically HP laptops with a docking port, where the kernel spews warnings and eventually fails to set the mode properly like: [drm:intel_pipe_config_compare [i915]] *ERROR* mismatch in has_drrs (expected 1, found 0) ------------[ cut here ]------------ WARNING: CPU: 0 PID: 79 at drivers/gpu/drm/i915/intel_display.c:12700 intel_modeset_check_state+0x5aa/0x870 [i915]() pipe state doesn't match! .... This patch just removes the check again for fixing the regression. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104041 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92456 Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=956397 Fixes: cfb23ed622d0 ('drm/i915: Allow fuzzy matching in pipe_config_compare, v2') Cc: # v4.3+ Reported-and-tested-by: Max Lin Signed-off-by: Takashi Iwai Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1448461607-16868-1-git-send-email-tiwai@suse.de Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 71860f8..12a2e9d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12460,7 +12460,6 @@ intel_pipe_config_compare(struct drm_device *dev, if (INTEL_INFO(dev)->gen < 8) { PIPE_CONF_CHECK_M_N(dp_m_n); - PIPE_CONF_CHECK_I(has_drrs); if (current_config->has_drrs) PIPE_CONF_CHECK_M_N(dp_m2_n2); } else -- cgit v0.10.2 From 2540058f7a9d9a843b4d9a28d4f8168dd034d030 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Nov 2015 12:09:56 +0100 Subject: drm/i915: Don't override output type for DDI HDMI Currently a DDI port may register the DP hotplug handler even though it's used with HDMI, and the DP HPD handler overrides the encoder type forcibly to DP. This caused the inconsistency on a machine connected with a HDMI monitor; upon a hotplug event, the DDI port is suddenly switched to be handled as a DP although the same monitor is kept connected, and this leads to the erroneous blank output. This patch papers over the bug by excluding the previous HDMI encoder type from this override. This should be fixed more fundamentally, e.g. by moving the encoder type reset from the HPD or by having individual encoder objects for HDMI and DP. But since the bug has been present for a long time (3.17), it's better to have a quick-n-dirty fix for now, and keep working on a cleaner fix. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=955190 Fixes: 0e32b39ceed6 ('drm/i915: add DP 1.2 MST support (v0.7)') Cc: # v3.17+ Signed-off-by: Takashi Iwai Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1447931396-19147-1-git-send-email-tiwai@suse.de Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 09bdd94..d34e643 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5153,7 +5153,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) enum intel_display_power_domain power_domain; enum irqreturn ret = IRQ_NONE; - if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) + if (intel_dig_port->base.type != INTEL_OUTPUT_EDP && + intel_dig_port->base.type != INTEL_OUTPUT_HDMI) intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) { -- cgit v0.10.2 From fbc416ff86183e2203cdf975e2881d7c164b0271 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 12:12:21 +0100 Subject: arm64: fix building without CONFIG_UID16 As reported by Michal Simek, building an ARM64 kernel with CONFIG_UID16 disabled currently fails because the system call table still needs to reference the individual function entry points that are provided by kernel/sys_ni.c in this case, and the declarations are hidden inside of #ifdef CONFIG_UID16: arch/arm64/include/asm/unistd32.h:57:8: error: 'sys_lchown16' undeclared here (not in a function) __SYSCALL(__NR_lchown, sys_lchown16) I believe this problem only exists on ARM64, because older architectures tend to not need declarations when their system call table is built in assembly code, while newer architectures tend to not need UID16 support. ARM64 only uses these system calls for compatibility with 32-bit ARM binaries. This changes the CONFIG_UID16 check into CONFIG_HAVE_UID16, which is set unconditionally on ARM64 with CONFIG_COMPAT, so we see the declarations whenever we need them, but otherwise the behavior is unchanged. Fixes: af1839eb4bd4 ("Kconfig: clean up the long arch list for the UID16 config option") Signed-off-by: Arnd Bergmann Acked-by: Will Deacon Cc: stable@vger.kernel.org Signed-off-by: Catalin Marinas diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index a156b82..c2b66a2 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -524,7 +524,7 @@ asmlinkage long sys_chown(const char __user *filename, asmlinkage long sys_lchown(const char __user *filename, uid_t user, gid_t group); asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group); -#ifdef CONFIG_UID16 +#ifdef CONFIG_HAVE_UID16 asmlinkage long sys_chown16(const char __user *filename, old_uid_t user, old_gid_t group); asmlinkage long sys_lchown16(const char __user *filename, diff --git a/include/linux/types.h b/include/linux/types.h index 70d8500..70dd3df 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -35,7 +35,7 @@ typedef __kernel_gid16_t gid16_t; typedef unsigned long uintptr_t; -#ifdef CONFIG_UID16 +#ifdef CONFIG_HAVE_UID16 /* This is defined by include/asm-{arch}/posix_types.h */ typedef __kernel_old_uid_t old_uid_t; typedef __kernel_old_gid_t old_gid_t; -- cgit v0.10.2 From c03784ee8aa99bf6a412e3febf8801c3df86e0ba Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 23 Nov 2015 15:09:36 +0000 Subject: arm64: mm: fix fault_info table xFSC decoding We are missing descriptions for some valid xFSC values in the fault info table (e.g. "TLB conflict abort"), and have erroneous descriptions for reserved values (e.g. "asynchronous external abort", "debug event"). This patch adds the missing xFSC values, and removes erroneous decoding of values reserved by the architecture, as described in ARM DDI 0487A.h. At the same time, fixed the unbalanced brackets for the synchronous parity error strings in the table. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 19211c4..92ddac1 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -393,16 +393,16 @@ static struct fault_info { { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, - { do_bad, SIGBUS, 0, "reserved access flag fault" }, + { do_bad, SIGBUS, 0, "unknown 8" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, - { do_bad, SIGBUS, 0, "reserved permission fault" }, + { do_bad, SIGBUS, 0, "unknown 12" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, { do_bad, SIGBUS, 0, "synchronous external abort" }, - { do_bad, SIGBUS, 0, "asynchronous external abort" }, + { do_bad, SIGBUS, 0, "unknown 17" }, { do_bad, SIGBUS, 0, "unknown 18" }, { do_bad, SIGBUS, 0, "unknown 19" }, { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, @@ -410,16 +410,16 @@ static struct fault_info { { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, { do_bad, SIGBUS, 0, "synchronous parity error" }, - { do_bad, SIGBUS, 0, "asynchronous parity error" }, + { do_bad, SIGBUS, 0, "unknown 25" }, { do_bad, SIGBUS, 0, "unknown 26" }, { do_bad, SIGBUS, 0, "unknown 27" }, - { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, - { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, - { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, - { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" }, { do_bad, SIGBUS, 0, "unknown 32" }, { do_bad, SIGBUS, BUS_ADRALN, "alignment fault" }, - { do_bad, SIGBUS, 0, "debug event" }, + { do_bad, SIGBUS, 0, "unknown 34" }, { do_bad, SIGBUS, 0, "unknown 35" }, { do_bad, SIGBUS, 0, "unknown 36" }, { do_bad, SIGBUS, 0, "unknown 37" }, @@ -433,21 +433,21 @@ static struct fault_info { { do_bad, SIGBUS, 0, "unknown 45" }, { do_bad, SIGBUS, 0, "unknown 46" }, { do_bad, SIGBUS, 0, "unknown 47" }, - { do_bad, SIGBUS, 0, "unknown 48" }, + { do_bad, SIGBUS, 0, "TLB conflict abort" }, { do_bad, SIGBUS, 0, "unknown 49" }, { do_bad, SIGBUS, 0, "unknown 50" }, { do_bad, SIGBUS, 0, "unknown 51" }, { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" }, - { do_bad, SIGBUS, 0, "unknown 53" }, + { do_bad, SIGBUS, 0, "implementation fault (unsupported exclusive)" }, { do_bad, SIGBUS, 0, "unknown 54" }, { do_bad, SIGBUS, 0, "unknown 55" }, { do_bad, SIGBUS, 0, "unknown 56" }, { do_bad, SIGBUS, 0, "unknown 57" }, - { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" }, + { do_bad, SIGBUS, 0, "unknown 58" }, { do_bad, SIGBUS, 0, "unknown 59" }, { do_bad, SIGBUS, 0, "unknown 60" }, - { do_bad, SIGBUS, 0, "unknown 61" }, - { do_bad, SIGBUS, 0, "unknown 62" }, + { do_bad, SIGBUS, 0, "section domain fault" }, + { do_bad, SIGBUS, 0, "page domain fault" }, { do_bad, SIGBUS, 0, "unknown 63" }, }; -- cgit v0.10.2 From 3b12acf4c999abaf93023af4bd78d931bce2520c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 23 Nov 2015 11:09:11 +0000 Subject: arm64: efi: correctly map runtime regions The kernel may use a page granularity of 4K, 16K, or 64K depending on configuration. When mapping EFI runtime regions, we use memrange_efi_to_native to round the physical base address of a region down to a kernel page boundary, and round the size up to a kernel page boundary, adding the residue left over from rounding down the physical base address. We do not round down the virtual base address. In __create_mapping we account for the offset of the virtual base from a granule boundary, adding the residue to the size before rounding the base down to said granule boundary. Thus we account for the residue twice, and when the residue is non-zero will cause __create_mapping to map an additional page at the end of the region. Depending on the memory map, this page may be in a region we are not intended/permitted to map, or may clash with a different region that we wish to map. In typical cases, mapping the next item in the memory map will overwrite the erroneously created entry, as we sort the memory map in the stub. As __create_mapping can cope with base addresses which are not page aligned, we can instead rely on it to map the region appropriately, and simplify efi_virtmap_init by removing the unnecessary code. Signed-off-by: Mark Rutland Reviewed-by: Ard Biesheuvel Cc: Leif Lindholm Cc: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index fc5508e..fe7cd1a 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -227,7 +227,6 @@ static bool __init efi_virtmap_init(void) init_new_context(NULL, &efi_mm); for_each_efi_memory_desc(&memmap, md) { - u64 paddr, npages, size; pgprot_t prot; if (!(md->attribute & EFI_MEMORY_RUNTIME)) @@ -235,11 +234,6 @@ static bool __init efi_virtmap_init(void) if (md->virt_addr == 0) return false; - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - pr_info(" EFI remap 0x%016llx => %p\n", md->phys_addr, (void *)md->virt_addr); @@ -256,7 +250,8 @@ static bool __init efi_virtmap_init(void) else prot = PAGE_KERNEL; - create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, + create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr, + md->num_pages << EFI_PAGE_SHIFT, __pgprot(pgprot_val(prot) | PTE_NG)); } return true; -- cgit v0.10.2 From 9c565e3386fdc804a61f8c116efc2c5999ba46e1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 23 Nov 2015 16:38:12 -0500 Subject: drm/radeon: make some dpm errors debug only "Could not force DPM to low", etc. is usually harmless and just confuses users. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/rv730_dpm.c b/drivers/gpu/drm/radeon/rv730_dpm.c index 3f5e1cf..d37ba2c 100644 --- a/drivers/gpu/drm/radeon/rv730_dpm.c +++ b/drivers/gpu/drm/radeon/rv730_dpm.c @@ -464,7 +464,7 @@ void rv730_stop_dpm(struct radeon_device *rdev) result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); if (result != PPSMC_Result_OK) - DRM_ERROR("Could not force DPM to low\n"); + DRM_DEBUG("Could not force DPM to low\n"); WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index d24c58c..e830c89 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -193,7 +193,7 @@ void rv770_stop_dpm(struct radeon_device *rdev) result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); if (result != PPSMC_Result_OK) - DRM_ERROR("Could not force DPM to low.\n"); + DRM_DEBUG("Could not force DPM to low.\n"); WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); @@ -1418,7 +1418,7 @@ int rv770_resume_smc(struct radeon_device *rdev) int rv770_set_sw_state(struct radeon_device *rdev) { if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK) - DRM_ERROR("rv770_set_sw_state failed\n"); + DRM_DEBUG("rv770_set_sw_state failed\n"); return 0; } -- cgit v0.10.2 From 19cebbcb04c8277bb8a7905957c8af11967c4e28 Mon Sep 17 00:00:00 2001 From: Christoph Biedl Date: Wed, 25 Nov 2015 07:47:40 +0100 Subject: isdn: Partially revert debug format string usage clean up Commit 35a4a57 ("isdn: clean up debug format string usage") introduced a safeguard to avoid accidential format string interpolation of data when calling debugl1 or HiSax_putstatus. This did however not take into account VHiSax_putstatus (called by HiSax_putstatus) does *not* call vsprintf if the head parameter is NULL - the format string is treated as plain text then instead. As a result, the string "%s" is processed literally, and the actual information is lost. This affects the isdnlog userspace program which stopped logging information since that commit. So revert the HiSax_putstatus invocations to the previous state. Fixes: 35a4a5733b0a ("isdn: clean up debug format string usage") Cc: Kees Cook Cc: Karsten Keil Signed-off-by: Christoph Biedl Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index b33f53b..bf04d2a 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1896,7 +1896,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if) ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 4a48255..90449e1 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -901,7 +901,7 @@ Begin: ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3); } diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index b1fad81..13b2151 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -674,7 +674,7 @@ receive_emsg(struct IsdnCardState *cs) ptr--; *ptr++ = '\n'; *ptr = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index b420f8b..ba4beb2 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -1179,7 +1179,7 @@ LogFrame(struct IsdnCardState *cs, u_char *buf, int size) dp--; *dp++ = '\n'; *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); } @@ -1246,7 +1246,7 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) } if (finish) { *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); return; } if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ @@ -1509,5 +1509,5 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) dp += sprintf(dp, "Unknown protocol %x!", buf[0]); } *dp = 0; - HiSax_putstatus(cs, NULL, "%s", cs->dlog); + HiSax_putstatus(cs, NULL, cs->dlog); } -- cgit v0.10.2 From dcd8376c369fa8fde8269e721b14f50475dd397b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 25 Nov 2015 10:12:54 -0700 Subject: Revert "blk-flush: Queue through IO scheduler when flush not required" This reverts commit 1b2ff19e6a957b1ef0f365ad331b608af80e932e. Jan writes: -- Thanks for report! After some investigation I found out we allocate elevator specific data in __get_request() only for non-flush requests. And this is actually required since the flush machinery uses the space in struct request for something else. Doh. So my patch is just wrong and not easy to fix since at the time __get_request() is called we are not sure whether the flush machinery will be used in the end. Jens, please revert 1b2ff19e6a957b1ef0f365ad331b608af80e932e. Thanks! I'm somewhat surprised that you can reliably hit the race where flushing gets disabled for the device just while the request is in flight. But I guess during boot it makes some sense. -- So let's just revert it, we can fix the queue run manually after the fact. This race is rare enough that it didn't trigger in testing, it requires the specific disable-while-in-flight scenario to trigger. diff --git a/block/blk-flush.c b/block/blk-flush.c index c81d56e..9c423e5 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -422,7 +422,7 @@ void blk_insert_flush(struct request *rq) if (q->mq_ops) { blk_mq_insert_request(rq, false, false, true); } else - q->elevator->type->ops.elevator_add_req_fn(q, rq); + list_add_tail(&rq->queuelist, &q->queue_head); return; } -- cgit v0.10.2 From c9da161c6517ba12154059d3b965c2cbaf16f90f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 24 Nov 2015 21:28:15 +0100 Subject: bpf: fix clearing on persistent program array maps Currently, when having map file descriptors pointing to program arrays, there's still the issue that we unconditionally flush program array contents via bpf_fd_array_map_clear() in bpf_map_release(). This happens when such a file descriptor is released and is independent of the map's refcount. Having this flush independent of the refcount is for a reason: there can be arbitrary complex dependency chains among tail calls, also circular ones (direct or indirect, nesting limit determined during runtime), and we need to make sure that the map drops all references to eBPF programs it holds, so that the map's refcount can eventually drop to zero and initiate its freeing. Btw, a walk of the whole dependency graph would not be possible for various reasons, one being complexity and another one inconsistency, i.e. new programs can be added to parts of the graph at any time, so there's no guaranteed consistent state for the time of such a walk. Now, the program array pinning itself works, but the issue is that each derived file descriptor on close would nevertheless call unconditionally into bpf_fd_array_map_clear(). Instead, keep track of users and postpone this flush until the last reference to a user is dropped. As this only concerns a subset of references (f.e. a prog array could hold a program that itself has reference on the prog array holding it, etc), we need to track them separately. Short analysis on the refcounting: on map creation time usercnt will be one, so there's no change in behaviour for bpf_map_release(), if unpinned. If we already fail in map_create(), we are immediately freed, and no file descriptor has been made public yet. In bpf_obj_pin_user(), we need to probe for a possible map in bpf_fd_probe_obj() already with a usercnt reference, so before we drop the reference on the fd with fdput(). Therefore, if actual pinning fails, we need to drop that reference again in bpf_any_put(), otherwise we keep holding it. When last reference drops on the inode, the bpf_any_put() in bpf_evict_inode() will take care of dropping the usercnt again. In the bpf_obj_get_user() case, the bpf_any_get() will grab a reference on the usercnt, still at a time when we have the reference on the path. Should we later on fail to grab a new file descriptor, bpf_any_put() will drop it, otherwise we hold it until bpf_map_release() time. Joint work with Alexei. Fixes: b2197755b263 ("bpf: add support for persistent maps/progs") Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller diff --git a/include/linux/bpf.h b/include/linux/bpf.h index de464e6..83d1926 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -40,6 +40,7 @@ struct bpf_map { struct user_struct *user; const struct bpf_map_ops *ops; struct work_struct work; + atomic_t usercnt; }; struct bpf_map_type_list { @@ -167,8 +168,10 @@ struct bpf_prog *bpf_prog_get(u32 ufd); void bpf_prog_put(struct bpf_prog *prog); void bpf_prog_put_rcu(struct bpf_prog *prog); -struct bpf_map *bpf_map_get(u32 ufd); +struct bpf_map *bpf_map_get_with_uref(u32 ufd); struct bpf_map *__bpf_map_get(struct fd f); +void bpf_map_inc(struct bpf_map *map, bool uref); +void bpf_map_put_with_uref(struct bpf_map *map); void bpf_map_put(struct bpf_map *map); extern int sysctl_unprivileged_bpf_disabled; diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index be6d726..5a8a797 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -34,7 +34,7 @@ static void *bpf_any_get(void *raw, enum bpf_type type) atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt); break; case BPF_TYPE_MAP: - atomic_inc(&((struct bpf_map *)raw)->refcnt); + bpf_map_inc(raw, true); break; default: WARN_ON_ONCE(1); @@ -51,7 +51,7 @@ static void bpf_any_put(void *raw, enum bpf_type type) bpf_prog_put(raw); break; case BPF_TYPE_MAP: - bpf_map_put(raw); + bpf_map_put_with_uref(raw); break; default: WARN_ON_ONCE(1); @@ -64,7 +64,7 @@ static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type) void *raw; *type = BPF_TYPE_MAP; - raw = bpf_map_get(ufd); + raw = bpf_map_get_with_uref(ufd); if (IS_ERR(raw)) { *type = BPF_TYPE_PROG; raw = bpf_prog_get(ufd); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 0d3313d..4a8f3c1 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -82,6 +82,14 @@ static void bpf_map_free_deferred(struct work_struct *work) map->ops->map_free(map); } +static void bpf_map_put_uref(struct bpf_map *map) +{ + if (atomic_dec_and_test(&map->usercnt)) { + if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) + bpf_fd_array_map_clear(map); + } +} + /* decrement map refcnt and schedule it for freeing via workqueue * (unrelying map implementation ops->map_free() might sleep) */ @@ -93,17 +101,15 @@ void bpf_map_put(struct bpf_map *map) } } -static int bpf_map_release(struct inode *inode, struct file *filp) +void bpf_map_put_with_uref(struct bpf_map *map) { - struct bpf_map *map = filp->private_data; - - if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) - /* prog_array stores refcnt-ed bpf_prog pointers - * release them all when user space closes prog_array_fd - */ - bpf_fd_array_map_clear(map); - + bpf_map_put_uref(map); bpf_map_put(map); +} + +static int bpf_map_release(struct inode *inode, struct file *filp) +{ + bpf_map_put_with_uref(filp->private_data); return 0; } @@ -142,6 +148,7 @@ static int map_create(union bpf_attr *attr) return PTR_ERR(map); atomic_set(&map->refcnt, 1); + atomic_set(&map->usercnt, 1); err = bpf_map_charge_memlock(map); if (err) @@ -174,7 +181,14 @@ struct bpf_map *__bpf_map_get(struct fd f) return f.file->private_data; } -struct bpf_map *bpf_map_get(u32 ufd) +void bpf_map_inc(struct bpf_map *map, bool uref) +{ + atomic_inc(&map->refcnt); + if (uref) + atomic_inc(&map->usercnt); +} + +struct bpf_map *bpf_map_get_with_uref(u32 ufd) { struct fd f = fdget(ufd); struct bpf_map *map; @@ -183,7 +197,7 @@ struct bpf_map *bpf_map_get(u32 ufd) if (IS_ERR(map)) return map; - atomic_inc(&map->refcnt); + bpf_map_inc(map, true); fdput(f); return map; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c607305..a7945d1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2021,8 +2021,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) * will be used by the valid program until it's unloaded * and all maps are released in free_bpf_prog_info() */ - atomic_inc(&map->refcnt); - + bpf_map_inc(map, false); fdput(f); next_insn: insn++; -- cgit v0.10.2 From 29f5b34ca1a191c2cf4f6c8c12f4dec56e8d3bc1 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 13 Nov 2015 17:29:53 +0100 Subject: arm: omap2+: add missing HWMOD_NO_IDLEST in 81xx hwmod data Add missing HWMOD_NO_IDLEST hwmod flag for entries not having omap4 clkctrl values. The emac0 hwmod flag fixes the davinci_emac driver probe since the return of pm_resume() call is now checked. This solves the following boot errors : [ 0.121429] omap_hwmod: l4_ls: _wait_target_ready failed: -16 [ 0.121441] omap_hwmod: l4_ls: cannot be enabled for reset (3) [ 0.124342] omap_hwmod: l4_hs: _wait_target_ready failed: -16 [ 0.124352] omap_hwmod: l4_hs: cannot be enabled for reset (3) [ 1.967228] omap_hwmod: emac0: _wait_target_ready failed: -16 Cc: Brian Hutchinson Signed-off-by: Neil Armstrong Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c index b1288f5..6256052 100644 --- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c @@ -144,6 +144,7 @@ static struct omap_hwmod dm81xx_l4_ls_hwmod = { .name = "l4_ls", .clkdm_name = "alwon_l3s_clkdm", .class = &l4_hwmod_class, + .flags = HWMOD_NO_IDLEST, }; /* @@ -155,6 +156,7 @@ static struct omap_hwmod dm81xx_l4_hs_hwmod = { .name = "l4_hs", .clkdm_name = "alwon_l3_med_clkdm", .class = &l4_hwmod_class, + .flags = HWMOD_NO_IDLEST, }; /* L3 slow -> L4 ls peripheral interface running at 125MHz */ @@ -850,6 +852,7 @@ static struct omap_hwmod dm816x_emac0_hwmod = { .name = "emac0", .clkdm_name = "alwon_ethernet_clkdm", .class = &dm816x_emac_hwmod_class, + .flags = HWMOD_NO_IDLEST, }; static struct omap_hwmod_ocp_if dm81xx_l4_hs__emac0 = { -- cgit v0.10.2 From 918af9f941af9995fcaa7ef1eb67c433a492e2b3 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 16 Nov 2015 19:38:53 +0200 Subject: ARM: OMAP4+: SMP: use lockless clkdm/pwrdm api in omap4_boot_secondary OMAP CPU hotplug uses cpu1's clocks and power domains for CPU1 wake up from low power states (or turn on CPU1). This part of code is also part of system suspend (disable_nonboot_cpus()). >From other side, cpu1's clocks and power domains are used by CPUIdle. All above functionality is mutually exclusive and, therefore, lockless clkdm/pwrdm api can be used in omap4_boot_secondary(). This fixes below back-trace on -RT which is triggered by pwrdm_lock/unlock(): BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:917 in_atomic(): 1, irqs_disabled(): 0, pid: 118, name: sh 9 locks held by sh/118: #0: (sb_writers#4){.+.+.+}, at: [] vfs_write+0x13c/0x164 #1: (&of->mutex){+.+.+.}, at: [] kernfs_fop_write+0x48/0x19c #2: (s_active#24){.+.+.+}, at: [] kernfs_fop_write+0x50/0x19c #3: (device_hotplug_lock){+.+.+.}, at: [] lock_device_hotplug_sysfs+0xc/0x4c #4: (&dev->mutex){......}, at: [] device_online+0x14/0x88 #5: (cpu_add_remove_lock){+.+.+.}, at: [] cpu_up+0x50/0x1a0 #6: (cpu_hotplug.lock){++++++}, at: [] cpu_hotplug_begin+0x0/0xc4 #7: (cpu_hotplug.lock#2){+.+.+.}, at: [] cpu_hotplug_begin+0x78/0xc4 #8: (boot_lock){+.+...}, at: [] omap4_boot_secondary+0x1c/0x178 Preemption disabled at:[< (null)>] (null) CPU: 0 PID: 118 Comm: sh Not tainted 4.1.12-rt11-01998-gb4a62c3-dirty #137 Hardware name: Generic DRA74X (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x80/0x94) [] (dump_stack) from [] (rt_spin_lock+0x24/0x54) [] (rt_spin_lock) from [] (clkdm_wakeup+0x10/0x2c) [] (clkdm_wakeup) from [] (omap4_boot_secondary+0x88/0x178) [] (omap4_boot_secondary) from [] (__cpu_up+0xc4/0x164) [] (__cpu_up) from [] (cpu_up+0x15c/0x1a0) [] (cpu_up) from [] (device_online+0x64/0x88) [] (device_online) from [] (online_store+0x68/0x74) [] (online_store) from [] (kernfs_fop_write+0xb8/0x19c) [] (kernfs_fop_write) from [] (__vfs_write+0x20/0xd8) [] (__vfs_write) from [] (vfs_write+0x90/0x164) [] (vfs_write) from [] (SyS_write+0x44/0x9c) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x54) CPU1: smp_ops.cpu_die() returned, trying to resuscitate Cc: Tero Kristo Signed-off-by: Grygorii Strashko Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 5305ec7..79e1f87 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -143,9 +143,9 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) * Ensure that CPU power state is set to ON to avoid CPU * powerdomain transition on wfi */ - clkdm_wakeup(cpu1_clkdm); - omap_set_pwrdm_state(cpu1_pwrdm, PWRDM_POWER_ON); - clkdm_allow_idle(cpu1_clkdm); + clkdm_wakeup_nolock(cpu1_clkdm); + pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON); + clkdm_allow_idle_nolock(cpu1_clkdm); if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { while (gic_dist_disabled()) { -- cgit v0.10.2 From 7c7a0e945349a3d0d497d7f32db6ed33d4031110 Mon Sep 17 00:00:00 2001 From: Gabriele Paoloni Date: Wed, 11 Nov 2015 09:12:25 +0800 Subject: ARM/PCI: Move align_resource function pointer to pci_host_bridge structure Commit b3a72384fe29 ("ARM/PCI: Replace pci_sys_data->align_resource with global function pointer") introduced an ARM-specific align_resource() function pointer. This is not portable to other arches and doesn't work for platforms with two different PCIe host bridge controllers. Move the function pointer to the pci_host_bridge structure so each host bridge driver can specify its own align_resource() function. Signed-off-by: Gabriele Paoloni Signed-off-by: Bjorn Helgaas Reviewed-by: Arnd Bergmann diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 6551d28..066f7f9 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -17,11 +17,6 @@ #include static int debug_pci; -static resource_size_t (*align_resource)(struct pci_dev *dev, - const struct resource *res, - resource_size_t start, - resource_size_t size, - resource_size_t align) = NULL; /* * We can't use pci_get_device() here since we are @@ -461,7 +456,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; - align_resource = hw->align_resource; INIT_LIST_HEAD(&sys->resources); if (hw->private_data) @@ -470,6 +464,8 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, ret = hw->setup(nr, sys); if (ret > 0) { + struct pci_host_bridge *host_bridge; + ret = pcibios_init_resources(nr, sys); if (ret) { kfree(sys); @@ -491,6 +487,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, busnr = sys->bus->busn_res.end + 1; list_add(&sys->node, head); + + host_bridge = pci_find_host_bridge(sys->bus); + host_bridge->align_resource = hw->align_resource; } else { kfree(sys); if (ret < 0) @@ -578,14 +577,18 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, { struct pci_dev *dev = data; resource_size_t start = res->start; + struct pci_host_bridge *host_bridge; if (res->flags & IORESOURCE_IO && start & 0x300) start = (start + 0x3ff) & ~0x3ff; start = (start + align - 1) & ~(align - 1); - if (align_resource) - return align_resource(dev, res, start, size, align); + host_bridge = pci_find_host_bridge(dev->bus); + + if (host_bridge->align_resource) + return host_bridge->align_resource(dev, res, + start, size, align); return start; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fd2f03f..d390fc1 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -337,6 +337,4 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) } #endif -struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); - #endif /* DRIVERS_PCI_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index e828e7b..6ae25aa 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -412,9 +412,18 @@ struct pci_host_bridge { void (*release_fn)(struct pci_host_bridge *); void *release_data; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ + /* Resource alignment requirements */ + resource_size_t (*align_resource)(struct pci_dev *dev, + const struct resource *res, + resource_size_t start, + resource_size_t size, + resource_size_t align); }; #define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev) + +struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); + void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void (*release_fn)(struct pci_host_bridge *), void *release_data); -- cgit v0.10.2 From 616c319683e34d10952b74a73ee12e080531b476 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 25 Nov 2015 13:50:45 -0500 Subject: nfs: ensure that attrcache is revalidated after a SETATTR If we get no post-op attributes back from a SETATTR operation, then no attributes will of course be updated during the call to nfs_update_inode. We know however that the attributes are invalid at that point, since we just changed some of them. At the very least, the ctime will be bogus. If we get no post-op attributes back on the call, mark the attrcache invalid to reflect that fact. Reviewed-by: Steve French Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 326d9e1..eda3da3 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -618,7 +618,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); nfs_vmtruncate(inode, attr->ia_size); } - nfs_update_inode(inode, fattr); + if (fattr->valid) + nfs_update_inode(inode, fattr); + else + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; spin_unlock(&inode->i_lock); } EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); -- cgit v0.10.2 From c812012f9ca7cf89c9e1a1cd512e6c3b5be04b85 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 25 Nov 2015 13:50:11 -0500 Subject: nfs: if we have no valid attrs, then don't declare the attribute cache valid If we pass in an empty nfs_fattr struct to nfs_update_inode, it will (correctly) not update any of the attributes, but it then clears the NFS_INO_INVALID_ATTR flag, which indicates that the attributes are up to date. Don't clear the flag if the fattr struct has no valid attrs to apply. Reviewed-by: Steve French Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index eda3da3..31b0a52 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1827,7 +1827,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0) nfsi->attr_gencount = fattr->gencount; } - invalid &= ~NFS_INO_INVALID_ATTR; + + /* Don't declare attrcache up to date if there were no attrs! */ + if (fattr->valid != 0) + invalid &= ~NFS_INO_INVALID_ATTR; + /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) -- cgit v0.10.2 From 4f2e9dce0c6348a95eaa56ade9bab18572221088 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 25 Nov 2015 13:43:14 -0500 Subject: nfs4: resend LAYOUTGET when there is a race that changes the seqid pnfs_layout_process will check the returned layout stateid against what the kernel has in-core. If it turns out that the stateid we received is older, then we should resend the LAYOUTGET instead of falling back to MDS I/O. Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org # 3.18+ Signed-off-by: Trond Myklebust diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 93496c0..5a8ae21 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo, dprintk("--> %s\n", __func__); - lgp = kzalloc(sizeof(*lgp), gfp_flags); - if (lgp == NULL) - return NULL; + /* + * Synchronously retrieve layout information from server and + * store in lseg. If we race with a concurrent seqid morphing + * op, then re-send the LAYOUTGET. + */ + do { + lgp = kzalloc(sizeof(*lgp), gfp_flags); + if (lgp == NULL) + return NULL; + + i_size = i_size_read(ino); + + lgp->args.minlength = PAGE_CACHE_SIZE; + if (lgp->args.minlength > range->length) + lgp->args.minlength = range->length; + if (range->iomode == IOMODE_READ) { + if (range->offset >= i_size) + lgp->args.minlength = 0; + else if (i_size - range->offset < lgp->args.minlength) + lgp->args.minlength = i_size - range->offset; + } + lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; + lgp->args.range = *range; + lgp->args.type = server->pnfs_curr_ld->id; + lgp->args.inode = ino; + lgp->args.ctx = get_nfs_open_context(ctx); + lgp->gfp_flags = gfp_flags; + lgp->cred = lo->plh_lc_cred; - i_size = i_size_read(ino); + lseg = nfs4_proc_layoutget(lgp, gfp_flags); + } while (lseg == ERR_PTR(-EAGAIN)); - lgp->args.minlength = PAGE_CACHE_SIZE; - if (lgp->args.minlength > range->length) - lgp->args.minlength = range->length; - if (range->iomode == IOMODE_READ) { - if (range->offset >= i_size) - lgp->args.minlength = 0; - else if (i_size - range->offset < lgp->args.minlength) - lgp->args.minlength = i_size - range->offset; - } - lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; - lgp->args.range = *range; - lgp->args.type = server->pnfs_curr_ld->id; - lgp->args.inode = ino; - lgp->args.ctx = get_nfs_open_context(ctx); - lgp->gfp_flags = gfp_flags; - lgp->cred = lo->plh_lc_cred; - - /* Synchronously retrieve layout information from server and - * store in lseg. - */ - lseg = nfs4_proc_layoutget(lgp, gfp_flags); if (IS_ERR(lseg)) { switch (PTR_ERR(lseg)) { case -ENOMEM: @@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) /* existing state ID, make sure the sequence number matches. */ if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { dprintk("%s forget reply due to sequence\n", __func__); + status = -EAGAIN; goto out_forget_reply; } pnfs_set_layout_stateid(lo, &res->stateid, false); -- cgit v0.10.2 From c21ac06648a7a9985fa81a53ba3a65569a1de388 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 25 Nov 2015 23:03:49 +0100 Subject: clk: mmp: add linux/clk.h includes The common clk implementation for MMP broke without anyone noticing when we stopped including linux/clk.h from the clk-provider header. This did not show up in the defconfig builds because those use the legacy MMP clk drivers, and it did not show up in my randconfig tests either because I was testing with my mmp multiplatform series applied, which at some point gained the fixup. This fixes the three broken files. Signed-off-by: Arnd Bergmann Fixes: 61ae76563ec3 ("clk: Remove clk.h from clk-provider.h") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index 09d2832..71fd293 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -9,6 +9,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c index 93e967c..7524491 100644 --- a/drivers/clk/mmp/clk-pxa168.c +++ b/drivers/clk/mmp/clk-pxa168.c @@ -9,6 +9,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c index 993abcd..37ba04b 100644 --- a/drivers/clk/mmp/clk-pxa910.c +++ b/drivers/clk/mmp/clk-pxa910.c @@ -9,6 +9,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include -- cgit v0.10.2 From 656279a1f3b210cf48ccc572fd7c6b8e2250be77 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 22 Nov 2015 18:16:15 -0500 Subject: x86 smpboot: Re-enable init_udelay=0 by default on modern CPUs commit f1ccd249319e allowed the cmdline "cpu_init_udelay=" to work with all values, including the default of 10000. But in setting the default of 10000, it over-rode the code that sets the delay 0 on modern processors. Also, tidy up use of INT/UINT. Fixes: f1ccd249319e "x86/smpboot: Fix cpu_init_udelay=10000 corner case boot parameter misbehavior" Reported-by: Shane Signed-off-by: Len Brown Cc: dparsons@brightdsl.net Cc: stable@kernel.org Link: http://lkml.kernel.org/r/9082eb809ef40dad02db714759c7aaf618c518d4.1448232494.git.len.brown@intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 892ee2e5..fbabe4f 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -509,7 +509,7 @@ void __inquire_remote_apic(int apicid) */ #define UDELAY_10MS_DEFAULT 10000 -static unsigned int init_udelay = INT_MAX; +static unsigned int init_udelay = UINT_MAX; static int __init cpu_init_udelay(char *str) { @@ -522,14 +522,15 @@ early_param("cpu_init_udelay", cpu_init_udelay); static void __init smp_quirk_init_udelay(void) { /* if cmdline changed it from default, leave it alone */ - if (init_udelay != INT_MAX) + if (init_udelay != UINT_MAX) return; /* if modern processor, use no delay */ if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) || - ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) + ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) { init_udelay = 0; - + return; + } /* else, use legacy delay */ init_udelay = UDELAY_10MS_DEFAULT; } -- cgit v0.10.2 From 584ee3dcb1d6232857c1e38bb28d9f6bf0ec89f5 Mon Sep 17 00:00:00 2001 From: Alexandra Yates Date: Wed, 18 Nov 2015 14:58:40 -0800 Subject: intel_pstate: Fix "performance" mode behavior with HWP enabled If hardware-driven P-state selection (HWP) is enabled, the "performance" mode of intel_pstate should only allow the processor to use the highest-performance P-state available. That is not the case currently, so make it actually happen. Acked-by: Srinivas Pandruvada Signed-off-by: Alexandra Yates [ rjw: Subject and changelog ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 8ad1f95..4d07cbd 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1101,6 +1101,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) policy->max >= policy->cpuinfo.max_freq) { pr_debug("intel_pstate: set performance\n"); limits = &performance_limits; + if (hwp_active) + intel_pstate_hwp_set(); return 0; } -- cgit v0.10.2 From 397737223c59e89dca7305feb6528caef8fbef84 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 13 Nov 2015 16:46:47 -0500 Subject: sd: Make discard granularity match logical block size when LBPRZ=1 A device may report an OPTIMAL UNMAP GRANULARITY and UNMAP GRANULARITY ALIGNMENT in the Block Limits VPD. These parameters describe the device's internal provisioning allocation units. By default the block layer will round and align any discard requests based on these limits. If a device reports LBPRZ=1 to guarantee zeroes after discard, however, it is imperative that the block layer does not leave out any parts of the requested block range. Otherwise the device can not do the required zeroing of any partial allocation units and this can lead to data corruption. Since the dm thinp personality relies on the block layer's current behavior and is unable to deal with partial discard blocks we work around the problem by setting the granularity to match the logical block size when LBPRZ is enabled. Signed-off-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f724777..e868d39 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -637,11 +637,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) unsigned int max_blocks = 0; q->limits.discard_zeroes_data = 0; - q->limits.discard_alignment = sdkp->unmap_alignment * - logical_block_size; - q->limits.discard_granularity = - max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); + + /* + * When LBPRZ is reported, discard alignment and granularity + * must be fixed to the logical block size. Otherwise the block + * layer will drop misaligned portions of the request which can + * lead to data corruption. If LBPRZ is not set, we honor the + * device preference. + */ + if (sdkp->lbprz) { + q->limits.discard_alignment = 0; + q->limits.discard_granularity = 1; + } else { + q->limits.discard_alignment = sdkp->unmap_alignment * + logical_block_size; + q->limits.discard_granularity = + max(sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + } sdkp->provisioning_mode = mode; -- cgit v0.10.2 From f4ab421b719763277e5721f3a2eabb12e31c3b9e Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 13 Nov 2015 16:46:49 -0500 Subject: MAINTAINERS: Add myself as co-maintainer of the SCSI subsystem. Signed-off-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen diff --git a/MAINTAINERS b/MAINTAINERS index d382b61..52aba45 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9177,8 +9177,10 @@ F: include/scsi/sg.h SCSI SUBSYSTEM M: "James E.J. Bottomley" -L: linux-scsi@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git +M: "Martin K. Petersen" +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git +L: linux-scsi@vger.kernel.org S: Maintained F: drivers/scsi/ F: include/scsi/ -- cgit v0.10.2 From f7f9f26b139e53d798ea76465223a5f237d90fd3 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Sun, 22 Nov 2015 12:11:28 -0500 Subject: scsi_debug: fix prevent_allow+verify regressions Ruediger Meier observed a regression with the PREVENT ALLOW MEDIUM REMOVAL command in lk 3.19: http://www.spinics.net/lists/util-linux-ng/msg11448.html Inspection indicated the same regression with VERIFY(10). The patch is against lk 3.19.3 and also works with lk 4.3.0 . With this patch both commands are accepted and do nothing. ChangeLog: - fix the lk 3.19 regression so that the PREVENT ALLOW MEDIUM REMOVAL command is supported once again - same fix for VERIFY(10) Signed-off-by: Douglas Gilbert Reviewed-by: Hannes Reinicke Reviewed-by: Ewan Milne Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index dfcc45b..d09d602 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -465,8 +465,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 0} }, {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ + {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, + 0, 0, 0, 0, 0, 0} }, {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ @@ -477,8 +478,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* 20 */ - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ + {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ -- cgit v0.10.2 From ca369d51b3e1649be4a72addd6d6a168cfb3f537 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 13 Nov 2015 16:46:48 -0500 Subject: block/sd: Fix device-imposed transfer length limits Commit 4f258a46346c ("sd: Fix maximum I/O size for BLOCK_PC requests") had the unfortunate side-effect of removing an implicit clamp to BLK_DEF_MAX_SECTORS for REQ_TYPE_FS requests in the block layer code. This caused problems for some SMR drives. Debugging this issue revealed a few problems with the existing infrastructure since the block layer didn't know how to deal with device-imposed limits, only limits set by the I/O controller. - Introduce a new queue limit, max_dev_sectors, which is used by the ULD to signal the maximum sectors for a REQ_TYPE_FS request. - Ensure that max_dev_sectors is correctly stacked and taken into account when overriding max_sectors through sysfs. - Rework sd_read_block_limits() so it saves the max_xfer and opt_xfer values for later processing. - In sd_revalidate() set the queue's max_dev_sectors based on the MAXIMUM TRANSFER LENGTH value in the Block Limits VPD. If this value is not reported, fall back to a cap based on the CDB TRANSFER LENGTH field size. - In sd_revalidate(), use OPTIMAL TRANSFER LENGTH from the Block Limits VPD--if reported and sane--to signal the preferred device transfer size for FS requests. Otherwise use BLK_DEF_MAX_SECTORS. - blk_limits_max_hw_sectors() is no longer used and can be removed. Signed-off-by: Martin K. Petersen Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=93581 Reviewed-by: Christoph Hellwig Tested-by: sweeneygj@gmx.com Tested-by: Arzeets Tested-by: David Eisner Tested-by: Mario Kicherer Signed-off-by: Martin K. Petersen diff --git a/block/blk-settings.c b/block/blk-settings.c index 7d8f129..dd49735 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -91,7 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim) lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; lim->virt_boundary_mask = 0; lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; - lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; + lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors = + BLK_SAFE_MAX_SECTORS; lim->chunk_sectors = 0; lim->max_write_same_sectors = 0; lim->max_discard_sectors = 0; @@ -127,6 +128,7 @@ void blk_set_stacking_limits(struct queue_limits *lim) lim->max_hw_sectors = UINT_MAX; lim->max_segment_size = UINT_MAX; lim->max_sectors = UINT_MAX; + lim->max_dev_sectors = UINT_MAX; lim->max_write_same_sectors = UINT_MAX; } EXPORT_SYMBOL(blk_set_stacking_limits); @@ -214,8 +216,8 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 max_addr) EXPORT_SYMBOL(blk_queue_bounce_limit); /** - * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request - * @limits: the queue limits + * blk_queue_max_hw_sectors - set max sectors for a request for this queue + * @q: the request queue for the device * @max_hw_sectors: max hardware sectors in the usual 512b unit * * Description: @@ -224,13 +226,19 @@ EXPORT_SYMBOL(blk_queue_bounce_limit); * the device driver based upon the capabilities of the I/O * controller. * + * max_dev_sectors is a hard limit imposed by the storage device for + * READ/WRITE requests. It is set by the disk driver. + * * max_sectors is a soft limit imposed by the block layer for * filesystem type requests. This value can be overridden on a * per-device basis in /sys/block//queue/max_sectors_kb. * The soft limit can not exceed max_hw_sectors. **/ -void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors) +void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) { + struct queue_limits *limits = &q->limits; + unsigned int max_sectors; + if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) { max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9); printk(KERN_INFO "%s: set to minimum %d\n", @@ -238,22 +246,9 @@ void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_ } limits->max_hw_sectors = max_hw_sectors; - limits->max_sectors = min_t(unsigned int, max_hw_sectors, - BLK_DEF_MAX_SECTORS); -} -EXPORT_SYMBOL(blk_limits_max_hw_sectors); - -/** - * blk_queue_max_hw_sectors - set max sectors for a request for this queue - * @q: the request queue for the device - * @max_hw_sectors: max hardware sectors in the usual 512b unit - * - * Description: - * See description for blk_limits_max_hw_sectors(). - **/ -void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) -{ - blk_limits_max_hw_sectors(&q->limits, max_hw_sectors); + max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors); + max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS); + limits->max_sectors = max_sectors; } EXPORT_SYMBOL(blk_queue_max_hw_sectors); @@ -527,6 +522,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); + t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors); t->max_write_same_sectors = min(t->max_write_same_sectors, b->max_write_same_sectors); t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3e44a9d..55c637b 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -205,6 +205,9 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) if (ret < 0) return ret; + max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb, (unsigned long) + q->limits.max_dev_sectors >> 1); + if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) return -EINVAL; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e868d39..7af47ed 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2238,11 +2238,8 @@ got_data: } } - if (sdkp->capacity > 0xffffffff) { + if (sdkp->capacity > 0xffffffff) sdp->use_16_for_rw = 1; - sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS; - } else - sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS; /* Rescale capacity to 512-byte units */ if (sector_size == 4096) @@ -2559,7 +2556,6 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) { unsigned int sector_sz = sdkp->device->sector_size; const int vpd_len = 64; - u32 max_xfer_length; unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); if (!buffer || @@ -2567,14 +2563,11 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) goto out; - max_xfer_length = get_unaligned_be32(&buffer[8]); - if (max_xfer_length) - sdkp->max_xfer_blocks = max_xfer_length; - blk_queue_io_min(sdkp->disk->queue, get_unaligned_be16(&buffer[6]) * sector_sz); - blk_queue_io_opt(sdkp->disk->queue, - get_unaligned_be32(&buffer[12]) * sector_sz); + + sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]); + sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]); if (buffer[3] == 0x3c) { unsigned int lba_count, desc_count; @@ -2723,6 +2716,11 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp) return 0; } +static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks) +{ + return blocks << (ilog2(sdev->sector_size) - 9); +} + /** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. @@ -2732,8 +2730,9 @@ static int sd_revalidate_disk(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; + struct request_queue *q = sdkp->disk->queue; unsigned char *buffer; - unsigned int max_xfer; + unsigned int dev_max, rw_max; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2781,11 +2780,26 @@ static int sd_revalidate_disk(struct gendisk *disk) */ sd_set_flush_flag(sdkp); - max_xfer = sdkp->max_xfer_blocks; - max_xfer <<= ilog2(sdp->sector_size) - 9; + /* Initial block count limit based on CDB TRANSFER LENGTH field size. */ + dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS; + + /* Some devices report a maximum block count for READ/WRITE requests. */ + dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks); + q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max); + + /* + * Use the device's preferred I/O size for reads and writes + * unless the reported value is unreasonably large (or garbage). + */ + if (sdkp->opt_xfer_blocks && sdkp->opt_xfer_blocks <= dev_max && + sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS) + rw_max = q->limits.io_opt = + logical_to_sectors(sdp, sdkp->opt_xfer_blocks); + else + rw_max = BLK_DEF_MAX_SECTORS; - sdkp->disk->queue->limits.max_sectors = - min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer); + /* Combine with controller limits */ + q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q)); set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 63ba5ca..5f2a84a 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -67,6 +67,7 @@ struct scsi_disk { atomic_t openers; sector_t capacity; /* size in 512-byte sectors */ u32 max_xfer_blocks; + u32 opt_xfer_blocks; u32 max_ws_blocks; u32 max_unmap_blocks; u32 unmap_granularity; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 38a5ff7..9dacb74 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -253,6 +253,7 @@ struct queue_limits { unsigned long virt_boundary_mask; unsigned int max_hw_sectors; + unsigned int max_dev_sectors; unsigned int chunk_sectors; unsigned int max_sectors; unsigned int max_segment_size; @@ -948,7 +949,6 @@ extern struct request_queue *blk_init_allocated_queue(struct request_queue *, extern void blk_cleanup_queue(struct request_queue *); extern void blk_queue_make_request(struct request_queue *, make_request_fn *); extern void blk_queue_bounce_limit(struct request_queue *, u64); -extern void blk_limits_max_hw_sectors(struct queue_limits *, unsigned int); extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_segments(struct request_queue *, unsigned short); -- cgit v0.10.2 From 77032ca66f86fa631b38b2e7feeb2b953e59f2f0 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 24 Nov 2015 17:30:34 -0600 Subject: Return EBUSY from BLKRRPART for mounted whole-dev fs Today, blockdev --rereadpt /dev/sda will fail with EBUSY if any partition of sda is mounted (and will fail with EINVAL if pointed at a partition). But it will pass if the entire block device is formatted with a filesystem and mounted. I don't think this makes sense; partitioning should surely not ever change out from under a mounted device. So check for bdev->bd_super, and fail that with -EBUSY as well. Signed-off-by: Eric Sandeen Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/block/partition-generic.c b/block/partition-generic.c index 3b03015..746935a 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -397,7 +397,7 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev) struct hd_struct *part; int res; - if (bdev->bd_part_count) + if (bdev->bd_part_count || bdev->bd_super) return -EBUSY; res = invalidate_partition(disk, 0); if (res) -- cgit v0.10.2 From 92792e48e2ae6051af30468a87994b5432da2f06 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 18:26:07 +0100 Subject: remoteproc: avoid stack overflow in debugfs file Recent gcc versions warn about reading from a negative offset of an on-stack array: drivers/remoteproc/remoteproc_debugfs.c: In function 'rproc_recovery_write': drivers/remoteproc/remoteproc_debugfs.c:167:9: warning: 'buf[4294967295u]' may be used uninitialized in this function [-Wmaybe-uninitialized] I don't see anything in sys_write() that prevents us from being called with a zero 'count' argument, so we should add an extra check in rproc_recovery_write() to prevent the access and avoid the warning. Signed-off-by: Arnd Bergmann Fixes: 2e37abb89a2e ("remoteproc: create a 'recovery' debugfs entry") Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 9d30809..916af50 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf, char buf[10]; int ret; - if (count > sizeof(buf)) + if (count < 1 || count > sizeof(buf)) return count; ret = copy_from_user(buf, user_buf, count); -- cgit v0.10.2 From 8e3d7c834ba0f79f200c155cf0647eacd39f2fbe Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Thu, 26 Nov 2015 22:25:58 +0800 Subject: nios2: fix cache coherency There is intermittent cache coherency issue caught in toolchian tests. Revert to use flushd. Signed-off-by: Ley Foon Tan diff --git a/arch/nios2/mm/cacheflush.c b/arch/nios2/mm/cacheflush.c index 223cdcc..87bf88e 100644 --- a/arch/nios2/mm/cacheflush.c +++ b/arch/nios2/mm/cacheflush.c @@ -23,22 +23,6 @@ static void __flush_dcache(unsigned long start, unsigned long end) end += (cpuinfo.dcache_line_size - 1); end &= ~(cpuinfo.dcache_line_size - 1); - for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) { - __asm__ __volatile__ (" flushda 0(%0)\n" - : /* Outputs */ - : /* Inputs */ "r"(addr) - /* : No clobber */); - } -} - -static void __flush_dcache_all(unsigned long start, unsigned long end) -{ - unsigned long addr; - - start &= ~(cpuinfo.dcache_line_size - 1); - end += (cpuinfo.dcache_line_size - 1); - end &= ~(cpuinfo.dcache_line_size - 1); - if (end > start + cpuinfo.dcache_size) end = start + cpuinfo.dcache_size; @@ -112,7 +96,7 @@ static void flush_aliases(struct address_space *mapping, struct page *page) void flush_cache_all(void) { - __flush_dcache_all(0, cpuinfo.dcache_size); + __flush_dcache(0, cpuinfo.dcache_size); __flush_icache(0, cpuinfo.icache_size); } @@ -182,7 +166,7 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page) */ unsigned long start = (unsigned long)page_address(page); - __flush_dcache_all(start, start + PAGE_SIZE); + __flush_dcache(start, start + PAGE_SIZE); } void flush_dcache_page(struct page *page) @@ -268,7 +252,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, { flush_cache_page(vma, user_vaddr, page_to_pfn(page)); memcpy(dst, src, len); - __flush_dcache_all((unsigned long)src, (unsigned long)src + len); + __flush_dcache((unsigned long)src, (unsigned long)src + len); if (vma->vm_flags & VM_EXEC) __flush_icache((unsigned long)src, (unsigned long)src + len); } @@ -279,7 +263,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, { flush_cache_page(vma, user_vaddr, page_to_pfn(page)); memcpy(dst, src, len); - __flush_dcache_all((unsigned long)dst, (unsigned long)dst + len); + __flush_dcache((unsigned long)dst, (unsigned long)dst + len); if (vma->vm_flags & VM_EXEC) __flush_icache((unsigned long)dst, (unsigned long)dst + len); } -- cgit v0.10.2 From 025af189fb44250206dd8a32fa4a682392af3301 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 20 Nov 2015 11:43:50 -0800 Subject: drm/ttm: Fixed a read/write lock imbalance In ttm_write_lock(), the uninterruptible path should call __ttm_write_lock() not __ttm_read_lock(). This fixes a vmwgfx hang on F23 start up. syeh: Extracted this from one of Thomas' internal patches. Cc: Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c index 6a95454..f154fb1 100644 --- a/drivers/gpu/drm/ttm/ttm_lock.c +++ b/drivers/gpu/drm/ttm/ttm_lock.c @@ -180,7 +180,7 @@ int ttm_write_lock(struct ttm_lock *lock, bool interruptible) spin_unlock(&lock->lock); } } else - wait_event(lock->queue, __ttm_read_lock(lock)); + wait_event(lock->queue, __ttm_write_lock(lock)); return ret; } -- cgit v0.10.2 From f1b9032f61c0412082a240cb7245f8b79e09ae8d Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Tue, 17 Nov 2015 18:47:08 +0300 Subject: arm64: KASAN depends on !(ARM64_16K_PAGES && ARM64_VA_BITS_48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On KASAN + 16K_PAGES + 48BIT_VA arch/arm64/mm/kasan_init.c: In function ‘kasan_early_init’: include/linux/compiler.h:484:38: error: call to ‘__compiletime_assert_95’ declared with attribute error: BUILD_BUG_ON failed: !IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE) _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) Currently KASAN will not work on 16K_PAGES and 48BIT_VA, so forbid such configuration to avoid above build failure. Signed-off-by: Andrey Ryabinin Reported-by: Suzuki K. Poulose Acked-by: Mark Rutland Signed-off-by: Catalin Marinas diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9ac16a4..bf7de69 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -49,7 +49,7 @@ config ARM64 select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_BITREVERSE select HAVE_ARCH_JUMP_LABEL - select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP + select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48) select HAVE_ARCH_KGDB select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK -- cgit v0.10.2 From 0ebea8088095f1c18c1d1de284ccc4c479ca21c1 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 26 Nov 2015 13:49:39 +0000 Subject: arm64: mm: keep reserved ASIDs in sync with mm after multiple rollovers Under some unusual context-switching patterns, it is possible to end up with multiple threads from the same mm running concurrently with different ASIDs: 1. CPU x schedules task t with mm p containing ASID a and generation g This task doesn't block and the CPU doesn't context switch. So: * per_cpu(active_asid, x) = {g,a} * p->context.id = {g,a} 2. Some other CPU generates an ASID rollover. The global generation is now (g + 1). CPU x is still running t, with no context switch and so per_cpu(reserved_asid, x) = {g,a} 3. CPU y schedules task t', which shares mm p with t. The generation mismatches, so we take the slowpath and hit the reserved ASID from CPU x. p is then updated so that p->context.id = {g + 1,a} 4. CPU y schedules some other task u, which has an mm != p. 5. Some other CPU generates *another* CPU rollover. The global generation is now (g + 2). CPU x is still running t, with no context switch and so per_cpu(reserved_asid, x) = {g,a}. 6. CPU y once again schedules task t', but now *fails* to hit the reserved ASID from CPU x because of the generation mismatch. This results in a new ASID being allocated, despite the fact that t is still running on CPU x with the same mm. Consequently, TLBIs (e.g. as a result of CoW) will not be synchronised between the two threads. This patch fixes the problem by updating all of the matching reserved ASIDs when we hit on the slowpath (i.e. in step 3 above). This keeps the reserved ASIDs in-sync with the mm and avoids the problem. Reported-by: Tony Thompson Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index f636a26..e87f53f 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -76,13 +76,28 @@ static void flush_context(unsigned int cpu) __flush_icache_all(); } -static int is_reserved_asid(u64 asid) +static bool check_update_reserved_asid(u64 asid, u64 newasid) { int cpu; - for_each_possible_cpu(cpu) - if (per_cpu(reserved_asids, cpu) == asid) - return 1; - return 0; + bool hit = false; + + /* + * Iterate over the set of reserved ASIDs looking for a match. + * If we find one, then we can update our mm to use newasid + * (i.e. the same ASID in the current generation) but we can't + * exit the loop early, since we need to ensure that all copies + * of the old ASID are updated to reflect the mm. Failure to do + * so could result in us missing the reserved ASID in a future + * generation. + */ + for_each_possible_cpu(cpu) { + if (per_cpu(reserved_asids, cpu) == asid) { + hit = true; + per_cpu(reserved_asids, cpu) = newasid; + } + } + + return hit; } static u64 new_context(struct mm_struct *mm, unsigned int cpu) @@ -92,12 +107,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) u64 generation = atomic64_read(&asid_generation); if (asid != 0) { + u64 newasid = generation | (asid & ~ASID_MASK); + /* * If our current ASID was active during a rollover, we * can continue to use it and this was just a false alarm. */ - if (is_reserved_asid(asid)) - return generation | (asid & ~ASID_MASK); + if (check_update_reserved_asid(asid, newasid)) + return newasid; /* * We had a valid ASID in a previous life, so try to re-use @@ -105,7 +122,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) */ asid &= ~ASID_MASK; if (!__test_and_set_bit(asid, asid_map)) - goto bump_gen; + return newasid; } /* @@ -129,10 +146,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) set_asid: __set_bit(asid, asid_map); cur_idx = asid; - -bump_gen: - asid |= generation; - return asid; + return asid | generation; } void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) -- cgit v0.10.2 From 667c27597ca823f20c524bbd486c6709f905673b Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 26 Nov 2015 15:42:41 +0000 Subject: Revert "arm64: Mark kernel page ranges contiguous" This reverts commit 348a65cdcbbf243073ee39d1f7d4413081ad7eab. Incorrect page table manipulation that does not respect the ARM ARM recommended break-before-make sequence may lead to TLB conflicts. The contiguous PTE patch makes the system even more susceptible to such errors by changing the mapping from a single page to a contiguous range of pages. An additional TLB invalidation would reduce the risk window, however, the correct fix is to switch to a temporary swapper_pg_dir. Once the correct workaround is done, the reverted commit will be re-applied. Signed-off-by: Catalin Marinas Reported-by: Jeremy Linton diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 78d91b1..873e363 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -85,55 +85,19 @@ static void split_pmd(pmd_t *pmd, pte_t *pte) do { /* * Need to have the least restrictive permissions available - * permissions will be fixed up later. Default the new page - * range as contiguous ptes. + * permissions will be fixed up later */ - set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC_CONT)); + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); pfn++; } while (pte++, i++, i < PTRS_PER_PTE); } -/* - * Given a PTE with the CONT bit set, determine where the CONT range - * starts, and clear the entire range of PTE CONT bits. - */ -static void clear_cont_pte_range(pte_t *pte, unsigned long addr) -{ - int i; - - pte -= CONT_RANGE_OFFSET(addr); - for (i = 0; i < CONT_PTES; i++) { - set_pte(pte, pte_mknoncont(*pte)); - pte++; - } - flush_tlb_all(); -} - -/* - * Given a range of PTEs set the pfn and provided page protection flags - */ -static void __populate_init_pte(pte_t *pte, unsigned long addr, - unsigned long end, phys_addr_t phys, - pgprot_t prot) -{ - unsigned long pfn = __phys_to_pfn(phys); - - do { - /* clear all the bits except the pfn, then apply the prot */ - set_pte(pte, pfn_pte(pfn, prot)); - pte++; - pfn++; - addr += PAGE_SIZE; - } while (addr != end); -} - static void alloc_init_pte(pmd_t *pmd, unsigned long addr, - unsigned long end, phys_addr_t phys, + unsigned long end, unsigned long pfn, pgprot_t prot, void *(*alloc)(unsigned long size)) { pte_t *pte; - unsigned long next; if (pmd_none(*pmd) || pmd_sect(*pmd)) { pte = alloc(PTRS_PER_PTE * sizeof(pte_t)); @@ -146,27 +110,9 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr, pte = pte_offset_kernel(pmd, addr); do { - next = min(end, (addr + CONT_SIZE) & CONT_MASK); - if (((addr | next | phys) & ~CONT_MASK) == 0) { - /* a block of CONT_PTES */ - __populate_init_pte(pte, addr, next, phys, - __pgprot(pgprot_val(prot) | PTE_CONT)); - } else { - /* - * If the range being split is already inside of a - * contiguous range but this PTE isn't going to be - * contiguous, then we want to unmark the adjacent - * ranges, then update the portion of the range we - * are interrested in. - */ - clear_cont_pte_range(pte, addr); - __populate_init_pte(pte, addr, next, phys, prot); - } - - pte += (next - addr) >> PAGE_SHIFT; - phys += next - addr; - addr = next; - } while (addr != end); + set_pte(pte, pfn_pte(pfn, prot)); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); } static void split_pud(pud_t *old_pud, pmd_t *pmd) @@ -227,7 +173,8 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud, } } } else { - alloc_init_pte(pmd, addr, next, phys, prot, alloc); + alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), + prot, alloc); } phys += next - addr; } while (pmd++, addr = next, addr != end); -- cgit v0.10.2 From f42f79af16ce2e8fff49ea9ba4949d3abdd6f26f Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 16 Sep 2015 19:29:18 -0500 Subject: remoteproc: fix memory leak of remoteproc ida cache layers The remoteproc core uses a static ida named rproc_dev_index for assigning an automatic index number to a registered remoteproc. The ida core may allocate some internal idr cache layers and ida bitmap upon any ida allocation, and all these layers are truely freed only upon the ida destruction. The rproc_dev_index ida is not destroyed at present, leading to a memory leak when using the remoteproc core as a module and atleast one rproc device is registered and unregistered. Fix this by invoking ida_destroy() in the remoteproc core module exit. Signed-off-by: Suman Anna Signed-off-by: Ohad Ben-Cohen diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 8b3130f..9e03d15 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1478,6 +1478,8 @@ module_init(remoteproc_init); static void __exit remoteproc_exit(void) { + ida_destroy(&rproc_dev_index); + rproc_exit_debugfs(); } module_exit(remoteproc_exit); -- cgit v0.10.2 From 99f9be4c73cff20ec64793be68f03f927474298c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 21 Nov 2015 13:29:39 +0300 Subject: drm/vmwgfx: fix a warning message The WARN_ON() macro only takes a condition argument, it doesn't take a message. I have converted this to WARN() instead. Signed-off-by: Dan Carpenter Reviewed-by: Sinclair Yeh diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index a8baf5f..b6a0806 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -390,7 +390,7 @@ void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes, else if (ctx_id == SVGA3D_INVALID_ID) ret = vmw_local_fifo_reserve(dev_priv, bytes); else { - WARN_ON("Command buffer has not been allocated.\n"); + WARN(1, "Command buffer has not been allocated.\n"); ret = NULL; } if (IS_ERR_OR_NULL(ret)) { -- cgit v0.10.2 From 3abb1ada21a4fb5b2920457a2e5c8483abb09a45 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Thu, 26 Nov 2015 15:37:13 +0100 Subject: rtc: ds1307: fix alarm reading at probe time With the actual code, read_alarm() always returns -EINVAL when called during the RTC device registration. This prevents from retrieving an already configured alarm in hardware. This patch fixes the issue by moving the HAS_ALARM bit configuration (if supported by the hardware) above the rtc_device_register() call. Signed-off-by: Simon Guinot Signed-off-by: Alexandre Belloni diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 3258368..aa705bb 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1134,7 +1134,10 @@ read_rtc: bin2bcd(tmp)); } - device_set_wakeup_capable(&client->dev, want_irq); + if (want_irq) { + device_set_wakeup_capable(&client->dev, true); + set_bit(HAS_ALARM, &ds1307->flags); + } ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, rtc_ops, THIS_MODULE); if (IS_ERR(ds1307->rtc)) { @@ -1148,12 +1151,11 @@ read_rtc: ds1307->rtc->name, client); if (err) { client->irq = 0; + device_set_wakeup_capable(&client->dev, false); + clear_bit(HAS_ALARM, &ds1307->flags); dev_err(&client->dev, "unable to request IRQ!\n"); - } else { - - set_bit(HAS_ALARM, &ds1307->flags); + } else dev_dbg(&client->dev, "got IRQ %d\n", client->irq); - } } if (chip->nvram_size) { -- cgit v0.10.2 From 9c17d96500f78d7ecdb71ca6942830158bc75a2b Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Tue, 10 Nov 2015 15:10:33 -0500 Subject: xen/gntdev: Grant maps should not be subject to NUMA balancing Doing so will cause the grant to be unmapped and then, during fault handling, the fault to be mistakenly treated as NUMA hint fault. In addition, even if those maps could partcipate in NUMA balancing, it wouldn't provide any benefit since we are unable to determine physical page's node (even if/when VNUMA is implemented). Marking grant maps' VMAs as VM_IO will exclude them from being part of NUMA balancing. Signed-off-by: Boris Ostrovsky Cc: stable@vger.kernel.org Signed-off-by: David Vrabel diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 2ea0b3b..1be5dd0 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -804,7 +804,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_ops = &gntdev_vmops; - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO; if (use_ptemod) vma->vm_flags |= VM_DONTCOPY; -- cgit v0.10.2 From d21182718400f51f0729ae8268d94bd820ec8b71 Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 18 Nov 2015 17:08:56 +0000 Subject: arm64: cpufeature: Add helpers for extracting unsigned values The cpuid_feature_extract_field() extracts the feature value as a signed integer. This could be problematic for features whose values are unsigned. e.g, ID_AA64DFR0_EL1:BRPs. Add an unsigned variant for the unsigned fields. Cc: Ard Biesheuvel Reported-by: AKASHI Takahiro Signed-off-by: Suzuki K. Poulose Signed-off-by: Catalin Marinas diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 11d5bb0f..7a16102 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -123,6 +123,18 @@ cpuid_feature_extract_field(u64 features, int field) return cpuid_feature_extract_field_width(features, field, 4); } +static inline unsigned int __attribute_const__ +cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width) +{ + return (u64)(features << (64 - width - field)) >> (64 - width); +} + +static inline unsigned int __attribute_const__ +cpuid_feature_extract_unsigned_field(u64 features, int field) +{ + return cpuid_feature_extract_unsigned_field_width(features, field, 4); +} + static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp) { return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift); -- cgit v0.10.2 From b4ff8389ed14b849354b59ce9b360bdefcdbf99c Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Fri, 20 Nov 2015 11:25:04 -0500 Subject: xen/events: Always allocate legacy interrupts on PV guests After commit 8c058b0b9c34 ("x86/irq: Probe for PIC presence before allocating descs for legacy IRQs") early_irq_init() will no longer preallocate descriptors for legacy interrupts if PIC does not exist, which is the case for Xen PV guests. Therefore we may need to allocate those descriptors ourselves. Signed-off-by: Boris Ostrovsky Suggested-by: Thomas Gleixner Signed-off-by: David Vrabel diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index be1d07d..1bd9510de 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -40,6 +40,11 @@ extern void arch_trigger_all_cpu_backtrace(bool); #define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x) #endif +static inline int nr_legacy_irqs(void) +{ + return NR_IRQS_LEGACY; +} + #endif #endif diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index bbb251b..8b9bf54 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -21,4 +21,9 @@ static inline void acpi_irq_init(void) } #define acpi_irq_init acpi_irq_init +static inline int nr_legacy_irqs(void) +{ + return 0; +} + #endif diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 849500e..524c221 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #endif #include @@ -420,7 +421,7 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi) return xen_allocate_irq_dynamic(); /* Legacy IRQ descriptors are already allocated by the arch. */ - if (gsi < NR_IRQS_LEGACY) + if (gsi < nr_legacy_irqs()) irq = gsi; else irq = irq_alloc_desc_at(gsi, -1); @@ -446,7 +447,7 @@ static void xen_free_irq(unsigned irq) kfree(info); /* Legacy IRQ descriptors are managed by the arch. */ - if (irq < NR_IRQS_LEGACY) + if (irq < nr_legacy_irqs()) return; irq_free_desc(irq); -- cgit v0.10.2 From 4f0a606bce5ecd3a8210e896c33f41d1bf7f752f Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 18 Nov 2015 17:08:57 +0000 Subject: arm64: cpufeature: Track unsigned fields Some of the feature bits have unsigned values and need to be treated accordingly to avoid errors. Adds the property to the feature bits and use the appropriate field extract helpers. Reported-by: AKASHI Takahiro Cc: Ard Biesheuvel Signed-off-by: Suzuki K. Poulose Signed-off-by: Catalin Marinas diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 7a16102..29c3f5d 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -46,8 +46,12 @@ enum ftr_type { #define FTR_STRICT true /* SANITY check strict matching required */ #define FTR_NONSTRICT false /* SANITY check ignored */ +#define FTR_SIGNED true /* Value should be treated as signed */ +#define FTR_UNSIGNED false /* Value should be treated as unsigned */ + struct arm64_ftr_bits { - bool strict; /* CPU Sanity check: strict matching required ? */ + bool sign; /* Value is signed ? */ + bool strict; /* CPU Sanity check: strict matching required ? */ enum ftr_type type; u8 shift; u8 width; @@ -142,7 +146,9 @@ static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp) static inline s64 arm64_ftr_value(struct arm64_ftr_bits *ftrp, u64 val) { - return cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width); + return ftrp->sign ? + cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width) : + cpuid_feature_extract_unsigned_field_width(val, ftrp->shift, ftrp->width); } static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index c8cf892..0669c63 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -44,8 +44,9 @@ unsigned int compat_elf_hwcap2 __read_mostly; DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); -#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ +#define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ { \ + .sign = SIGNED, \ .strict = STRICT, \ .type = TYPE, \ .shift = SHIFT, \ @@ -53,6 +54,14 @@ DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); .safe_val = SAFE_VAL, \ } +/* Define a feature with signed values */ +#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ + __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) + +/* Define a feature with unsigned value */ +#define U_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \ + __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) + #define ARM64_FTR_END \ { \ .width = 0, \ @@ -99,7 +108,7 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr0[] = { * Differing PARange is fine as long as all peripherals and memory are mapped * within the minimum PARange of all CPUs */ - ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0), ARM64_FTR_END, }; @@ -115,18 +124,18 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = { }; static struct arm64_ftr_bits ftr_ctr[] = { - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ + U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */ ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */ - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ + U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */ + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ /* * Linux can handle differing I-cache policies. Userspace JITs will * make use of *minLine */ - ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0), /* L1Ip */ + U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0), /* L1Ip */ ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0), /* RAZ */ - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */ + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */ ARM64_FTR_END, }; @@ -144,12 +153,12 @@ static struct arm64_ftr_bits ftr_id_mmfr0[] = { static struct arm64_ftr_bits ftr_id_aa64dfr0[] = { ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0), + U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6), ARM64_FTR_END, }; -- cgit v0.10.2 From 1944bf8e78b7178f8ebfeefaced738ce1d111a4c Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 18 Nov 2015 17:08:58 +0000 Subject: arm64: debug: Treat the BRPs/WRPs as unsigned IDAA64DFR0_EL1: BRPs and WRPs are unsigned values. Use the appropriate helpers to extract those fields. Cc: Ard Biesheuvel Reported-by: AKASHI Takahiro Acked-by: Will Deacon Signed-off-by: Suzuki K. Poulose Signed-off-by: Catalin Marinas diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index e54415e..9732908 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -138,16 +138,18 @@ extern struct pmu perf_ops_bp; /* Determine number of BRP registers available. */ static inline int get_num_brps(void) { + u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1); return 1 + - cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1), + cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_BRPS_SHIFT); } /* Determine number of WRP registers available. */ static inline int get_num_wrps(void) { + u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1); return 1 + - cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1), + cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_WRPS_SHIFT); } -- cgit v0.10.2 From 81d945772afccc77660374aa6e512184b9107580 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 23 Nov 2015 08:43:23 +0100 Subject: arm64: efi: deal with NULL return value of early_memremap() Add NULL return value checks to two invocations of early_memremap() in the UEFI init code. For the UEFI configuration tables, we just warn since we have a better chance of being able to report the issue in a way that can actually be noticed by a human operator if we don't abort right away. For the UEFI memory map, however, all we can do is panic() since we cannot proceed without a description of memory. Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Acked-by: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index fe7cd1a..96e4b1b 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -127,7 +127,11 @@ static int __init uefi_init(void) table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; config_tables = early_memremap(efi_to_phys(efi.systab->tables), table_size); - + if (config_tables == NULL) { + pr_warn("Unable to map EFI config table array.\n"); + retval = -ENOMEM; + goto out; + } retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sizeof(efi_config_table_64_t), NULL); @@ -209,6 +213,14 @@ void __init efi_init(void) PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); memmap.phys_map = params.mmap; memmap.map = early_memremap(params.mmap, params.mmap_size); + if (memmap.map == NULL) { + /* + * If we are booting via UEFI, the UEFI memory map is the only + * description of memory we have, so there is little point in + * proceeding if we cannot access it. + */ + panic("Unable to map EFI memory map.\n"); + } memmap.map_end = memmap.map + params.mmap_size; memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver; -- cgit v0.10.2 From 66362c9afc1d4a806280b9e3646d2d0a26cf83e9 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 23 Nov 2015 08:43:24 +0100 Subject: arm64: efi: fix initcall return values Even though initcall return values are typically ignored, the prototype is to return 0 on success or a negative errno value on error. So fix the arm_enable_runtime_services() implementation to return 0 on conditions that are not in fact errors, and return a meaningful error code otherwise. Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Acked-by: Will Deacon Signed-off-by: Catalin Marinas diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 96e4b1b..4eeb171 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -280,12 +280,12 @@ static int __init arm64_enable_runtime_services(void) if (!efi_enabled(EFI_BOOT)) { pr_info("EFI services will not be available.\n"); - return -1; + return 0; } if (efi_runtime_disabled()) { pr_info("EFI runtime services will be disabled.\n"); - return -1; + return 0; } pr_info("Remapping and enabling EFI services.\n"); @@ -295,7 +295,7 @@ static int __init arm64_enable_runtime_services(void) mapsize); if (!memmap.map) { pr_err("Failed to remap EFI memory map\n"); - return -1; + return -ENOMEM; } memmap.map_end = memmap.map + mapsize; efi.memmap = &memmap; @@ -304,13 +304,13 @@ static int __init arm64_enable_runtime_services(void) sizeof(efi_system_table_t)); if (!efi.systab) { pr_err("Failed to remap EFI System Table\n"); - return -1; + return -ENOMEM; } set_bit(EFI_SYSTEM_TABLES, &efi.flags); if (!efi_virtmap_init()) { pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); - return -1; + return -ENOMEM; } /* Set up runtime services function pointers */ -- cgit v0.10.2 From 8620015499101090ae275bf11e9bc2f9febfdf08 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 26 Nov 2015 16:14:35 +0000 Subject: xen/evtchn: dynamically grow pending event channel ring If more than 1024 event channels are bound to a evtchn device then it possible (even with well behaved applications) for the ring to overflow and events to be lost (reported as an -EFBIG error). Dynamically increase the size of the ring so there is always enough space for all bound events. Well behaved applicables that only unmask events after draining them from the ring can thus no longer lose events. However, an application could unmask an event before draining it, allowing multiple entries per port to accumulate in the ring, and a overflow could still occur. So the overflow detection and reporting is retained. The ring size is initially only 64 entries so the common use case of an application only binding a few events will use less memory than before. The ring size may grow to 512 KiB (enough for all 2^17 possible channels). This order 7 kmalloc() may fail due to memory fragmentation, so we fall back to trying vmalloc(). Signed-off-by: David Vrabel Reviewed-by: Andrew Cooper diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 00f40f0..38272ad 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include @@ -58,10 +60,10 @@ struct per_user_data { struct mutex bind_mutex; /* serialize bind/unbind operations */ struct rb_root evtchns; + unsigned int nr_evtchns; /* Notification ring, accessed via /dev/xen/evtchn. */ -#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) -#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) + unsigned int ring_size; evtchn_port_t *ring; unsigned int ring_cons, ring_prod, ring_overflow; struct mutex ring_cons_mutex; /* protect against concurrent readers */ @@ -80,10 +82,41 @@ struct user_evtchn { bool enabled; }; +static evtchn_port_t *evtchn_alloc_ring(unsigned int size) +{ + evtchn_port_t *ring; + size_t s = size * sizeof(*ring); + + ring = kmalloc(s, GFP_KERNEL); + if (!ring) + ring = vmalloc(s); + + return ring; +} + +static void evtchn_free_ring(evtchn_port_t *ring) +{ + kvfree(ring); +} + +static unsigned int evtchn_ring_offset(struct per_user_data *u, + unsigned int idx) +{ + return idx & (u->ring_size - 1); +} + +static evtchn_port_t *evtchn_ring_entry(struct per_user_data *u, + unsigned int idx) +{ + return u->ring + evtchn_ring_offset(u, idx); +} + static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) { struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL; + u->nr_evtchns++; + while (*new) { struct user_evtchn *this; @@ -107,6 +140,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) { + u->nr_evtchns--; rb_erase(&evtchn->node, &u->evtchns); kfree(evtchn); } @@ -144,8 +178,8 @@ static irqreturn_t evtchn_interrupt(int irq, void *data) spin_lock(&u->ring_prod_lock); - if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { - u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port; + if ((u->ring_prod - u->ring_cons) < u->ring_size) { + *evtchn_ring_entry(u, u->ring_prod) = evtchn->port; wmb(); /* Ensure ring contents visible */ if (u->ring_cons == u->ring_prod++) { wake_up_interruptible(&u->evtchn_wait); @@ -200,10 +234,10 @@ static ssize_t evtchn_read(struct file *file, char __user *buf, } /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ - if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { - bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * + if (((c ^ p) & u->ring_size) != 0) { + bytes1 = (u->ring_size - evtchn_ring_offset(u, c)) * sizeof(evtchn_port_t); - bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); + bytes2 = evtchn_ring_offset(u, p) * sizeof(evtchn_port_t); } else { bytes1 = (p - c) * sizeof(evtchn_port_t); bytes2 = 0; @@ -219,7 +253,7 @@ static ssize_t evtchn_read(struct file *file, char __user *buf, rc = -EFAULT; rmb(); /* Ensure that we see the port before we copy it. */ - if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || + if (copy_to_user(buf, evtchn_ring_entry(u, c), bytes1) || ((bytes2 != 0) && copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) goto unlock_out; @@ -278,6 +312,66 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf, return rc; } +static int evtchn_resize_ring(struct per_user_data *u) +{ + unsigned int new_size; + evtchn_port_t *new_ring, *old_ring; + unsigned int p, c; + + /* + * Ensure the ring is large enough to capture all possible + * events. i.e., one free slot for each bound event. + */ + if (u->nr_evtchns <= u->ring_size) + return 0; + + if (u->ring_size == 0) + new_size = 64; + else + new_size = 2 * u->ring_size; + + new_ring = evtchn_alloc_ring(new_size); + if (!new_ring) + return -ENOMEM; + + old_ring = u->ring; + + /* + * Access to the ring contents is serialized by either the + * prod /or/ cons lock so take both when resizing. + */ + mutex_lock(&u->ring_cons_mutex); + spin_lock_irq(&u->ring_prod_lock); + + /* + * Copy the old ring contents to the new ring. + * + * If the ring contents crosses the end of the current ring, + * it needs to be copied in two chunks. + * + * +---------+ +------------------+ + * |34567 12| -> | 1234567 | + * +-----p-c-+ +------------------+ + */ + p = evtchn_ring_offset(u, u->ring_prod); + c = evtchn_ring_offset(u, u->ring_cons); + if (p < c) { + memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring)); + memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring)); + } else + memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring)); + + u->ring = new_ring; + u->ring_size = new_size; + + spin_unlock_irq(&u->ring_prod_lock); + mutex_unlock(&u->ring_cons_mutex); + + evtchn_free_ring(old_ring); + + return 0; +} + static int evtchn_bind_to_user(struct per_user_data *u, int port) { struct user_evtchn *evtchn; @@ -305,6 +399,10 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) if (rc < 0) goto err; + rc = evtchn_resize_ring(u); + if (rc < 0) + goto err; + rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0, u->name, evtchn); if (rc < 0) @@ -503,13 +601,6 @@ static int evtchn_open(struct inode *inode, struct file *filp) init_waitqueue_head(&u->evtchn_wait); - u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL); - if (u->ring == NULL) { - kfree(u->name); - kfree(u); - return -ENOMEM; - } - mutex_init(&u->bind_mutex); mutex_init(&u->ring_cons_mutex); spin_lock_init(&u->ring_prod_lock); @@ -532,7 +623,7 @@ static int evtchn_release(struct inode *inode, struct file *filp) evtchn_unbind_from_user(u, evtchn); } - free_page((unsigned long)u->ring); + evtchn_free_ring(u->ring); kfree(u->name); kfree(u); -- cgit v0.10.2 From e2c9e0b28e146c9a3bce21408f3c02e24ac7ac31 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 26 Nov 2015 15:20:19 -0500 Subject: ext4: fix an endianness bug in ext4_encrypted_zeroout() ex->ee_block is not host-endian (note that accesses of other fields of *ex right next to that line go through the helpers that do proper conversion from little-endian to host-endian; it might make sense to add similar for ->ee_block to avoid reintroducing that kind of bugs...) Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Al Viro Signed-off-by: Theodore Ts'o diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index af06830..1a08350 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -389,7 +389,7 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex) struct ext4_crypto_ctx *ctx; struct page *ciphertext_page = NULL; struct bio *bio; - ext4_lblk_t lblk = ex->ee_block; + ext4_lblk_t lblk = le32_to_cpu(ex->ee_block); ext4_fsblk_t pblk = ext4_ext_pblock(ex); unsigned int len = ext4_ext_get_actual_len(ex); int ret, err = 0; -- cgit v0.10.2 From 5a1c7f47da9b32d0671e776b0f388095b7f91e2e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 26 Nov 2015 15:20:50 -0500 Subject: ext4: fix an endianness bug in ext4_encrypted_follow_link() applying le32_to_cpu() to 16bit value is a bad idea... Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Al Viro Signed-off-by: Theodore Ts'o diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index abe2401..e8e7af6 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -52,7 +52,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook /* Symlink is encrypted */ sd = (struct ext4_encrypted_symlink_data *)caddr; cstr.name = sd->encrypted_path; - cstr.len = le32_to_cpu(sd->len); + cstr.len = le16_to_cpu(sd->len); if ((cstr.len + sizeof(struct ext4_encrypted_symlink_data) - 1) > max_size) { -- cgit v0.10.2 From 681c46b164d79aaa5d18f7519b39e29f9b441e40 Mon Sep 17 00:00:00 2001 From: Xu Cang Date: Thu, 26 Nov 2015 15:52:24 -0500 Subject: ext4: add "static" to ext4_seq_##name##_fops struct to fix sparse warning, add static to ext4_seq_##name##_fops struct. Signed-off-by: Theodore Ts'o diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c index 1b57c72..1420a3c 100644 --- a/fs/ext4/sysfs.c +++ b/fs/ext4/sysfs.c @@ -358,7 +358,7 @@ static int name##_open(struct inode *inode, struct file *file) \ return single_open(file, ext4_seq_##name##_show, PDE_DATA(inode)); \ } \ \ -const struct file_operations ext4_seq_##name##_fops = { \ +static const struct file_operations ext4_seq_##name##_fops = { \ .owner = THIS_MODULE, \ .open = name##_open, \ .read = seq_read, \ -- cgit v0.10.2 From 62f49ee26f14753bd7fa634f51d537a79061bf0f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Nov 2015 22:26:43 +0100 Subject: cpufreq: s3c24xx: Do not mark s3c2410_plls_add as __init s3c2410_plls_add is a device notifier that may be called at runtime and is correctly not marked __init. However it calls s3c_plltab_register() which is marked __init, and that triggers a build error when we are checking for section mismatches: WARNING: vmlinux.o(.text+0x195e0): Section mismatch in reference from the function s3c2410_plls_add() to the function .init.text:s3c_plltab_register() The function s3c2410_plls_add() references the function __init s3c_plltab_register(). This is often because s3c2410_plls_add lacks a __init annotation or the annotation of s3c_plltab_register is wrong. This removes the __init annotation from s3c2410_plls_add as well as the __initdata section annotations from s3c2440_plls_12 and s3c2440_plls_169344, which in turn are referenced from s3c2410_plls_add. Signed-off-by: Arnd Bergmann Signed-off-by: Krzysztof Kozlowski diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c index a19460e..b355fca 100644 --- a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c +++ b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c @@ -20,7 +20,7 @@ #include #include -static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = { +static struct cpufreq_frequency_table s3c2440_plls_12[] = { { .frequency = 75000000, .driver_data = PLLVAL(0x75, 3, 3), }, /* FVco 600.000000 */ { .frequency = 80000000, .driver_data = PLLVAL(0x98, 4, 3), }, /* FVco 640.000000 */ { .frequency = 90000000, .driver_data = PLLVAL(0x70, 2, 3), }, /* FVco 720.000000 */ diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c index 1191b29..be9a248 100644 --- a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c +++ b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c @@ -20,7 +20,7 @@ #include #include -static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = { +static struct cpufreq_frequency_table s3c2440_plls_169344[] = { { .frequency = 78019200, .driver_data = PLLVAL(121, 5, 3), }, /* FVco 624.153600 */ { .frequency = 84067200, .driver_data = PLLVAL(131, 5, 3), }, /* FVco 672.537600 */ { .frequency = 90115200, .driver_data = PLLVAL(141, 5, 3), }, /* FVco 720.921600 */ diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 733aa51..68ef8fd 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -648,7 +648,7 @@ late_initcall(s3c_cpufreq_initcall); * * Register the given set of PLLs with the system. */ -int __init s3c_plltab_register(struct cpufreq_frequency_table *plls, +int s3c_plltab_register(struct cpufreq_frequency_table *plls, unsigned int plls_no) { struct cpufreq_frequency_table *vals; -- cgit v0.10.2 From 77e8058810303e5c18b462adb4f761dbb4f3b657 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Fri, 27 Nov 2015 12:31:09 +0000 Subject: spi: bugfix: spi_message.transfer_length does not get reset When submitting an identical spi_message multiple times via spi_sync the spi_message.frame_length does not get reset to 0 in __spi_validate before adding up all spi_transfer.len resulting in frame_length > actual_length on all but the first spi_sync call. Signed-off-by: Martin Sperl Signed-off-by: Mark Brown diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e2415be..a0e346f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2130,6 +2130,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) * Set transfer tx_nbits and rx_nbits as single transfer default * (SPI_NBITS_SINGLE) if it is not set for this transfer. */ + message->frame_length = 0; list_for_each_entry(xfer, &message->transfers, transfer_list) { message->frame_length += xfer->len; if (!xfer->bits_per_word) -- cgit v0.10.2 From 8ae743e82f0b86f3b860c27fc2c8f574cf959fd0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2015 14:23:00 +0100 Subject: ALSA: hda - Skip ELD notification during system suspend The recent addition of ELD notifier for Intel HDMI/DP codec may lead the bad codec connection found as kernel messages like below: Suspending console(s) (use no_console_suspend to debug) hdmi_present_sense: snd_hda_codec_hdmi hdaudioC0D2: HDMI status: Codec=2 Pin=6 Presence_Detect=1 ELD_Valid=1 snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08 snd_hda_intel 0000:00:1f.3: spurious response 0x0:0x2, last cmd=0x206f2e08 .... snd_hda_codec_hdmi hdaudioC0D2: HDMI: ELD buf size is 0, force 128 snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to polling mode: last cmd=0x206f2f00 snd_hda_intel 0000:00:1f.3: No response from codec, disabling MSI: last cmd=0x206f2f00 snd_hda_intel 0000:00:1f.3: azx_get_response timeout, switching to single_cmd mode: last cmd=0x206f2f00 azx_single_wait_for_response: 42 callbacks suppressed This seems appearing when the sound driver went to suspend before i915 driver. Then i915 driver disables HDMI/DP audio bit and calls the registered notifier, and the HDA codec tries to handle it as a hot(un)plug. But since the driver is already in the suspended state, it fails miserably. As this is a sort of spurious wakeup, it can be ignored safely, as long as it's delivered during the system suspend. OTOH, if a notification comes during the runtime suspend, the situation is different: we need to wake up. But during the system suspend, such a notification can't be the reason for a wakeup. This patch addresses it by a simple check of the current sound card status. The skipped notification doesn't matter because the HDA driver will check the plugged status forcibly at the resume in return. Then, why the card status, not a runtime PM status or else? The HDA controller driver is supposed to set the card status to D3 at the system suspend but not at the runtime suspend. So we can see it as a flag that is set only for the system suspend. Admittedly, it's a bit ugly, but it should work well for now. Reported-and-tested-by: "Zhang, Xiong Y" Fixes: 25adc137c546 ('ALSA: hda - Wake the codec up on pin/ELD notify events') Cc: # v4.3+ Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index bdb6f22..4b6fb66 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2352,6 +2352,12 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) struct hda_codec *codec = audio_ptr; int pin_nid = port + 0x04; + /* skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume + */ + if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + return; + check_presence_and_report(codec, pin_nid); } -- cgit v0.10.2 From c861519fcf95b2d46cb4275903423b43ae150a40 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 27 Nov 2015 19:17:01 +0100 Subject: MIPS: Fix delay loops which may be removed by GCC. GCC 4.1 and newer remove empty loops. This becomes a problem when delay loops get removed. Fixed by rewriting to user the proper Linux interface for such delays. Signed-off-by: Ralf Baechle Reported-by: Rasmus Villemoes Acked-by: John Crispin diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index 8a97802..dbbeccc 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -11,6 +11,7 @@ * by the Free Software Foundation. */ +#include #include #include #include @@ -232,8 +233,7 @@ static int rt288x_pci_probe(struct platform_device *pdev) ioport_resource.end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1; rt2880_pci_reg_write(0, RT2880_PCI_REG_PCICFG_ADDR); - for (i = 0; i < 0xfffff; i++) - ; + udelay(1); rt2880_pci_reg_write(0x79, RT2880_PCI_REG_ARBCTL); rt2880_pci_reg_write(0x07FF0001, RT2880_PCI_REG_BAR0SETUP_ADDR); diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c index 4f925e0..78b2ef4 100644 --- a/arch/mips/pmcs-msp71xx/msp_setup.c +++ b/arch/mips/pmcs-msp71xx/msp_setup.c @@ -10,6 +10,8 @@ * option) any later version. */ +#include + #include #include #include @@ -77,7 +79,7 @@ void msp7120_reset(void) */ /* Wait a bit for the DDRC to settle */ - for (i = 0; i < 100000000; i++); + mdelay(125); #if defined(CONFIG_PMC_MSP7120_GW) /* diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c index 244f942..db8f88b 100644 --- a/arch/mips/sni/reset.c +++ b/arch/mips/sni/reset.c @@ -3,6 +3,8 @@ * * Reset a SNI machine. */ +#include + #include #include #include @@ -32,9 +34,9 @@ void sni_machine_restart(char *command) for (;;) { for (i = 0; i < 100; i++) { kb_wait(); - for (j = 0; j < 100000 ; j++) - /* nothing */; + udelay(50); outb_p(0xfe, 0x64); /* pulse reset low */ + udelay(50); } } } -- cgit v0.10.2 From aa7d5f18e54529ae58a494447ee9b610d379b8d2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Nov 2015 13:20:54 +0100 Subject: ARM: 8454/1: OF implies OF_FLATTREE On the ARM architecture, individual platforms select CONFIG_USE_OF if they need it, but all device tree code is keyed off CONFIG_OF. When building a platform without DT support and manually enabling CONFIG_OF, we now get a number of build errors, e.g. arch/arm/kernel/devtree.c: In function 'setup_machine_fdt': arch/arm/kernel/devtree.c:215:19: error: implicit declaration of function 'early_init_dt_verify' [-Werror=implicit-function-declaration] We could now try to separate the use case of booting from DT vs. the case of using the dynamic implementation, but that seems more complicated than it can gain us. This simply changes the ARM Kconfig file to always enable OF_RESERVED_MEM and OF_EARLY_FLATTREE when CONFIG_OF is enabled. These options add a little extra code when we just want the dynamic OF implementation, but that seems like a rather obscure case, and this version solves all CONFIG_OF related randconfig regressions. Signed-off-by: Arnd Bergmann Fixes: 0166dc11be91 ("of: make CONFIG_OF user selectable") Acked-by: Rob Herring Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0365cbb..34e1569 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -76,6 +76,8 @@ config ARM select IRQ_FORCED_THREADING select MODULES_USE_ELF_REL select NO_BOOTMEM + select OF_EARLY_FLATTREE if OF + select OF_RESERVED_MEM if OF select OLD_SIGACTION select OLD_SIGSUSPEND3 select PERF_USE_VMALLOC @@ -1822,8 +1824,6 @@ config USE_OF bool "Flattened Device Tree support" select IRQ_DOMAIN select OF - select OF_EARLY_FLATTREE - select OF_RESERVED_MEM help Include support for flattened device tree machine descriptions. -- cgit v0.10.2 From 611e2267b68fc061aea86345b3a8b87151395187 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 13 Nov 2015 10:42:19 -0800 Subject: target/user: Fix time calc in expired cmd processing Reversed arguments meant that we were doing nothing for cmds whose deadline had passed. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 937cebf..41f9eb0 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -638,7 +638,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) return 0; - if (!time_after(cmd->deadline, jiffies)) + if (!time_after(jiffies, cmd->deadline)) return 0; set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags); -- cgit v0.10.2 From 6ba4bd297d99ad522a6414001e6837ddaa8753fd Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 13 Nov 2015 10:42:20 -0800 Subject: target/user: Do not set unused fields in tcmu_ops TCMU sets TRANSPORT_FLAG_PASSTHROUGH, so INQUIRY commands will not be emulated by LIO but passed up to userspace. Therefore TCMU should not set these, just like pscsi doesn't. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 41f9eb0..5e6d6cb 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1101,8 +1101,6 @@ tcmu_parse_cdb(struct se_cmd *cmd) static const struct target_backend_ops tcmu_ops = { .name = "user", - .inquiry_prod = "USER", - .inquiry_rev = TCMU_VERSION, .owner = THIS_MODULE, .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, .attach_hba = tcmu_attach_hba, -- cgit v0.10.2 From 82a819e8fb5f36c2a0e14b92bc820225c484a387 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 19 Oct 2015 21:18:24 +0100 Subject: iscsi-target: return -ENOMEM instead of -1 in case of failed kmalloc() Smatch complains about returning hard coded error codes, silence this warning. drivers/target/iscsi/iscsi_target_parameters.c:211 iscsi_create_default_params() warn: returning -1 instead of -ENOMEM is sloppy Signed-off-by: Luis de Bethencourt Reviewed-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 51d1734..2cbea2a 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -208,7 +208,7 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) if (!pl) { pr_err("Unable to allocate memory for" " struct iscsi_param_list.\n"); - return -1 ; + return -ENOMEM; } INIT_LIST_HEAD(&pl->param_list); INIT_LIST_HEAD(&pl->extra_response_list); @@ -578,7 +578,7 @@ int iscsi_copy_param_list( param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL); if (!param_list) { pr_err("Unable to allocate memory for struct iscsi_param_list.\n"); - return -1; + return -ENOMEM; } INIT_LIST_HEAD(¶m_list->param_list); INIT_LIST_HEAD(¶m_list->extra_response_list); @@ -629,7 +629,7 @@ int iscsi_copy_param_list( err_out: iscsi_release_param_list(param_list); - return -1; + return -ENOMEM; } static void iscsi_release_extra_responses(struct iscsi_param_list *param_list) @@ -729,7 +729,7 @@ static int iscsi_add_notunderstood_response( if (!extra_response) { pr_err("Unable to allocate memory for" " struct iscsi_extra_response.\n"); - return -1; + return -ENOMEM; } INIT_LIST_HEAD(&extra_response->er_list); @@ -1370,7 +1370,7 @@ int iscsi_decode_text_input( tmpbuf = kzalloc(length + 1, GFP_KERNEL); if (!tmpbuf) { pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length); - return -1; + return -ENOMEM; } memcpy(tmpbuf, textbuf, length); -- cgit v0.10.2 From ca82c2bded29b38d36140bfa1e76a7bbfcade390 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 5 Nov 2015 14:11:59 -0800 Subject: iscsi-target: Fix rx_login_comp hang after login failure This patch addresses a case where iscsi_target_do_tx_login_io() fails sending the last login response PDU, after the RX/TX threads have already been started. The case centers around iscsi_target_rx_thread() not invoking allow_signal(SIGINT) before the send_sig(SIGINT, ...) occurs from the failure path, resulting in RX thread hanging indefinately on iscsi_conn->rx_login_comp. Note this bug is a regression introduced by: commit e54198657b65625085834847ab6271087323ffea Author: Nicholas Bellinger Date: Wed Jul 22 23:14:19 2015 -0700 iscsi-target: Fix iscsit_start_kthreads failure OOPs To address this bug, complete ->rx_login_complete for good measure in the failure path, and immediately return from RX thread context if connection state did not actually reach full feature phase (TARG_CONN_STATE_LOGGED_IN). Cc: Sagi Grimberg Cc: # v3.10+ Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 342a07c..72204fb 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -4074,6 +4074,17 @@ reject: return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); } +static bool iscsi_target_check_conn_state(struct iscsi_conn *conn) +{ + bool ret; + + spin_lock_bh(&conn->state_lock); + ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN); + spin_unlock_bh(&conn->state_lock); + + return ret; +} + int iscsi_target_rx_thread(void *arg) { int ret, rc; @@ -4091,7 +4102,7 @@ int iscsi_target_rx_thread(void *arg) * incoming iscsi/tcp socket I/O, and/or failing the connection. */ rc = wait_for_completion_interruptible(&conn->rx_login_comp); - if (rc < 0) + if (rc < 0 || iscsi_target_check_conn_state(conn)) return 0; if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 5c964c0..9fc9117 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -388,6 +388,7 @@ err: if (login->login_complete) { if (conn->rx_thread && conn->rx_thread_active) { send_sig(SIGINT, conn->rx_thread, 1); + complete(&conn->rx_login_comp); kthread_stop(conn->rx_thread); } if (conn->tx_thread && conn->tx_thread_active) { -- cgit v0.10.2 From 057085e522f8bf94c2e691a5b76880f68060f8ba Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 5 Nov 2015 23:37:59 -0800 Subject: target: Fix race for SCF_COMPARE_AND_WRITE_POST checking This patch addresses a race + use after free where the first stage of COMPARE_AND_WRITE in compare_and_write_callback() is rescheduled after the backend sends the secondary WRITE, resulting in second stage compare_and_write_post() callback completing in target_complete_ok_work() before the first can return. Because current code depends on checking se_cmd->se_cmd_flags after return from se_cmd->transport_complete_callback(), this results in first stage having SCF_COMPARE_AND_WRITE_POST set, which incorrectly falls through into second stage CAW processing code, eventually triggering a NULL pointer dereference due to use after free. To address this bug, pass in a new *post_ret parameter into se_cmd->transport_complete_callback(), and depend upon this value instead of ->se_cmd_flags to determine when to return or fall through into ->queue_status() code for CAW. Cc: Sagi Grimberg Cc: # v3.12+ Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 0b4b2a6..ae24d0f 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -371,7 +371,8 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o return 0; } -static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success) +static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success, + int *post_ret) { unsigned char *buf, *addr; struct scatterlist *sg; @@ -437,7 +438,8 @@ sbc_execute_rw(struct se_cmd *cmd) cmd->data_direction); } -static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) +static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, + int *post_ret) { struct se_device *dev = cmd->se_dev; @@ -447,8 +449,10 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) * sent to the backend driver. */ spin_lock_irq(&cmd->t_state_lock); - if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) + if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) { cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; + *post_ret = 1; + } spin_unlock_irq(&cmd->t_state_lock); /* @@ -460,7 +464,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) return TCM_NO_SENSE; } -static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success) +static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success, + int *post_ret) { struct se_device *dev = cmd->se_dev; struct scatterlist *write_sg = NULL, *sg; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 5bacc7b..010b8c4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1658,7 +1658,7 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags) void transport_generic_request_failure(struct se_cmd *cmd, sense_reason_t sense_reason) { - int ret = 0; + int ret = 0, post_ret = 0; pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx" " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]); @@ -1680,7 +1680,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, */ if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd, false); + cmd->transport_complete_callback(cmd, false, &post_ret); switch (sense_reason) { case TCM_NON_EXISTENT_LUN: @@ -2068,11 +2068,13 @@ static void target_complete_ok_work(struct work_struct *work) */ if (cmd->transport_complete_callback) { sense_reason_t rc; + bool caw = (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE); + bool zero_dl = !(cmd->data_length); + int post_ret = 0; - rc = cmd->transport_complete_callback(cmd, true); - if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { - if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && - !cmd->data_length) + rc = cmd->transport_complete_callback(cmd, true, &post_ret); + if (!rc && !post_ret) { + if (caw && zero_dl) goto queue_rsp; return; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 0a2c740..aabf0ac 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -474,7 +474,7 @@ struct se_cmd { struct completion cmd_wait_comp; const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); - sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); + sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool, int *); void *protocol_data; unsigned char *t_task_cdb; -- cgit v0.10.2 From 9ff9d15eddd13ecdd41876c5e1f31ddbb127101c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 22 Oct 2015 15:57:04 -0700 Subject: target: Invoke release_cmd() callback without holding a spinlock This patch fixes the following kernel warning because it avoids that IRQs are disabled while ft_release_cmd() is invoked (fc_seq_set_resp() invokes spin_unlock_bh()): WARNING: CPU: 3 PID: 117 at kernel/softirq.c:150 __local_bh_enable_ip+0xaa/0x110() Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0x8a/0xc0 [] warn_slowpath_null+0x1a/0x20 [] __local_bh_enable_ip+0xaa/0x110 [] _raw_spin_unlock_bh+0x39/0x40 [] fc_seq_set_resp+0xe4/0x100 [libfc] [] ft_free_cmd+0x4a/0x90 [tcm_fc] [] ft_release_cmd+0x12/0x20 [tcm_fc] [] target_release_cmd_kref+0x56/0x90 [target_core_mod] [] target_put_sess_cmd+0xc0/0x110 [target_core_mod] [] transport_release_cmd+0x41/0x70 [target_core_mod] [] transport_generic_free_cmd+0x35/0x420 [target_core_mod] Signed-off-by: Bart Van Assche Acked-by: Joern Engel Reviewed-by: Andy Grover Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 5b28203..28fb301 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -130,6 +130,9 @@ void core_tmr_abort_task( if (tmr->ref_task_tag != ref_tag) continue; + if (!kref_get_unless_zero(&se_cmd->cmd_kref)) + continue; + printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); @@ -139,13 +142,15 @@ void core_tmr_abort_task( " skipping\n", ref_tag); spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + + target_put_sess_cmd(se_cmd); + goto out; } se_cmd->transport_state |= CMD_T_ABORTED; spin_unlock(&se_cmd->t_state_lock); list_del_init(&se_cmd->se_cmd_list); - kref_get(&se_cmd->cmd_kref); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); cancel_work_sync(&se_cmd->work); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 010b8c4..4fdcee2 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2509,23 +2509,24 @@ out: EXPORT_SYMBOL(target_get_sess_cmd); static void target_release_cmd_kref(struct kref *kref) - __releases(&se_cmd->se_sess->sess_cmd_lock) { struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); struct se_session *se_sess = se_cmd->se_sess; + unsigned long flags; + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (list_empty(&se_cmd->se_cmd_list)) { - spin_unlock(&se_sess->sess_cmd_lock); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); se_cmd->se_tfo->release_cmd(se_cmd); return; } if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { - spin_unlock(&se_sess->sess_cmd_lock); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); complete(&se_cmd->cmd_wait_comp); return; } list_del(&se_cmd->se_cmd_list); - spin_unlock(&se_sess->sess_cmd_lock); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); se_cmd->se_tfo->release_cmd(se_cmd); } @@ -2541,8 +2542,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd) se_cmd->se_tfo->release_cmd(se_cmd); return 1; } - return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, - &se_sess->sess_cmd_lock); + return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref); } EXPORT_SYMBOL(target_put_sess_cmd); -- cgit v0.10.2 From 3a66d7dca186ebdef9b0bf55e216778fa598062c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 22 Oct 2015 16:02:14 -0700 Subject: kref: Remove kref_put_spinlock_irqsave() The last user is gone. Hence remove this function. Signed-off-by: Bart Van Assche Cc: Greg Kroah-Hartman Cc: Christoph Hellwig Cc: Joern Engel Signed-off-by: Nicholas Bellinger diff --git a/include/linux/kref.h b/include/linux/kref.h index 484604d..e15828f 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -19,7 +19,6 @@ #include #include #include -#include struct kref { atomic_t refcount; @@ -99,38 +98,6 @@ static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref) return kref_sub(kref, 1, release); } -/** - * kref_put_spinlock_irqsave - decrement refcount for object. - * @kref: object. - * @release: pointer to the function that will clean up the object when the - * last reference to the object is released. - * This pointer is required, and it is not acceptable to pass kfree - * in as this function. - * @lock: lock to take in release case - * - * Behaves identical to kref_put with one exception. If the reference count - * drops to zero, the lock will be taken atomically wrt dropping the reference - * count. The release function has to call spin_unlock() without _irqrestore. - */ -static inline int kref_put_spinlock_irqsave(struct kref *kref, - void (*release)(struct kref *kref), - spinlock_t *lock) -{ - unsigned long flags; - - WARN_ON(release == NULL); - if (atomic_add_unless(&kref->refcount, -1, 1)) - return 0; - spin_lock_irqsave(lock, flags); - if (atomic_dec_and_test(&kref->refcount)) { - release(kref); - local_irq_restore(flags); - return 1; - } - spin_unlock_irqrestore(lock, flags); - return 0; -} - static inline int kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref), struct mutex *lock) -- cgit v0.10.2 From 3786dc454fa4c10b129acc0535705f1c5a64fc72 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 24 Nov 2015 12:20:15 -0500 Subject: qla2xxx: Fix regression introduced by target configFS changes this patch fixes following regression # targetcli [Errno 13] Permission denied: '/sys/kernel/config/target/qla2xxx/21:00:00:0e:1e:08:c7:20/tpgt_1/enable' Fixes: 2eafd72939fd ("target: use per-attribute show and store methods") Signed-off-by: Himanshu Madhani Signed-off-by: Giridhar Malavali Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 3ba2e95..81af294 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -902,7 +902,7 @@ static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item, return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type); } -CONFIGFS_ATTR_WO(tcm_qla2xxx_tpg_, enable); +CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable); CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions); CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type); -- cgit v0.10.2 From d94e5a61357a04938ce14d6033b4d33a3c5fd780 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 23 Nov 2015 17:46:32 +0100 Subject: target: fix COMPARE_AND_WRITE non zero SGL offset data corruption target_core_sbc's compare_and_write functionality suffers from taking data at the wrong memory location when writing a CAW request to disk when a SGL offset is non-zero. This can happen with loopback and vhost-scsi fabric drivers when SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is used to map existing user-space SGL memory into COMPARE_AND_WRITE READ/WRITE payload buffers. Given the following sample LIO subtopology, % targetcli ls /loopback/ o- loopback ................................. [1 Target] o- naa.6001405ebb8df14a ....... [naa.60014059143ed2b3] o- luns ................................... [2 LUNs] o- lun0 ................ [iblock/ram0 (/dev/ram0)] o- lun1 ................ [iblock/ram1 (/dev/ram1)] % lsscsi -g [3:0:1:0] disk LIO-ORG IBLOCK 4.0 /dev/sdc /dev/sg3 [3:0:1:1] disk LIO-ORG IBLOCK 4.0 /dev/sdd /dev/sg4 the following bug can be observed in Linux 4.3 and 4.4~rc1: % perl -e 'print chr$_ for 0..255,reverse 0..255' >rand % perl -e 'print "\0" x 512' >zero % cat rand >/dev/sdd % sg_compare_and_write -i rand -D zero --lba 0 /dev/sdd % sg_compare_and_write -i zero -D rand --lba 0 /dev/sdd Miscompare reported % hexdump -Cn 512 /dev/sdd 00000000 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 * 00000200 Rather than writing all-zeroes as instructed with the -D file, it corrupts the data in the sector by splicing some of the original bytes in. The page of the first entry of cmd->t_data_sg includes the CDB, and sg->offset is set to a position past the CDB. I presume that sg->offset is also the right choice to use for subsequent sglist members. Signed-off-by: Jan Engelhardt Tested-by: Douglas Gilbert Cc: # v3.12+ Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ae24d0f..98698d8 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -561,11 +561,11 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes if (block_size < PAGE_SIZE) { sg_set_page(&write_sg[i], m.page, block_size, - block_size); + m.piter.sg->offset + block_size); } else { sg_miter_next(&m); sg_set_page(&write_sg[i], m.page, block_size, - 0); + m.piter.sg->offset); } len -= block_size; i++; -- cgit v0.10.2 From 8f90353950b2da8d877c6ac3dde5e1109257a117 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 27 Nov 2015 18:37:47 +0100 Subject: target/stat: print full t10_wwn.model buffer Cut 'n paste error saw it only process sizeof(t10_wwn.vendor) characters. Signed-off-by: David Disseldorp Signed-off-by: Nicholas Bellinger diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 273c72b..81a6b3e 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -246,7 +246,7 @@ static ssize_t target_stat_lu_prod_show(struct config_item *item, char *page) char str[sizeof(dev->t10_wwn.model)+1]; /* scsiLuProductId */ - for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++) + for (i = 0; i < sizeof(dev->t10_wwn.model); i++) str[i] = ISPRINT(dev->t10_wwn.model[i]) ? dev->t10_wwn.model[i] : ' '; str[i] = '\0'; -- cgit v0.10.2 From d06165b329c04c8050c4b744c05ec61046709490 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 11 Nov 2015 14:36:53 +0200 Subject: gpiolib: fix oops, if gpio name is NULL Commit c0017ed71966 ("gpio: Introduce gpio descriptor 'name'") causes OOPS on boot on LPC32xx boards: Unable to handle kernel NULL pointer dereference at virtual address 00000000 CPU: 0 PID: 1 Comm: swapper Not tainted 4.3.0+ #707 Hardware name: LPC32XX SoC (Flattened Device Tree) task: c381baa0 ti: c381e000 task.ti: c381e000 PC is at strcmp+0x10/0x40 LR is at gpiochip_add+0x3d0/0x4d4 pc : [<>] lr : [<>] psr: a0000093 sp : c381fd60 ip : c381fd70 fp : c381fd6c [snip] Backtrace: [<>] (strcmp) from [<>] (gpiochip_add+0x3d0/0x4d4) [<>] (gpiochip_add) from [<>] (lpc32xx_gpio_probe+0x44/0x60) [<>] (lpc32xx_gpio_probe) from [<>] (platform_drv_probe+0x40/0x8c) [<>] (platform_drv_probe) from [<>] (driver_probe_device+0x110/0x294) [<>] (driver_probe_device) from [<>] (__driver_attach+0x70/0x94) [<>] (__driver_attach) from [<>] (bus_for_each_dev+0x74/0x98) [<>] (bus_for_each_dev) from [<>] (driver_attach+0x20/0x28) [<>] (driver_attach) from [<>] (bus_add_driver+0xd4/0x1f0) [<>] (bus_add_driver) from [<>] (driver_register+0xa4/0xe8) [<>] (driver_register) from [<>] (__platform_driver_register+0x38/0x4c) [<>] (__platform_driver_register) from [<>] (lpc32xx_gpio_driver_init+0x18/0x20) [<>] (lpc32xx_gpio_driver_init) from [<>] (do_one_initcall+0x108/0x1c8) [<>] (do_one_initcall) from [<>] (kernel_init_freeable+0x10c/0x1d4) [<>] (kernel_init_freeable) from [<>] (kernel_init+0x10/0xec) [<>] (kernel_init) from [<>] (ret_from_fork+0x14/0x24) This is caused by the fact that at the moment some GPIO names are set to NULL, there is a hole in linear representation of one GPI bank, see drivers/gpio/gpio-lpc32xx.c / gpi_p3_names[] for details. The same problem most probably affects also gpio-cs5535.c, see cs5535_gpio_names[]. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a18f00f..2a91f32 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -233,7 +233,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) for (i = 0; i != chip->ngpio; ++i) { struct gpio_desc *gpio = &chip->desc[i]; - if (!gpio->name) + if (!gpio->name || !name) continue; if (!strcmp(gpio->name, name)) { -- cgit v0.10.2 From c4699e70d1db14119708dae76dac7c43e1e12988 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Sat, 28 Nov 2015 16:49:22 +0100 Subject: lightnvm: Simplify config when disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't compile an object file to get empty implementations; conforms to linux coding style on conditional compilation. Signed-off-by: Keith Busch Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile index 219dc206..a5fe239 100644 --- a/drivers/nvme/host/Makefile +++ b/drivers/nvme/host/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_BLK_DEV_NVME) += nvme.o -nvme-y += pci.o scsi.o lightnvm.o +lightnvm-$(CONFIG_NVM) := lightnvm.o +nvme-y += pci.o scsi.o $(lightnvm-y) diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 9202d1a..07451d6 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -22,8 +22,6 @@ #include "nvme.h" -#ifdef CONFIG_NVM - #include #include #include @@ -588,14 +586,3 @@ int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id) return 0; } -#else -int nvme_nvm_register(struct request_queue *q, char *disk_name) -{ - return 0; -} -void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {}; -int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id) -{ - return 0; -} -#endif /* CONFIG_NVM */ diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index fdb4e5b..044253d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -136,8 +136,22 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr); int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg); int nvme_sg_get_version_num(int __user *ip); +#ifdef CONFIG_NVM int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id); int nvme_nvm_register(struct request_queue *q, char *disk_name); void nvme_nvm_unregister(struct request_queue *q, char *disk_name); +#else +static inline int nvme_nvm_register(struct request_queue *q, char *disk_name) +{ + return 0; +} + +static inline void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {}; + +static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id) +{ + return 0; +} +#endif /* CONFIG_NVM */ #endif /* _NVME_H */ -- cgit v0.10.2 From 8261bd48c6c9c36cd2c2e343a69e76a3be2b04a4 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sat, 28 Nov 2015 16:49:23 +0100 Subject: lightnvm: free memory when gennvm register fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit free allocated nvm block and gennvm lun structures when gennvm register fails, otherwise it will cause memory leak. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index e20e74e..3969a98 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -207,6 +207,14 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) return 0; } +static void gennvm_free(struct nvm_dev *dev) +{ + gennvm_blocks_free(dev); + gennvm_luns_free(dev); + kfree(dev->mp); + dev->mp = NULL; +} + static int gennvm_register(struct nvm_dev *dev) { struct gen_nvm *gn; @@ -234,16 +242,13 @@ static int gennvm_register(struct nvm_dev *dev) return 1; err: - kfree(gn); + gennvm_free(dev); return ret; } static void gennvm_unregister(struct nvm_dev *dev) { - gennvm_blocks_free(dev); - gennvm_luns_free(dev); - kfree(dev->mp); - dev->mp = NULL; + gennvm_free(dev); } static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, -- cgit v0.10.2 From 76e25081b6ae60fb094328dedf900ec15f10a9fd Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Sat, 28 Nov 2015 16:49:24 +0100 Subject: lightnvm: fix ioctl memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If copy_to_user() fails we returned error but we missed releasing devices. Signed-off-by: Sudip Mukherjee Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 5178645..ea50fa5 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -680,8 +680,10 @@ static long nvm_ioctl_info(struct file *file, void __user *arg) info->tgtsize = tgt_iter; up_write(&nvm_lock); - if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) + if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) { + kfree(info); return -EFAULT; + } kfree(info); return 0; @@ -724,8 +726,11 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg) devices->nr_devices = i; - if (copy_to_user(arg, devices, sizeof(struct nvm_ioctl_get_devices))) + if (copy_to_user(arg, devices, + sizeof(struct nvm_ioctl_get_devices))) { + kfree(devices); return -EFAULT; + } kfree(devices); return 0; -- cgit v0.10.2 From d160147b5c96ef5ec842c604ccd79f5f03306677 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sat, 28 Nov 2015 16:49:25 +0100 Subject: lightnvm: do device max sectors boundary check first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit do device max_phys_sect boundary check first, otherwise we will allocate dma_pools for devices whose max sectors are beyond lightnvm support and register them. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index ea50fa5..ea6dba5 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -308,6 +308,12 @@ int nvm_register(struct request_queue *q, char *disk_name, if (ret) goto err_init; + if (dev->ops->max_phys_sect > 256) { + pr_info("nvm: max sectors supported is 256.\n"); + ret = -EINVAL; + goto err_init; + } + if (dev->ops->max_phys_sect > 1) { dev->ppalist_pool = dev->ops->create_dma_pool(dev->q, "ppalist"); @@ -316,10 +322,6 @@ int nvm_register(struct request_queue *q, char *disk_name, ret = -ENOMEM; goto err_init; } - } else if (dev->ops->max_phys_sect > 256) { - pr_info("nvm: max sectors supported is 256.\n"); - ret = -EINVAL; - goto err_init; } down_write(&nvm_lock); -- cgit v0.10.2 From 09f2e716096811081b204c6afd6264c2e64d1210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sat, 28 Nov 2015 16:49:26 +0100 Subject: lightnvm: refactor and change vendor id for qemu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QEMU NVMe implementation uses Intel vendor, Intel device id, and the first vendor specific byte to identify a LightNVM compatible nvme instance. Instead of using the Intel specific, use a preallocated from CNEX Labs instead. This lets us uniquely identify a QEMU lightnvm device without breaking other vendor specific work in the qemu device driver. Reported-by: Christoph Hellwig Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 07451d6..b9e5cc7 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -569,18 +569,25 @@ void nvme_nvm_unregister(struct request_queue *q, char *disk_name) nvm_unregister(disk_name); } +/* move to shared place when used in multiple places. */ +#define PCI_VENDOR_ID_CNEX 0x1d1d +#define PCI_DEVICE_ID_CNEX_WL 0x2807 +#define PCI_DEVICE_ID_CNEX_QEMU 0x1f1f + int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id) { struct nvme_dev *dev = ns->dev; struct pci_dev *pdev = to_pci_dev(dev->dev); /* QEMU NVMe simulator - PCI ID + Vendor specific bit */ - if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x5845 && + if (pdev->vendor == PCI_VENDOR_ID_CNEX && + pdev->device == PCI_DEVICE_ID_CNEX_QEMU && id->vs[0] == 0x1) return 1; /* CNEX Labs - PCI ID + Vendor specific bit */ - if (pdev->vendor == 0x1d1d && pdev->device == 0x2807 && + if (pdev->vendor == PCI_VENDOR_ID_CNEX && + pdev->device == PCI_DEVICE_ID_CNEX_WL && id->vs[0] == 0x1) return 1; -- cgit v0.10.2 From 08236c6bb2980561fba657c58fdc76f2865f236c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sat, 28 Nov 2015 16:49:27 +0100 Subject: lightnvm: unconverted ppa returned in get_bb_tbl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_bb_tbl function takes ppa as a generic address, which is converted to the ppa device address within the device driver. When the update_bbtbl callback is called from get_bb_tbl, the device specific ppa is used, instead of the generic ppa. Make sure to pass the generic ppa. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 3969a98..35dde84 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -75,7 +75,6 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks, struct nvm_block *blk; int i; - ppa = dev_to_generic_addr(gn->dev, ppa); lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun]; for (i = 0; i < nr_blocks; i++) { @@ -187,7 +186,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) ppa.g.lun = lun->vlun.id; ppa = generic_to_dev_addr(dev, ppa); - ret = dev->ops->get_bb_tbl(dev->q, ppa, + ret = dev->ops->get_bb_tbl(dev, ppa, dev->blks_per_lun, gennvm_block_bb, gn); if (ret) diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index b9e5cc7..06c3364 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -355,10 +355,11 @@ out: return ret; } -static int nvme_nvm_get_bb_tbl(struct request_queue *q, struct ppa_addr ppa, +static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, int nr_blocks, nvm_bb_update_fn *update_bbtbl, void *priv) { + struct request_queue *q = nvmdev->q; struct nvme_ns *ns = q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_command c = {}; @@ -402,6 +403,7 @@ static int nvme_nvm_get_bb_tbl(struct request_queue *q, struct ppa_addr ppa, goto out; } + ppa = dev_to_generic_addr(nvmdev, ppa); ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv); if (ret) { ret = -EINTR; diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 3db5552..c6916ae 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -179,7 +179,7 @@ typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *); typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *); typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32, nvm_l2p_update_fn *, void *); -typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, struct ppa_addr, int, +typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int, nvm_bb_update_fn *, void *); typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int); typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *); -- cgit v0.10.2 From d0a712ceb83ebaea32d520825ee7b997f59b168f Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sat, 28 Nov 2015 16:49:28 +0100 Subject: lightnvm: missing nvm_lock acquire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid race conditions, traverse dev, media manager, and target lists and also register, unregister entries to/from them, should be always under the nvm_lock control. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index ea6dba5..86ce887 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -123,6 +123,26 @@ void nvm_unregister_mgr(struct nvmm_type *mt) } EXPORT_SYMBOL(nvm_unregister_mgr); +/* register with device with a supported manager */ +static int register_mgr(struct nvm_dev *dev) +{ + struct nvmm_type *mt; + int ret = 0; + + list_for_each_entry(mt, &nvm_mgrs, list) { + ret = mt->register_mgr(dev); + if (ret > 0) { + dev->mt = mt; + break; /* successfully initialized */ + } + } + + if (!ret) + pr_info("nvm: no compatible nvm manager found.\n"); + + return ret; +} + static struct nvm_dev *nvm_find_nvm_dev(const char *name) { struct nvm_dev *dev; @@ -221,7 +241,6 @@ static void nvm_free(struct nvm_dev *dev) static int nvm_init(struct nvm_dev *dev) { - struct nvmm_type *mt; int ret = -EINVAL; if (!dev->q || !dev->ops) @@ -252,21 +271,13 @@ static int nvm_init(struct nvm_dev *dev) goto err; } - /* register with device with a supported manager */ - list_for_each_entry(mt, &nvm_mgrs, list) { - ret = mt->register_mgr(dev); - if (ret < 0) - goto err; /* initialization failed */ - if (ret > 0) { - dev->mt = mt; - break; /* successfully initialized */ - } - } - - if (!ret) { - pr_info("nvm: no compatible manager found.\n"); + down_write(&nvm_lock); + ret = register_mgr(dev); + up_write(&nvm_lock); + if (ret < 0) + goto err; + if (!ret) return 0; - } pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n", dev->name, dev->sec_per_pg, dev->nr_planes, @@ -337,15 +348,17 @@ EXPORT_SYMBOL(nvm_register); void nvm_unregister(char *disk_name) { - struct nvm_dev *dev = nvm_find_nvm_dev(disk_name); + struct nvm_dev *dev; + down_write(&nvm_lock); + dev = nvm_find_nvm_dev(disk_name); if (!dev) { pr_err("nvm: could not find device %s to unregister\n", disk_name); + up_write(&nvm_lock); return; } - down_write(&nvm_lock); list_del(&dev->devices); up_write(&nvm_lock); @@ -363,38 +376,30 @@ static int nvm_create_target(struct nvm_dev *dev, { struct nvm_ioctl_create_simple *s = &create->conf.s; struct request_queue *tqueue; - struct nvmm_type *mt; struct gendisk *tdisk; struct nvm_tgt_type *tt; struct nvm_target *t; void *targetdata; int ret = 0; + down_write(&nvm_lock); if (!dev->mt) { - /* register with device with a supported NVM manager */ - list_for_each_entry(mt, &nvm_mgrs, list) { - ret = mt->register_mgr(dev); - if (ret < 0) - return ret; /* initialization failed */ - if (ret > 0) { - dev->mt = mt; - break; /* successfully initialized */ - } - } - - if (!ret) { - pr_info("nvm: no compatible nvm manager found.\n"); - return -ENODEV; + ret = register_mgr(dev); + if (!ret) + ret = -ENODEV; + if (ret < 0) { + up_write(&nvm_lock); + return ret; } } tt = nvm_find_target_type(create->tgttype); if (!tt) { pr_err("nvm: target type %s not found\n", create->tgttype); + up_write(&nvm_lock); return -EINVAL; } - down_write(&nvm_lock); list_for_each_entry(t, &dev->online_targets, list) { if (!strcmp(create->tgtname, t->disk->disk_name)) { pr_err("nvm: target name already exists.\n"); @@ -478,7 +483,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) struct nvm_dev *dev; struct nvm_ioctl_create_simple *s; + down_write(&nvm_lock); dev = nvm_find_nvm_dev(create->dev); + up_write(&nvm_lock); if (!dev) { pr_err("nvm: device not found\n"); return -EINVAL; @@ -537,7 +544,9 @@ static int nvm_configure_show(const char *val) return -EINVAL; } + down_write(&nvm_lock); dev = nvm_find_nvm_dev(devname); + up_write(&nvm_lock); if (!dev) { pr_err("nvm: device not found\n"); return -EINVAL; -- cgit v0.10.2 From bf4e6b4e757488dee1b6a581f49c7ac34cd217f8 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 26 Nov 2015 08:46:57 +0100 Subject: block: Always check queue limits for cloned requests When a cloned request is retried on other queues it always needs to be checked against the queue limits of that queue. Otherwise the calculations for nr_phys_segments might be wrong, leading to a crash in scsi_init_sgtable(). To clarify this the patch renames blk_rq_check_limits() to blk_cloned_rq_check_limits() and removes the symbol export, as the new function should only be used for cloned requests and never exported. Cc: Mike Snitzer Cc: Ewan Milne Cc: Jeff Moyer Signed-off-by: Hannes Reinecke Fixes: e2a60da74 ("block: Clean up special command handling logic") Cc: stable@vger.kernel.org # 3.7+ Acked-by: Mike Snitzer Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 5131993b..a0af404 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2114,7 +2114,8 @@ blk_qc_t submit_bio(int rw, struct bio *bio) EXPORT_SYMBOL(submit_bio); /** - * blk_rq_check_limits - Helper function to check a request for the queue limit + * blk_cloned_rq_check_limits - Helper function to check a cloned request + * for new the queue limits * @q: the queue * @rq: the request being checked * @@ -2125,20 +2126,13 @@ EXPORT_SYMBOL(submit_bio); * after it is inserted to @q, it should be checked against @q before * the insertion using this generic function. * - * This function should also be useful for request stacking drivers - * in some cases below, so export this function. * Request stacking drivers like request-based dm may change the queue - * limits while requests are in the queue (e.g. dm's table swapping). - * Such request stacking drivers should check those requests against - * the new queue limits again when they dispatch those requests, - * although such checkings are also done against the old queue limits - * when submitting requests. + * limits when retrying requests on other queues. Those requests need + * to be checked against the new queue limits again during dispatch. */ -int blk_rq_check_limits(struct request_queue *q, struct request *rq) +static int blk_cloned_rq_check_limits(struct request_queue *q, + struct request *rq) { - if (!rq_mergeable(rq)) - return 0; - if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; @@ -2158,7 +2152,6 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq) return 0; } -EXPORT_SYMBOL_GPL(blk_rq_check_limits); /** * blk_insert_cloned_request - Helper for stacking drivers to submit a request @@ -2170,7 +2163,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) unsigned long flags; int where = ELEVATOR_INSERT_BACK; - if (blk_rq_check_limits(q, rq)) + if (blk_cloned_rq_check_limits(q, rq)) return -EIO; if (rq->rq_disk && diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c0d2b79..c06f8ea 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -773,7 +773,6 @@ extern void blk_rq_set_block_pc(struct request *); extern void blk_requeue_request(struct request_queue *, struct request *); extern void blk_add_request_payload(struct request *rq, struct page *page, unsigned int len); -extern int blk_rq_check_limits(struct request_queue *q, struct request *rq); extern int blk_lld_busy(struct request_queue *q); extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, struct bio_set *bs, gfp_t gfp_mask, -- cgit v0.10.2 From 31ade3b83e1821da5fbb2f11b5b3d4ab2ec39db8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 29 Nov 2015 18:58:26 -0800 Subject: Linux 4.4-rc3 diff --git a/Makefile b/Makefile index 2ffdf9d..904a1d6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Blurry Fish Butt # *DOCUMENTATION* -- cgit v0.10.2 From 880621c2605b82eb5af91a2c94223df6f5a3fb64 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 22 Nov 2015 17:46:09 +0100 Subject: packet: Allow packets with only a header (but no payload) Commit 9c7077622dd91 ("packet: make packet_snd fail on len smaller than l2 header") added validation for the packet size in packet_snd. This change enforces that every packet needs a header (with at least hard_header_len bytes) plus a payload with at least one byte. Before this change the payload was optional. This fixes PPPoE connections which do not have a "Service" or "Host-Uniq" configured (which is violating the spec, but is still widely used in real-world setups). Those are currently failing with the following message: "pppd: packet size is too short (24 <= 24)" Signed-off-by: Martin Blumenstingl Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 67bfac1..3b5d134 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1398,7 +1398,8 @@ enum netdev_priv_flags { * @dma: DMA channel * @mtu: Interface MTU value * @type: Interface hardware type - * @hard_header_len: Hardware header length + * @hard_header_len: Hardware header length, which means that this is the + * minimum size of a packet. * * @needed_headroom: Extra headroom the hardware may need, but not in all * cases can this be guaranteed diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 1cf928f..992396a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2329,8 +2329,8 @@ static void tpacket_destruct_skb(struct sk_buff *skb) static bool ll_header_truncated(const struct net_device *dev, int len) { /* net device doesn't like empty head */ - if (unlikely(len <= dev->hard_header_len)) { - net_warn_ratelimited("%s: packet size is too short (%d <= %d)\n", + if (unlikely(len < dev->hard_header_len)) { + net_warn_ratelimited("%s: packet size is too short (%d < %d)\n", current->comm, len, dev->hard_header_len); return true; } -- cgit v0.10.2 From 9ffad80a9c65d7c2ab5ad6cb8b4b0559b9ed8b8c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 Nov 2015 09:02:10 -0800 Subject: drivers: net: xgene: fix possible use after free Once TX has been enabled on a NIC, it is illegal to access skb, as this skb might have been freed by another cpu, from TX completion handler. Signed-off-by: Eric Dumazet Reported-by: Mark Rutland Tested-by: Mark Rutland Cc: Iyappan Subramanian Acked-by: Iyappan Subramanian Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 1adfe70..9147a01 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -450,12 +450,12 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } - pdata->ring_ops->wr_cmd(tx_ring, count); skb_tx_timestamp(skb); pdata->stats.tx_packets++; pdata->stats.tx_bytes += skb->len; + pdata->ring_ops->wr_cmd(tx_ring, count); return NETDEV_TX_OK; } -- cgit v0.10.2 From 000255b7dfc3119c13f388f179d6fc19cd00eada Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 20 Nov 2015 15:35:14 +0200 Subject: gpio: omap: drop omap1 mpuio specific irq_mask/unmask callbacks Originally OMAP MPUIO GPIO irqchip was implemented using Generic irq chip, but after set of reworks Generic irq chip code was replaced by common OMAP GPIO implementation and finally removed by commit d2d05c65c40e ("gpio: omap: Fix regression for MPUIO interrupts"). Unfortunately, above commit left .irq_mask/unmask callbacks assigned as below for MPUIO GPIO case: irqc->irq_mask = irq_gc_mask_set_bit; irqc->irq_unmask = irq_gc_mask_clr_bit; This now causes boot failure on OMAP1 platforms, after commit 450fa54cfd66 ("gpio: omap: convert to use generic irq handler") which forces these callbacks to be called during GPIO IRQs mapping from gpiochip_irq_map: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 75 [#1] ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.4.0-rc1-e3-los_afe0c+-00002-g25379c0-dirty #1 Hardware name: Amstrad E3 (Delta) task: c1836000 ti: c1838000 task.ti: c1838000 PC is at irq_gc_mask_set_bit+0x1c/0x60 LR is at __irq_do_set_handler+0x118/0x15c pc : [] lr : [] psr: 600000d3 sp : c1839c90 ip : c1862c64 fp : c1839c9c r10: 00000000 r9 : c0411950 r8 : c0411bbc r7 : 00000000 r6 : c185c310 r5 : c00444e8 r4 : c185c300 r3 : c1854b50 r2 : 00000000 r1 : 00000000 r0 : c185c310 Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel Control: 0000317f Table: 10004000 DAC: 00000057 Process swapper (pid: 1, stack limit = 0xc1838190) Stack: (0xc1839c90 to 0xc183a000) [...] Backtrace: [] (irq_gc_mask_set_bit) from [] (__irq_do_set_handler+0x118/0x15c) [] (__irq_do_set_handler) from [] (__irq_set_handler+0x44/0x5c) r6:00000000 r5:c00444e8 r4:c185c300 [] (__irq_set_handler) from [] (irq_set_chip_and_handler_name+0x30/0x34) r7:00000050 r6:00000000 r5:c00444e8 r4:00000050 [] (irq_set_chip_and_handler_name) from [] (gpiochip_irq_map+0x3c/0x8c) r7:00000050 r6:00000000 r5:00000050 r4:c1862c64 [] (gpiochip_irq_map) from [] (irq_domain_associate+0x7c/0x1c4) r5:c185c310 r4:c185cb00 [] (irq_domain_associate) from [] (irq_domain_add_simple+0x98/0xc0) r8:c0411bbc r7:c185cb00 r6:00000050 r5:00000010 r4:00000001 [] (irq_domain_add_simple) from [] (_gpiochip_irqchip_add+0x64/0x10c) r7:c1862c64 r6:c0419280 r5:c1862c64 r4:c1854b50 [] (_gpiochip_irqchip_add) from [] (omap_gpio_probe+0x2fc/0x63c) r5:c1854b50 r4:c1862c10 [] (omap_gpio_probe) from [] (platform_drv_probe+0x2c/0x64) r10:00000000 r9:c03e45e8 r8:00000000 r7:c0419294 r6:c0411984 r5:c0419294 r4:c0411950 [] (platform_drv_probe) from [] (really_probe+0x160/0x29c) Hence, fix it by remove obsolete callbacks assignment. After this change omap_gpio_mask_irq()/omap_gpio_unmask_irq() will be used for MPUIO IRQs masking, but this now happens anyway from omap_gpio_irq_startup/shutdown(). Cc: Tony Lindgren Fixes: commit d2d05c65c40e ("gpio: omap: Fix regression for MPUIO interrupts") Reported-by: Aaro Koskinen Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Tested-by: Aaro Koskinen Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 56d2d02..f7fbb46 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1122,8 +1122,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) /* MPUIO is a bit different, reading IRQ status clears it */ if (bank->is_mpuio) { irqc->irq_ack = dummy_irq_chip.irq_ack; - irqc->irq_mask = irq_gc_mask_set_bit; - irqc->irq_unmask = irq_gc_mask_clr_bit; if (!bank->regs->wkup_en) irqc->irq_set_wake = NULL; } -- cgit v0.10.2 From 53254f900bd9ff1e3cc5628e76126bb403d9d160 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Nov 2015 14:55:41 -0500 Subject: cgroup: make css_set pin its css's to avoid use-afer-free A css_set represents the relationship between a set of tasks and css's. css_set never pinned the associated css's. This was okay because tasks used to always disassociate immediately (in RCU sense) - either a task is moved to a different css_set or exits and never accesses css_set again. Unfortunately, afcf6c8b7544 ("cgroup: add cgroup_subsys->free() method and use it to fix pids controller") and patches leading up to it made a zombie hold onto its css_set and deref the associated css's on its release. Nothing pins the css's after exit and it might have already been freed leading to use-after-free. general protection fault: 0000 [#1] PREEMPT SMP task: ffffffff81bf2500 ti: ffffffff81be4000 task.ti: ffffffff81be4000 RIP: 0010:[] [] pids_cancel.constprop.4+0x5/0x40 ... Call Trace: [] ? pids_free+0x3d/0xa0 [] cgroup_free+0x53/0xe0 [] __put_task_struct+0x42/0x130 [] delayed_put_task_struct+0x77/0x130 [] rcu_process_callbacks+0x2f4/0x820 [] ? rcu_process_callbacks+0x2b3/0x820 [] __do_softirq+0xd4/0x460 [] irq_exit+0x89/0xa0 [] smp_apic_timer_interrupt+0x42/0x50 [] apic_timer_interrupt+0x84/0x90 ... Code: 5b 5d c3 48 89 df 48 c7 c2 c9 f9 ae 81 48 c7 c6 91 2c ae 81 e8 1d 94 0e 00 31 c0 5b 5d c3 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 83 87 e0 00 00 00 ff 78 01 c3 80 3d 08 7a c1 00 00 74 02 RIP [] pids_cancel.constprop.4+0x5/0x40 RSP ---[ end trace 89a4a4b916b90c49 ]--- Kernel panic - not syncing: Fatal exception in interrupt Kernel Offset: disabled ---[ end Kernel panic - not syncing: Fatal exception in interrupt Fix it by making css_set pin the associate css's until its release. Signed-off-by: Tejun Heo Reported-by: Dave Jones Reported-by: Daniel Wagner Link: http://lkml.kernel.org/g/20151120041836.GA18390@codemonkey.org.uk Link: http://lkml.kernel.org/g/5652D448.3080002@bmw-carit.de Fixes: afcf6c8b7544 ("cgroup: add cgroup_subsys->free() method and use it to fix pids controller") diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b316deb..5cea63f 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -760,9 +760,11 @@ static void put_css_set_locked(struct css_set *cset) if (!atomic_dec_and_test(&cset->refcount)) return; - /* This css_set is dead. unlink it and release cgroup refcounts */ - for_each_subsys(ss, ssid) + /* This css_set is dead. unlink it and release cgroup and css refs */ + for_each_subsys(ss, ssid) { list_del(&cset->e_cset_node[ssid]); + css_put(cset->subsys[ssid]); + } hash_del(&cset->hlist); css_set_count--; @@ -1062,9 +1064,13 @@ static struct css_set *find_css_set(struct css_set *old_cset, key = css_set_hash(cset->subsys); hash_add(css_set_table, &cset->hlist, key); - for_each_subsys(ss, ssid) + for_each_subsys(ss, ssid) { + struct cgroup_subsys_state *css = cset->subsys[ssid]; + list_add_tail(&cset->e_cset_node[ssid], - &cset->subsys[ssid]->cgroup->e_csets[ssid]); + &css->cgroup->e_csets[ssid]); + css_get(css); + } spin_unlock_bh(&css_set_lock); -- cgit v0.10.2 From c9e75f0492b248aeaa7af8991a6fc9a21506bc96 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 27 Nov 2015 19:57:19 +0100 Subject: cgroup: pids: fix race between cgroup_post_fork() and cgroup_migrate() If the new child migrates to another cgroup before cgroup_post_fork() calls subsys->fork(), then both pids_can_attach() and pids_fork() will do the same pids_uncharge(old_pids) + pids_charge(pids) sequence twice. Change copy_process() to call threadgroup_change_begin/threadgroup_change_end unconditionally. percpu_down_read() is cheap and this allows other cleanups, see the next changes. Also, this way we can unify cgroup_threadgroup_rwsem and dup_mmap_sem. Signed-off-by: Oleg Nesterov Acked-by: Zefan Li Signed-off-by: Tejun Heo diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c index cdd8df4..15ef2e4 100644 --- a/kernel/cgroup_pids.c +++ b/kernel/cgroup_pids.c @@ -243,27 +243,10 @@ static void pids_cancel_fork(struct task_struct *task, void *priv) static void pids_fork(struct task_struct *task, void *priv) { - struct cgroup_subsys_state *css; - struct cgroup_subsys_state *old_css = priv; - struct pids_cgroup *pids; - struct pids_cgroup *old_pids = css_pids(old_css); - - css = task_get_css(task, pids_cgrp_id); - pids = css_pids(css); - - /* - * If the association has changed, we have to revert and reapply the - * charge/uncharge on the wrong hierarchy to the current one. Since - * the association can only change due to an organisation event, its - * okay for us to ignore the limit in this case. - */ - if (pids != old_pids) { - pids_uncharge(old_pids, 1); - pids_charge(pids, 1); - } + struct cgroup_subsys_state *css = priv; + WARN_ON(task_css_check(task, pids_cgrp_id, true) != css); css_put(css); - css_put(old_css); } static void pids_free(struct task_struct *task) diff --git a/kernel/fork.c b/kernel/fork.c index f97f2c4..fce002e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1368,8 +1368,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->real_start_time = ktime_get_boot_ns(); p->io_context = NULL; p->audit_context = NULL; - if (clone_flags & CLONE_THREAD) - threadgroup_change_begin(current); + threadgroup_change_begin(current); cgroup_fork(p); #ifdef CONFIG_NUMA p->mempolicy = mpol_dup(p->mempolicy); @@ -1610,8 +1609,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, proc_fork_connector(p); cgroup_post_fork(p, cgrp_ss_priv); - if (clone_flags & CLONE_THREAD) - threadgroup_change_end(current); + threadgroup_change_end(current); perf_event_fork(p); trace_task_newtask(p, clone_flags); @@ -1652,8 +1650,7 @@ bad_fork_cleanup_policy: mpol_put(p->mempolicy); bad_fork_cleanup_threadgroup_lock: #endif - if (clone_flags & CLONE_THREAD) - threadgroup_change_end(current); + threadgroup_change_end(current); delayacct_tsk_free(p); bad_fork_cleanup_count: atomic_dec(&p->cred->user->processes); -- cgit v0.10.2 From afbcb364bee9e7cf46c94257a82cb9760b6d254f Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 27 Nov 2015 19:57:22 +0100 Subject: cgroup: pids: kill pids_fork(), simplify pids_can_fork() and pids_cancel_fork() Now that we know that the forking task can't migrate amd the child is always moved to the same cgroup by cgroup_post_fork()->css_set_move_task() we can change pids_can_fork() and pids_cancel_fork() to just use task_css(current). And since we no longer need to pin this css, we can remove pid_fork(). Note: the patch uses task_css_check(true), perhaps it makes sense to add a helper or change task_css_set_check() to take cgroup_threadgroup_rwsem into account. Signed-off-by: Oleg Nesterov Acked-by: Zefan Li Signed-off-by: Tejun Heo diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c index 15ef2e4..de3359a 100644 --- a/kernel/cgroup_pids.c +++ b/kernel/cgroup_pids.c @@ -205,48 +205,28 @@ static void pids_cancel_attach(struct cgroup_subsys_state *css, } } +/* + * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies + * on threadgroup_change_begin() held by the copy_process(). + */ static int pids_can_fork(struct task_struct *task, void **priv_p) { struct cgroup_subsys_state *css; struct pids_cgroup *pids; - int err; - /* - * Use the "current" task_css for the pids subsystem as the tentative - * css. It is possible we will charge the wrong hierarchy, in which - * case we will forcefully revert/reapply the charge on the right - * hierarchy after it is committed to the task proper. - */ - css = task_get_css(current, pids_cgrp_id); + css = task_css_check(current, pids_cgrp_id, true); pids = css_pids(css); - - err = pids_try_charge(pids, 1); - if (err) - goto err_css_put; - - *priv_p = css; - return 0; - -err_css_put: - css_put(css); - return err; + return pids_try_charge(pids, 1); } static void pids_cancel_fork(struct task_struct *task, void *priv) { - struct cgroup_subsys_state *css = priv; - struct pids_cgroup *pids = css_pids(css); + struct cgroup_subsys_state *css; + struct pids_cgroup *pids; + css = task_css_check(current, pids_cgrp_id, true); + pids = css_pids(css); pids_uncharge(pids, 1); - css_put(css); -} - -static void pids_fork(struct task_struct *task, void *priv) -{ - struct cgroup_subsys_state *css = priv; - - WARN_ON(task_css_check(task, pids_cgrp_id, true) != css); - css_put(css); } static void pids_free(struct task_struct *task) @@ -329,7 +309,6 @@ struct cgroup_subsys pids_cgrp_subsys = { .cancel_attach = pids_cancel_attach, .can_fork = pids_can_fork, .cancel_fork = pids_cancel_fork, - .fork = pids_fork, .free = pids_free, .legacy_cftypes = pids_files, .dfl_cftypes = pids_files, -- cgit v0.10.2 From 023113d24ef9e1d2b44cb2446872b17e2b01d8b1 Mon Sep 17 00:00:00 2001 From: Xiangliang Yu Date: Thu, 26 Nov 2015 20:27:02 +0800 Subject: AHCI: Fix softreset failed issue of Port Multiplier Current code doesn't update port value of Port Multiplier(PM) when sending FIS of softreset to device, command will fail if FBS is enabled. There are two ways to fix the issue: the first is to disable FBS before sending softreset command to PM device and the second is to update port value of PM when sending command. For the first way, i can't find any related rule in AHCI Spec. The second way can avoid disabling FBS and has better performance. Signed-off-by: Xiangliang Yu Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 096064c..4665512 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1273,6 +1273,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, ata_tf_to_fis(tf, pmp, is_cmd, fis); ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); + /* set port value for softreset of Port Multiplier */ + if (pp->fbs_enabled && pp->fbs_last_dev != pmp) { + tmp = readl(port_mmio + PORT_FBS); + tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC); + tmp |= pmp << PORT_FBS_DEV_OFFSET; + writel(tmp, port_mmio + PORT_FBS); + pp->fbs_last_dev = pmp; + } + /* issue & wait */ writel(1, port_mmio + PORT_CMD_ISSUE); -- cgit v0.10.2 From c86576ea114a9a881cf7328dc7181052070ca311 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 28 Nov 2015 08:52:04 -0800 Subject: mn10300: Select CONFIG_HAVE_UID16 to fix build failure mn10300 builds fail with fs/stat.c: In function 'cp_old_stat': fs/stat.c:163:2: error: 'old_uid_t' undeclared ipc/util.c: In function 'ipc64_perm_to_ipc_perm': ipc/util.c:540:2: error: 'old_uid_t' undeclared Select CONFIG_HAVE_UID16 and remove local definition of CONFIG_UID16 to fix the problem. Fixes: fbc416ff8618 ("arm64: fix building without CONFIG_UID16") Cc: Arnd Bergmann Acked-by: Arnd Bergmann Acked-by: Acked-by: David Howells Signed-off-by: Guenter Roeck diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 4434b54..78ae555 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -1,6 +1,7 @@ config MN10300 def_bool y select HAVE_OPROFILE + select HAVE_UID16 select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select HAVE_ARCH_TRACEHOOK @@ -37,9 +38,6 @@ config HIGHMEM config NUMA def_bool n -config UID16 - def_bool y - config RWSEM_GENERIC_SPINLOCK def_bool y -- cgit v0.10.2 From d98f1cd0a3b70ea91f1dfda3ac36c3b2e1a4d5e2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 26 Nov 2015 12:00:59 -0500 Subject: sata_sil: disable trim When I connect an Intel SSD to SATA SIL controller (PCI ID 1095:3114), any TRIM command results in I/O errors being reported in the log. There is other similar error reported with TRIM and the SIL controller: https://bugs.centos.org/view.php?id=5880 Apparently the controller doesn't support TRIM commands. This patch disables TRIM support on the SATA SIL controller. ata7.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x0 ata7.00: BMDMA2 stat 0x50001 ata7.00: failed command: DATA SET MANAGEMENT ata7.00: cmd 06/01:01:00:00:00/00:00:00:00:00/a0 tag 0 dma 512 out res 51/04:01:00:00:00/00:00:00:00:00/a0 Emask 0x1 (device error) ata7.00: status: { DRDY ERR } ata7.00: error: { ABRT } ata7.00: device reported invalid CHS sector 0 sd 8:0:0:0: [sdb] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE sd 8:0:0:0: [sdb] tag#0 Sense Key : Illegal Request [current] [descriptor] sd 8:0:0:0: [sdb] tag#0 Add. Sense: Unaligned write command sd 8:0:0:0: [sdb] tag#0 CDB: Write same(16) 93 08 00 00 00 00 00 21 95 88 00 20 00 00 00 00 blk_update_request: I/O error, dev sdb, sector 2200968 Signed-off-by: Mikulas Patocka Cc: stable@kernel.org Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index dea6edcb..29bcff0 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -630,6 +630,9 @@ static void sil_dev_config(struct ata_device *dev) unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; + /* This controller doesn't support trim */ + dev->horkage |= ATA_HORKAGE_NOTRIM; + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); for (n = 0; sil_blacklist[n].product; n++) -- cgit v0.10.2 From bc0d0d093b379b0b379c429e3348498287c8a9ca Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Nov 2015 09:10:33 -0800 Subject: libnvdimm, e820: skip module loading when no type-12 If there are no persistent memory ranges present then don't bother creating the platform device. Otherwise, it loads the full libnvdimm sub-system only to discover no resources present. Reported-by: Andy Lutomirski Acked-by: Andy Lutomirski Signed-off-by: Dan Williams diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c index 4f00b63..14415af 100644 --- a/arch/x86/kernel/pmem.c +++ b/arch/x86/kernel/pmem.c @@ -4,10 +4,22 @@ */ #include #include +#include + +static int found(u64 start, u64 end, void *data) +{ + return 1; +} static __init int register_e820_pmem(void) { + char *pmem = "Persistent Memory (legacy)"; struct platform_device *pdev; + int rc; + + rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found); + if (rc <= 0) + return 0; /* * See drivers/nvdimm/e820.c for the implementation, this is -- cgit v0.10.2 From 74cedf9b6c603f2278a05bc91b140b32b434d0b5 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 30 Nov 2015 10:15:42 -0700 Subject: direct-io: Fix negative return from dio read beyond eof Assume a filesystem with 4KB blocks. When a file has size 1000 bytes and we issue direct IO read at offset 1024, blockdev_direct_IO() reads the tail of the last block and the logic for handling short DIO reads in dio_complete() results in a return value -24 (1000 - 1024) which obviously confuses userspace. Fix the problem by bailing out early once we sample i_size and can reliably check that direct IO read starts beyond i_size. Reported-by: Avi Kivity Fixes: 9fe55eea7e4b444bafc42fa0000cc2d1d2847275 CC: stable@vger.kernel.org CC: Steven Whitehouse Signed-off-by: Jan Kara Signed-off-by: Jens Axboe diff --git a/fs/direct-io.c b/fs/direct-io.c index cb5337d..1c75a3a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1169,6 +1169,15 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, } } + /* Once we sampled i_size check for reads beyond EOF */ + dio->i_size = i_size_read(inode); + if (iov_iter_rw(iter) == READ && offset >= dio->i_size) { + if (dio->flags & DIO_LOCKING) + mutex_unlock(&inode->i_mutex); + kmem_cache_free(dio_cache, dio); + goto out; + } + /* * For file extending writes updating i_size before data writeouts * complete can expose uninitialized blocks in dumb filesystems. @@ -1222,7 +1231,6 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, sdio.next_block_for_io = -1; dio->iocb = iocb; - dio->i_size = i_size_read(inode); spin_lock_init(&dio->bio_lock); dio->refcount = 1; -- cgit v0.10.2 From d3e41a9fc091bf5f5d4504aead899d73bd67d71e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 12 Nov 2015 15:07:30 +0100 Subject: ARM: dts: add dm816x missing #mbox-cells Add missing #mbox-cells for dm816x mbox DT node. Cc: Brian Hutchinson Signed-off-by: Neil Armstrong Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index 3c99cfa..a7a34e4 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -218,6 +218,7 @@ reg = <0x480c8000 0x2000>; interrupts = <77>; ti,hwmods = "mailbox"; + #mbox-cells = <1>; ti,mbox-num-users = <4>; ti,mbox-num-fifos = <12>; mbox_dsp: mbox_dsp { -- cgit v0.10.2 From f1b2e7c29a52309724d13a1eb4de457406697118 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 12 Nov 2015 15:07:35 +0100 Subject: ARM: dts: add dm816x missing spi DT dma handles Add the missing SPI controller DMA handler in the dm816x DT node, only properties for the two channels on four were present. Cc: Brian Hutchinson Signed-off-by: Neil Armstrong Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index a7a34e4..eee636d 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -280,8 +280,11 @@ ti,spi-num-cs = <4>; ti,hwmods = "mcspi1"; dmas = <&edma 16 &edma 17 - &edma 18 &edma 19>; - dma-names = "tx0", "rx0", "tx1", "rx1"; + &edma 18 &edma 19 + &edma 20 &edma 21 + &edma 22 &edma 23>; + dma-names = "tx0", "rx0", "tx1", "rx1", + "tx2", "rx2", "tx3", "rx3"; }; mmc1: mmc@48060000 { -- cgit v0.10.2 From 585116c5fafe578e89c146c9839c95ac75acfb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 26 Nov 2015 11:06:20 +0100 Subject: drm/amdgpu: fix userptr flags check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That got messed up while porting it from Radeon. Reviewed-by: Michel Dänzer Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index fc32fc0..f6ea4b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -235,8 +235,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, AMDGPU_GEM_USERPTR_REGISTER)) return -EINVAL; - if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) || - !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) { + if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && ( + !(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) || + !(args->flags & AMDGPU_GEM_USERPTR_REGISTER))) { /* if we want to write to it we must require anonymous memory and install a MMU notifier */ -- cgit v0.10.2 From 82b9c55b1edfcb87f5568add56bc7313f5893b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 27 Nov 2015 16:49:00 +0100 Subject: drm/amdgpu: fix VM page table reference counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the reservation object of the page directory for the page tables as well, because of this the page directory should be freed last. Ensure that by keeping a reference from the page tables to the directory. Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 251b147..670fefb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -539,6 +539,7 @@ struct amdgpu_bo { /* Constant after initialization */ struct amdgpu_device *adev; struct drm_gem_object gem_base; + struct amdgpu_bo *parent; struct ttm_bo_kmap_obj dma_buf_vmap; pid_t pid; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 0d52438..c3ce103 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -100,6 +100,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) list_del_init(&bo->list); mutex_unlock(&bo->adev->gem.mutex); drm_gem_object_release(&bo->gem_base); + amdgpu_bo_unref(&bo->parent); kfree(bo->metadata); kfree(bo); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index ae037e5..a582ef5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1079,6 +1079,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, if (r) goto error_free; + /* Keep a reference to the page table to avoid freeing + * them up in the wrong order. + */ + pt->parent = amdgpu_bo_ref(vm->page_directory); + r = amdgpu_vm_clear_bo(adev, pt); if (r) { amdgpu_bo_unref(&pt); -- cgit v0.10.2 From 0c62c6599b28b8f9e5a1822668325083598579da Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sat, 28 Nov 2015 22:01:05 +0100 Subject: add blacklist for thinkpad T40p Thinkpad T40p needs agpmode 1. Signed-off-by: Pavel Machek Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index fe994aa..c77d349 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -54,6 +54,9 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50, PCI_VENDOR_ID_IBM, 0x0550, 1}, + /* Intel 82855PM host bridge / RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] needs AGPMode 1 (Thinkpad T40p) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x054d, 1}, /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57, PCI_VENDOR_ID_IBM, 0x0530, 1}, -- cgit v0.10.2 From ac316c783d5bef4240db3de000c1bc74481df88e Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 26 Nov 2015 08:35:41 +0100 Subject: stmmac: fix a filter problem after resuming. When resume the HW is re-configured but some settings can be lost. For example, the MAC Address_X High/Low Registers used for VLAN tagging.. So, while resuming, the set_filter callback needs to be invoked to re-program perfect and hash-table registers. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 64d8aa4..e3d96f2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3102,6 +3102,7 @@ int stmmac_resume(struct net_device *ndev) init_dma_desc_rings(ndev, GFP_ATOMIC); stmmac_hw_setup(ndev, false); stmmac_init_tx_coalesce(priv); + stmmac_set_rx_mode(ndev); napi_enable(&priv->napi); -- cgit v0.10.2 From 61adcc03bd010a494664dc46049dc8da245bc277 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 26 Nov 2015 08:35:42 +0100 Subject: stmmac: fix csr clock divisor for 300MHz This patch is to fix the csr clock in case of 300MHz is provided. Reported-by: Kent Borg Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e3d96f2..6256b32 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -185,7 +185,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) priv->clk_csr = STMMAC_CSR_100_150M; else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) priv->clk_csr = STMMAC_CSR_150_250M; - else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) + else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M)) priv->clk_csr = STMMAC_CSR_250_300M; } } -- cgit v0.10.2 From 22407e13172e9d5257ad3548a4f69bff8ed20111 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 26 Nov 2015 08:35:43 +0100 Subject: stmmac: dwmac-sti: fix st,tx-retime-src check In case of the st,tx-retime-src is missing from device-tree (it's an optional field) the driver will invoke the strcasecmp to check which clock has been selected and this is a bug; the else condition is needed. In the dwmac_setup, the "rs" variable, passed to the strcasecmp, was not initialized and the compiler, depending on the options adopted, could take it in some different part of the stack generating the hang in such configuration. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 7f6f4a4..58c05ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -299,16 +299,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { const char *rs; + dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; + err = of_property_read_string(np, "st,tx-retime-src", &rs); if (err < 0) { dev_warn(dev, "Use internal clock source\n"); - dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; - } else if (!strcasecmp(rs, "clk_125")) { - dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; - } else if (!strcasecmp(rs, "txclk")) { - dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; + } else { + if (!strcasecmp(rs, "clk_125")) + dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; + else if (!strcasecmp(rs, "txclk")) + dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; } - dwmac->speed = SPEED_1000; } -- cgit v0.10.2 From ae26c1c6cb9bd5ad6fa1dbfdf1fe430ac09b0d28 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 26 Nov 2015 08:35:44 +0100 Subject: stmmac: fix PHY reset during resume When stmmac_mdio_reset, was called from stmmac_resume, it was not resetting the PHY due to which MAC was not getting reset properly and hence ethernet interface not was resumed properly. The issue was currently only reproducible on stih301-b2204. Signed-off-by: Pankaj Dev Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index ebf6abc..bba670c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -138,7 +138,6 @@ int stmmac_mdio_reset(struct mii_bus *bus) #ifdef CONFIG_OF if (priv->device->of_node) { - int reset_gpio, active_low; if (data->reset_gpio < 0) { struct device_node *np = priv->device->of_node; @@ -154,24 +153,23 @@ int stmmac_mdio_reset(struct mii_bus *bus) "snps,reset-active-low"); of_property_read_u32_array(np, "snps,reset-delays-us", data->delays, 3); - } - reset_gpio = data->reset_gpio; - active_low = data->active_low; + if (gpio_request(data->reset_gpio, "mdio-reset")) + return 0; + } - if (!gpio_request(reset_gpio, "mdio-reset")) { - gpio_direction_output(reset_gpio, active_low ? 1 : 0); - if (data->delays[0]) - msleep(DIV_ROUND_UP(data->delays[0], 1000)); + gpio_direction_output(data->reset_gpio, + data->active_low ? 1 : 0); + if (data->delays[0]) + msleep(DIV_ROUND_UP(data->delays[0], 1000)); - gpio_set_value(reset_gpio, active_low ? 0 : 1); - if (data->delays[1]) - msleep(DIV_ROUND_UP(data->delays[1], 1000)); + gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); + if (data->delays[1]) + msleep(DIV_ROUND_UP(data->delays[1], 1000)); - gpio_set_value(reset_gpio, active_low ? 1 : 0); - if (data->delays[2]) - msleep(DIV_ROUND_UP(data->delays[2], 1000)); - } + gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); + if (data->delays[2]) + msleep(DIV_ROUND_UP(data->delays[2], 1000)); } #endif -- cgit v0.10.2 From e527c4a769d375ac0472450c52bde29087f49cd9 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 26 Nov 2015 08:35:45 +0100 Subject: stmmac: fix oversized frame reception The receive skb buffers can be preallocated when the link is opened according to mtu size. While testing on a network environment with not standard MTU (e.g. 3000), a panic occurred if an incoming packet had a length greater than rx skb buffer size. This is because the HW is programmed to copy, from the DMA, an Jumbo frame and the Sw must check if the allocated buffer is enough to store the frame. Signed-off-by: Alexandre TORGUE Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6256b32..3c6549a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2232,6 +2232,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) frame_len = priv->hw->desc->get_rx_frame_len(p, coe); + /* check if frame_len fits the preallocated memory */ + if (frame_len > priv->dma_buf_sz) { + priv->dev->stats.rx_length_errors++; + break; + } + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 * Type frames (LLC/LLC-SNAP) */ -- cgit v0.10.2 From a88d32af18b8a6616128c971f766eaf545966405 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 30 Nov 2015 16:05:49 +0800 Subject: blk-merge: fix computing bio->bi_seg_front_size in case of single segment When bio has only one physical segment, we should set bio's bi_seg_front_size as the real(final) size of the single segment. Fixes: 02e707424c2ea(blk-merge: fix blk_bio_segment_split) Reported-by: Markus Trippelsdorf Tested-by: Markus Trippelsdorf Signed-off-by: Ming Lei Signed-off-by: Jens Axboe diff --git a/block/blk-merge.c b/block/blk-merge.c index 41a55ba..e01405a 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -103,6 +103,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, bvprv = bv; bvprvp = &bvprv; sectors += bv.bv_len >> 9; + + if (nsegs == 1 && seg_size > front_seg_size) + front_seg_size = seg_size; continue; } new_segment: -- cgit v0.10.2 From 9490f886b192964796285907d777ff00fba1fa0f Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 26 Nov 2015 12:08:18 +0100 Subject: af-unix: passcred support for sendpage sendpage did not care about credentials at all. This could lead to situations in which because of fd passing between processes we could append data to skbs with different scm data. It is illegal to splice those skbs together. Instead we have to allocate a new skb and if requested fill out the scm details. Fixes: 869e7c62486ec ("net: af_unix: implement stream sendpage support") Reported-by: Al Viro Cc: Al Viro Cc: Eric Dumazet Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4e95bdf..6ced746 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1551,6 +1551,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen return err; } +static bool unix_passcred_enabled(const struct socket *sock, + const struct sock *other) +{ + return test_bit(SOCK_PASSCRED, &sock->flags) || + !other->sk_socket || + test_bit(SOCK_PASSCRED, &other->sk_socket->flags); +} + /* * Some apps rely on write() giving SCM_CREDENTIALS * We include credentials if source or destination socket @@ -1561,14 +1569,41 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, { if (UNIXCB(skb).pid) return; - if (test_bit(SOCK_PASSCRED, &sock->flags) || - !other->sk_socket || - test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) { + if (unix_passcred_enabled(sock, other)) { UNIXCB(skb).pid = get_pid(task_tgid(current)); current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid); } } +static int maybe_init_creds(struct scm_cookie *scm, + struct socket *socket, + const struct sock *other) +{ + int err; + struct msghdr msg = { .msg_controllen = 0 }; + + err = scm_send(socket, &msg, scm, false); + if (err) + return err; + + if (unix_passcred_enabled(socket, other)) { + scm->pid = get_pid(task_tgid(current)); + current_uid_gid(&scm->creds.uid, &scm->creds.gid); + } + return err; +} + +static bool unix_skb_scm_eq(struct sk_buff *skb, + struct scm_cookie *scm) +{ + const struct unix_skb_parms *u = &UNIXCB(skb); + + return u->pid == scm->pid && + uid_eq(u->uid, scm->creds.uid) && + gid_eq(u->gid, scm->creds.gid) && + unix_secdata_eq(scm, skb); +} + /* * Send AF_UNIX data. */ @@ -1884,8 +1919,10 @@ out_err: static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page, int offset, size_t size, int flags) { - int err = 0; - bool send_sigpipe = true; + int err; + bool send_sigpipe = false; + bool init_scm = true; + struct scm_cookie scm; struct sock *other, *sk = socket->sk; struct sk_buff *skb, *newskb = NULL, *tail = NULL; @@ -1903,7 +1940,7 @@ alloc_skb: newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT, &err, 0); if (!newskb) - return err; + goto err; } /* we must acquire readlock as we modify already present @@ -1912,12 +1949,12 @@ alloc_skb: err = mutex_lock_interruptible(&unix_sk(other)->readlock); if (err) { err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS; - send_sigpipe = false; goto err; } if (sk->sk_shutdown & SEND_SHUTDOWN) { err = -EPIPE; + send_sigpipe = true; goto err_unlock; } @@ -1926,17 +1963,27 @@ alloc_skb: if (sock_flag(other, SOCK_DEAD) || other->sk_shutdown & RCV_SHUTDOWN) { err = -EPIPE; + send_sigpipe = true; goto err_state_unlock; } + if (init_scm) { + err = maybe_init_creds(&scm, socket, other); + if (err) + goto err_state_unlock; + init_scm = false; + } + skb = skb_peek_tail(&other->sk_receive_queue); if (tail && tail == skb) { skb = newskb; - } else if (!skb) { - if (newskb) + } else if (!skb || !unix_skb_scm_eq(skb, &scm)) { + if (newskb) { skb = newskb; - else + } else { + tail = skb; goto alloc_skb; + } } else if (newskb) { /* this is fast path, we don't necessarily need to * call to kfree_skb even though with newskb == NULL @@ -1957,6 +2004,9 @@ alloc_skb: atomic_add(size, &sk->sk_wmem_alloc); if (newskb) { + err = unix_scm_to_skb(&scm, skb, false); + if (err) + goto err_state_unlock; spin_lock(&other->sk_receive_queue.lock); __skb_queue_tail(&other->sk_receive_queue, newskb); spin_unlock(&other->sk_receive_queue.lock); @@ -1966,7 +2016,7 @@ alloc_skb: mutex_unlock(&unix_sk(other)->readlock); other->sk_data_ready(other); - + scm_destroy(&scm); return size; err_state_unlock: @@ -1977,6 +2027,8 @@ err: kfree_skb(newskb); if (send_sigpipe && !(flags & MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); + if (!init_scm) + scm_destroy(&scm); return err; } @@ -2280,10 +2332,7 @@ unlock: if (check_creds) { /* Never glue messages from different writers */ - if ((UNIXCB(skb).pid != scm.pid) || - !uid_eq(UNIXCB(skb).uid, scm.creds.uid) || - !gid_eq(UNIXCB(skb).gid, scm.creds.gid) || - !unix_secdata_eq(&scm, skb)) + if (!unix_skb_scm_eq(skb, &scm)) break; } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { /* Copy credentials */ -- cgit v0.10.2 From fea0f6650979a4fddd3f3fe255563ed15a2fc318 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Nov 2015 11:59:45 +0000 Subject: net: fsl: Don't use NO_IRQ to check return value of irq_of_parse_and_map() This driver can be built on arm64 but relies on NO_IRQ to check the return value of irq_of_parse_and_map() which fails to build on arm64 because the architecture does not provide a NO_IRQ. Fix this to correctly check the return value of irq_of_parse_and_map(). Even on ARM systems where the driver was previously used the check was broken since on ARM NO_IRQ is -1 but irq_of_parse_and_map() returns 0 on error. Signed-off-by: Mark Brown Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3e6b9b4..7cf8984 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -647,9 +647,9 @@ static int gfar_parse_group(struct device_node *np, if (model && strcasecmp(model, "FEC")) { gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1); gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2); - if (gfar_irq(grp, TX)->irq == NO_IRQ || - gfar_irq(grp, RX)->irq == NO_IRQ || - gfar_irq(grp, ER)->irq == NO_IRQ) + if (!gfar_irq(grp, TX)->irq || + !gfar_irq(grp, RX)->irq || + !gfar_irq(grp, ER)->irq) return -EINVAL; } -- cgit v0.10.2 From 0f2c0d32e6536ad39c3e9589d42c53d0ee3bfa08 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Nov 2015 11:59:46 +0000 Subject: net: fsl: Fix error checking for platform_get_irq() The gianfar driver has recently been enabled on arm64 but fails to build since it check the return value of platform_get_irq() against NO_IRQ. Fix this by instead checking for a negative error code. Even on ARM where this code was previously being built this check was incorrect since platform_get_irq() returns a negative error code which may not be exactly the (unsigned int)(-1) that NO_IRQ is defined to be. Signed-off-by: Mark Brown Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 664d0c2..b40fba9 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -467,7 +467,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) etsects->irq = platform_get_irq(dev, 0); - if (etsects->irq == NO_IRQ) { + if (etsects->irq < 0) { pr_err("irq not in device tree\n"); goto no_node; } -- cgit v0.10.2 From 142a2e7ece8d8ac0e818eb2c91f99ca894730e2a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 26 Nov 2015 08:18:14 -0800 Subject: tcp: initialize tp->copied_seq in case of cross SYN connection Dmitry provided a syzkaller (http://github.com/google/syzkaller) generated program that triggers the WARNING at net/ipv4/tcp.c:1729 in tcp_recvmsg() : WARN_ON(tp->copied_seq != tp->rcv_nxt && !(flags & (MSG_PEEK | MSG_TRUNC))); His program is specifically attempting a Cross SYN TCP exchange, that we support (for the pleasure of hackers ?), but it looks we lack proper tcp->copied_seq initialization. Thanks again Dmitry for your report and testings. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Tested-by: Dmitry Vyukov Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a4a0b6b..2d656ee 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5683,6 +5683,7 @@ discard: } tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; + tp->copied_seq = tp->rcv_nxt; tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; /* RFC1323: The window in SYN & SYN/ACK segments is -- cgit v0.10.2 From 741e96e8790cbd389d27e29bbf66de2c691fd775 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 3 Nov 2015 19:46:23 -0500 Subject: imx/clk-pllv1: fix wrong do_div() usage do_div() is meant to be used with an unsigned dividend. Signed-off-by: Nicolas Pitre Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c index 8564e43..82fe366 100644 --- a/drivers/clk/imx/clk-pllv1.c +++ b/drivers/clk/imx/clk-pllv1.c @@ -52,7 +52,7 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pllv1 *pll = to_clk_pllv1(hw); - long long ll; + unsigned long long ull; int mfn_abs; unsigned int mfi, mfn, mfd, pd; u32 reg; @@ -94,16 +94,16 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, rate = parent_rate * 2; rate /= pd + 1; - ll = (unsigned long long)rate * mfn_abs; + ull = (unsigned long long)rate * mfn_abs; - do_div(ll, mfd + 1); + do_div(ull, mfd + 1); if (mfn_is_negative(pll, mfn)) - ll = -ll; + ull = (rate * mfi) - ull; + else + ull = (rate * mfi) + ull; - ll = (rate * mfi) + ll; - - return ll; + return ull; } static struct clk_ops clk_pllv1_ops = { -- cgit v0.10.2 From 0d2681e1f19162e5975b70edd0c2d1d256f38023 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 3 Nov 2015 20:01:40 -0500 Subject: imx/clk-pllv2: fix wrong do_div() usage do_div() is meant to be used with an unsigned dividend. Signed-off-by: Nicolas Pitre Acked-by: Shawn Guo Signed-off-by: Stephen Boyd diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c index b18f875..4aeda56 100644 --- a/drivers/clk/imx/clk-pllv2.c +++ b/drivers/clk/imx/clk-pllv2.c @@ -79,7 +79,7 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate, { long mfi, mfn, mfd, pdf, ref_clk; unsigned long dbl; - s64 temp; + u64 temp; dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; @@ -98,8 +98,9 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate, temp = (u64) ref_clk * abs(mfn); do_div(temp, mfd + 1); if (mfn < 0) - temp = -temp; - temp = (ref_clk * mfi) + temp; + temp = (ref_clk * mfi) - temp; + else + temp = (ref_clk * mfi) + temp; return temp; } @@ -126,7 +127,7 @@ static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate, { u32 reg; long mfi, pdf, mfn, mfd = 999999; - s64 temp64; + u64 temp64; unsigned long quad_parent_rate; quad_parent_rate = 4 * parent_rate; -- cgit v0.10.2 From 279104e3ade92b38198fdaead9e84bd80057693a Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 23 Nov 2015 15:36:50 +0530 Subject: clk: qoriq: fix memory leak If get_pll_div() fails we exited by returning NULL but we missed releasing hwc. Signed-off-by: Sudip Mukherjee Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 1ab0fb8..7bc1c45 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -778,8 +778,10 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) */ clksel = (cg_in(cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT; div = get_pll_div(cg, hwc, clksel); - if (!div) + if (!div) { + kfree(hwc); return NULL; + } pct80_rate = clk_get_rate(div->clk); pct80_rate *= 8; -- cgit v0.10.2 From 5e4789d357a575f9777dec317cc0efc7b7458714 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 30 Nov 2015 15:02:44 +0000 Subject: drm: imx: imx-tve: Fix module autoload for OF platform driver This platform driver has 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: Philipp Zabel diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index e671ad3..f959714 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = { { .compatible = "fsl,imx53-tve", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, imx_tve_dt_ids); static struct platform_driver imx_tve_driver = { .probe = imx_tve_probe, -- cgit v0.10.2 From 62e345ae5b6ed977b02c24d1eaeaece062f9fb17 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 Nov 2015 15:24:29 -0600 Subject: usb: dwc3: gadget: don't prestart interrupt endpoints Because interrupt endpoints usually transmit such small amounts of data, it seems pointless to prestart transfers and try to get speed improvements. This patch also sorts out a problem with CDC ECM function where its notification endpoint gets stuck in busy state and we continuously issue Update Transfer commands. Fixes: 8a1a9c9e4503 ("usb: dwc3: gadget: start transfer on XFER_COMPLETE") Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e24a01c..a58376f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1078,6 +1078,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * little bit faster. */ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && + !usb_endpoint_xfer_int(dep->endpoint.desc) && !(dep->flags & DWC3_EP_BUSY)) { ret = __dwc3_gadget_kick_transfer(dep, 0, true); goto out; -- cgit v0.10.2 From 1170419496ae333fff1c2e8ca7dccf9a412e97c1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 30 Nov 2015 22:32:15 +0100 Subject: ACPI: Better describe ACPI_DEBUGGER Hi, For a brief moment I was tricked into thinking that: In-kernel debugger (EXPERIMENTAL) (ACPI_DEBUGGER) [N/y/?] (NEW) might be something useful. Better describe the feature to reduce such confusion. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 706c2e9..5e6e0a8 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -58,10 +58,10 @@ config ACPI_CCA_REQUIRED bool config ACPI_DEBUGGER - bool "In-kernel debugger (EXPERIMENTAL)" + bool "AML debugger interface (EXPERIMENTAL)" select ACPI_DEBUG help - Enable in-kernel debugging facilities: statistics, internal + Enable in-kernel debugging of AML facilities: statistics, internal object dump, single step control method execution. This is still under development, currently enabling this only results in the compilation of the ACPICA debugger files. -- cgit v0.10.2 From 826c416f3c9493b69630a811832cfb7c9007f840 Mon Sep 17 00:00:00 2001 From: Linda Knippers Date: Fri, 20 Nov 2015 19:05:47 -0500 Subject: nfit: Account for table size length variation The size of NFIT tables don't necessarily match the size of the data structures that we use for them. For example, the NVDIMM Control Region Structure table is shorter for a device with no block control windows than for a device with block control windows. Other tables, such as Flush Hint Address Structure and the Interleave Structure are variable length by definition. Account for the size difference when comparing table entries by using the actual table size from the table header if it's less than the structure size. Signed-off-by: Linda Knippers Acked-by: Vishal Verma Signed-off-by: Dan Williams diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index f7dab53..4d5ab28 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_system_address *spa) { + size_t length = min_t(size_t, sizeof(*spa), spa->header.length); struct device *dev = acpi_desc->dev; struct nfit_spa *nfit_spa; list_for_each_entry(nfit_spa, &prev->spas, list) { - if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) { + if (memcmp(nfit_spa->spa, spa, length) == 0) { list_move_tail(&nfit_spa->list, &acpi_desc->spas); return true; } @@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_memory_map *memdev) { + size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length); struct device *dev = acpi_desc->dev; struct nfit_memdev *nfit_memdev; list_for_each_entry(nfit_memdev, &prev->memdevs, list) - if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) { + if (memcmp(nfit_memdev->memdev, memdev, length) == 0) { list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs); return true; } @@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_control_region *dcr) { + size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length); struct device *dev = acpi_desc->dev; struct nfit_dcr *nfit_dcr; list_for_each_entry(nfit_dcr, &prev->dcrs, list) - if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) { + if (memcmp(nfit_dcr->dcr, dcr, length) == 0) { list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs); return true; } @@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_data_region *bdw) { + size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length); struct device *dev = acpi_desc->dev; struct nfit_bdw *nfit_bdw; list_for_each_entry(nfit_bdw, &prev->bdws, list) - if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) { + if (memcmp(nfit_bdw->bdw, bdw, length) == 0) { list_move_tail(&nfit_bdw->list, &acpi_desc->bdws); return true; } @@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_interleave *idt) { + size_t length = min_t(size_t, sizeof(*idt), idt->header.length); struct device *dev = acpi_desc->dev; struct nfit_idt *nfit_idt; list_for_each_entry(nfit_idt, &prev->idts, list) - if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) { + if (memcmp(nfit_idt->idt, idt, length) == 0) { list_move_tail(&nfit_idt->list, &acpi_desc->idts); return true; } @@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, struct acpi_nfit_flush_address *flush) { + size_t length = min_t(size_t, sizeof(*flush), flush->header.length); struct device *dev = acpi_desc->dev; struct nfit_flush *nfit_flush; list_for_each_entry(nfit_flush, &prev->flushes, list) - if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) { + if (memcmp(nfit_flush->flush, flush, length) == 0) { list_move_tail(&nfit_flush->list, &acpi_desc->flushes); return true; } -- cgit v0.10.2 From fc82792851d693e4f6da81b4b97e7af62d596af9 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 26 Nov 2015 17:22:23 +0200 Subject: ARM: OMAP2+: enable REGULATOR_FIXED_VOLTAGE Enable REGULATOR_FIXED_VOLTAGE for all OMAP2+ platforms otherwise system can't boot from SD-card when kernel is built for single SoC (for example, with CONFIG_SOC_DRA7XX=y only). It's also required for almost all TI SoC's platforms. Signed-off-by: Grygorii Strashko Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 5076d3f..4b4371d 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -121,6 +121,7 @@ config ARCH_OMAP2PLUS_TYPICAL select NEON if CPU_V7 select PM select REGULATOR + select REGULATOR_FIXED_VOLTAGE select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4 select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4 select VFP @@ -201,7 +202,6 @@ config MACH_OMAP3_PANDORA depends on ARCH_OMAP3 default y select OMAP_PACKAGE_CBB - select REGULATOR_FIXED_VOLTAGE if REGULATOR config MACH_NOKIA_N810 bool -- cgit v0.10.2 From ff5a55f89c6690a0b292f1a7e0cd4532961588d5 Mon Sep 17 00:00:00 2001 From: Linda Knippers Date: Fri, 20 Nov 2015 19:05:48 -0500 Subject: nfit: Fix the check for a successful NFIT merge Missed previously due to a lack of test coverage on a platform that provided an valid response to _FIT. Signed-off-by: Linda Knippers Acked-by: Vishal Verma Signed-off-by: Dan Williams diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 4d5ab28..f92adb5 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1816,7 +1816,7 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) nfit_saved = acpi_desc->nfit; acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; ret = acpi_nfit_init(acpi_desc, buf.length); - if (!ret) { + if (ret) { /* Merge failed, restore old nfit, and exit */ acpi_desc->nfit = nfit_saved; dev_err(dev, "failed to merge updated NFIT\n"); -- cgit v0.10.2 From 6b577c9d772c45448aec784ec235cea228b4d3ad Mon Sep 17 00:00:00 2001 From: Linda Knippers Date: Fri, 20 Nov 2015 19:05:49 -0500 Subject: nfit: Adjust for different _FIT and NFIT headers When support for _FIT was added, the code presumed that the data returned by the _FIT method is identical to the NFIT table, which starts with an acpi_table_header. However, the _FIT is defined to return a data in the format of a series of NFIT type structure entries and as a method, has an acpi_object header rather tahn an acpi_table_header. To address the differences, explicitly save the acpi_table_header from the NFIT, since it is accessible through /sys, and change the nfit pointer in the acpi_desc structure to point to the table entries rather than the headers. Reported-by: Jeff Moyer (jmoyer@redhat.com> Signed-off-by: Linda Knippers Acked-by: Vishal Verma [vishal: fix up unit test for new header assumptions] Signed-off-by: Dan Williams diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index f92adb5..e7ed39b 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -661,7 +661,7 @@ static ssize_t revision_show(struct device *dev, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision); + return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision); } static DEVICE_ATTR_RO(revision); @@ -1658,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) data = (u8 *) acpi_desc->nfit; end = data + sz; - data += sizeof(struct acpi_table_nfit); while (!IS_ERR_OR_NULL(data)) data = add_table(acpi_desc, &prev, data, end); @@ -1754,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev) return PTR_ERR(acpi_desc); } - acpi_desc->nfit = (struct acpi_table_nfit *) tbl; + /* + * Save the acpi header for later and then skip it, + * making nfit point to the first nfit table header. + */ + acpi_desc->acpi_header = *tbl; + acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit); + sz -= sizeof(struct acpi_table_nfit); /* Evaluate _FIT and override with that if present */ status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); if (ACPI_SUCCESS(status) && buf.length > 0) { - acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; - sz = buf.length; + union acpi_object *obj; + /* + * Adjust for the acpi_object header of the _FIT + */ + obj = buf.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + acpi_desc->nfit = + (struct acpi_nfit_header *)obj->buffer.pointer; + sz = obj->buffer.length; + } else + dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n", + __func__, (int) obj->type); } rc = acpi_nfit_init(acpi_desc, sz); @@ -1783,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) { struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev); struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_table_nfit *nfit_saved; + struct acpi_nfit_header *nfit_saved; + union acpi_object *obj; struct device *dev = &adev->dev; acpi_status status; int ret; @@ -1814,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) } nfit_saved = acpi_desc->nfit; - acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; - ret = acpi_nfit_init(acpi_desc, buf.length); - if (ret) { - /* Merge failed, restore old nfit, and exit */ - acpi_desc->nfit = nfit_saved; - dev_err(dev, "failed to merge updated NFIT\n"); + obj = buf.pointer; + if (obj->type == ACPI_TYPE_BUFFER) { + acpi_desc->nfit = + (struct acpi_nfit_header *)obj->buffer.pointer; + ret = acpi_nfit_init(acpi_desc, obj->buffer.length); + if (ret) { + /* Merge failed, restore old nfit, and exit */ + acpi_desc->nfit = nfit_saved; + dev_err(dev, "failed to merge updated NFIT\n"); + } + } else { + /* Bad _FIT, restore old nfit */ + dev_err(dev, "Invalid _FIT\n"); } kfree(buf.pointer); diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 2ea5c07..3d549a3 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -96,7 +96,8 @@ struct nfit_mem { struct acpi_nfit_desc { struct nvdimm_bus_descriptor nd_desc; - struct acpi_table_nfit *nfit; + struct acpi_table_header acpi_header; + struct acpi_nfit_header *nfit; struct mutex spa_map_mutex; struct mutex init_mutex; struct list_head spa_maps; diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 40ab447..51cf825 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -420,8 +420,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) static int nfit_test0_alloc(struct nfit_test *t) { - size_t nfit_size = sizeof(struct acpi_table_nfit) - + sizeof(struct acpi_nfit_system_address) * NUM_SPA + size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA + sizeof(struct acpi_nfit_memory_map) * NUM_MEM + sizeof(struct acpi_nfit_control_region) * NUM_DCR + sizeof(struct acpi_nfit_data_region) * NUM_BDW @@ -471,8 +470,7 @@ static int nfit_test0_alloc(struct nfit_test *t) static int nfit_test1_alloc(struct nfit_test *t) { - size_t nfit_size = sizeof(struct acpi_table_nfit) - + sizeof(struct acpi_nfit_system_address) + size_t nfit_size = sizeof(struct acpi_nfit_system_address) + sizeof(struct acpi_nfit_memory_map) + sizeof(struct acpi_nfit_control_region); @@ -488,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t) return 0; } -static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size) -{ - memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4); - nfit->header.length = size; - nfit->header.revision = 1; - memcpy(nfit->header.oem_id, "LIBND", 6); - memcpy(nfit->header.oem_table_id, "TEST", 5); - nfit->header.oem_revision = 1; - memcpy(nfit->header.asl_compiler_id, "TST", 4); - nfit->header.asl_compiler_revision = 1; -} - static void nfit_test0_setup(struct nfit_test *t) { struct nvdimm_bus_descriptor *nd_desc; struct acpi_nfit_desc *acpi_desc; struct acpi_nfit_memory_map *memdev; void *nfit_buf = t->nfit_buf; - size_t size = t->nfit_size; struct acpi_nfit_system_address *spa; struct acpi_nfit_control_region *dcr; struct acpi_nfit_data_region *bdw; struct acpi_nfit_flush_address *flush; unsigned int offset; - nfit_test_init_header(nfit_buf, size); - /* * spa0 (interleave first half of dimm0 and dimm1, note storage * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + sizeof(struct acpi_table_nfit); + spa = nfit_buf; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); @@ -533,7 +516,7 @@ static void nfit_test0_setup(struct nfit_test *t) * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa); + spa = nfit_buf + sizeof(*spa); spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); @@ -542,7 +525,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = SPA1_SIZE; /* spa2 (dcr0) dimm0 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2; + spa = nfit_buf + sizeof(*spa) * 2; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -551,7 +534,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa3 (dcr1) dimm1 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3; + spa = nfit_buf + sizeof(*spa) * 3; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -560,7 +543,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa4 (dcr2) dimm2 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4; + spa = nfit_buf + sizeof(*spa) * 4; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -569,7 +552,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa5 (dcr3) dimm3 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5; + spa = nfit_buf + sizeof(*spa) * 5; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); @@ -578,7 +561,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DCR_SIZE; /* spa6 (bdw for dcr0) dimm0 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6; + spa = nfit_buf + sizeof(*spa) * 6; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -587,7 +570,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa7 (bdw for dcr1) dimm1 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7; + spa = nfit_buf + sizeof(*spa) * 7; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -596,7 +579,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa8 (bdw for dcr2) dimm2 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8; + spa = nfit_buf + sizeof(*spa) * 8; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -605,7 +588,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->length = DIMM_SIZE; /* spa9 (bdw for dcr3) dimm3 */ - spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9; + spa = nfit_buf + sizeof(*spa) * 9; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); @@ -613,7 +596,7 @@ static void nfit_test0_setup(struct nfit_test *t) spa->address = t->dimm_dma[3]; spa->length = DIMM_SIZE; - offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10; + offset = sizeof(*spa) * 10; /* mem-region0 (spa0, dimm0) */ memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; @@ -1100,15 +1083,13 @@ static void nfit_test0_setup(struct nfit_test *t) static void nfit_test1_setup(struct nfit_test *t) { - size_t size = t->nfit_size, offset; + size_t offset; void *nfit_buf = t->nfit_buf; struct acpi_nfit_memory_map *memdev; struct acpi_nfit_control_region *dcr; struct acpi_nfit_system_address *spa; - nfit_test_init_header(nfit_buf, size); - - offset = sizeof(struct acpi_table_nfit); + offset = 0; /* spa0 (flat range with no bdw aliasing) */ spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; -- cgit v0.10.2 From 9eb8cd2b0780bca0719e754e7bdcf5f368f001bd Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 18 Nov 2015 21:46:38 +1100 Subject: of: Fix comparison of reserved memory regions In order to check for overlapping reserved memory regions, we first need to sort the array of memory regions. This is implemented using sort(), and a custom comparison function __rmem_cmp(). Unfortunatley __rmem_cmp() doesn't work in all cases. Because the two base values are phys_addr_t, they may be u64 on some platforms, in which case subtracting one from the other and then (implicitly) casting to int does not give us the -ve/0/+ve value we need. This leads to incorrect reports about overlaps, eg: ibm,slw-image@1ffe600000 (0x0000001ffe600000--0x0000001ffe700000) overlaps with ibm,firmware-allocs-memory@1000000000 (0x0000001000000000--0x0000001000dc0200) Fix it by just doing the standard double if and return 0 logic. Fixes: ae1add247bf8 ("of: Check for overlap in reserved memory regions") Signed-off-by: Michael Ellerman Signed-off-by: Rob Herring diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index be77e75..1a3556a 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -206,7 +206,13 @@ static int __init __rmem_cmp(const void *a, const void *b) { const struct reserved_mem *ra = a, *rb = b; - return ra->base - rb->base; + if (ra->base < rb->base) + return -1; + + if (ra->base > rb->base) + return 1; + + return 0; } static void __init __rmem_check_for_overlap(void) -- cgit v0.10.2 From 78bb2abe09d6bd15eeee7250f2fa0cb76432a8a2 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Krivenok" Date: Mon, 30 Nov 2015 23:45:48 +0300 Subject: of: do not use 0x in front of %pa Signed-off-by: Dmitry V. Krivenok Signed-off-by: Rob Herring diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index d243029..1bbe3a9 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1041,7 +1041,7 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size, bool nomap) { - pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n", + pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n", &base, &size, nomap ? " (nomap)" : ""); return -ENOSYS; } -- cgit v0.10.2 From ba85edbe0d39710dc74a2a9c6f90929b5722a53b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 30 Nov 2015 15:22:37 +0900 Subject: of/address: fix typo in comment block of of_translate_one() Remove the "not" before "cannot". I am fixing the comment block style while I am here. Signed-off-by: Masahiro Yamada Signed-off-by: Rob Herring diff --git a/drivers/of/address.c b/drivers/of/address.c index cd53fe4..9582c57 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -485,9 +485,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, int rone; u64 offset = OF_BAD_ADDR; - /* Normally, an absence of a "ranges" property means we are + /* + * Normally, an absence of a "ranges" property means we are * crossing a non-translatable boundary, and thus the addresses - * below the current not cannot be converted to CPU physical ones. + * below the current cannot be converted to CPU physical ones. * Unfortunately, while this is very clear in the spec, it's not * what Apple understood, and they do have things like /uni-n or * /ht nodes with no "ranges" property and a lot of perfectly -- cgit v0.10.2 From e80cf2e50bfabb14dd3667b2360a393dda3edc3f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 21 Oct 2015 22:41:40 +0200 Subject: clk: scpi: add missing of_node_put for_each_available_child_of_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put. The semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // @@ expression root,e; local idexpression child; @@ for_each_available_child_of_node(root, child) { ... when != of_node_put(child) when != e = child ( return child; | + of_node_put(child); ? return ...; ) ... } // Signed-off-by: Julia Lawall Acked-by: Sudeep Holla Signed-off-by: Stephen Boyd diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 0b501a9..cd0f272 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -292,6 +292,7 @@ static int scpi_clocks_probe(struct platform_device *pdev) ret = scpi_clk_add(dev, child, match); if (ret) { scpi_clocks_remove(pdev); + of_node_put(child); return ret; } } -- cgit v0.10.2 From d6d38d9d795edc0f31c6c2d4e6743e66564d6c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 13 Nov 2015 14:00:40 +0100 Subject: virtio-gpu: use no-merge for fill-modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid the sticky preferred mode bit by using the no-merge version of the function (this allows gnome-shell to resize to lower resolutions than the default resolution) Signed-off-by: Marc-André Lureau Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index f545913..578fe0a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -412,7 +412,7 @@ static const struct drm_connector_funcs virtio_gpu_connector_funcs = { .save = virtio_gpu_conn_save, .restore = virtio_gpu_conn_restore, .detect = virtio_gpu_conn_detect, - .fill_modes = drm_helper_probe_single_connector_modes, + .fill_modes = drm_helper_probe_single_connector_modes_nomerge, .destroy = virtio_gpu_conn_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -- cgit v0.10.2 From b49493f99690c8eaacfbc635bafaad629ea2c036 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 18 Nov 2015 14:56:36 -0800 Subject: Fix a memory leak in scsi_host_dev_release() Avoid that kmemleak reports the following memory leak if a SCSI LLD calls scsi_host_alloc() and scsi_host_put() but neither scsi_host_add() nor scsi_host_remove(). The following shell command triggers that scenario: for ((i=0; i<2; i++)); do srp_daemon -oac | while read line; do echo $line >/sys/class/infiniband_srp/srp-mlx4_0-1/add_target done done unreferenced object 0xffff88021b24a220 (size 8): comm "srp_daemon", pid 56421, jiffies 4295006762 (age 4240.750s) hex dump (first 8 bytes): 68 6f 73 74 35 38 00 a5 host58.. backtrace: [] kmemleak_alloc+0x7a/0xc0 [] __kmalloc_track_caller+0xfe/0x160 [] kvasprintf+0x5b/0x90 [] kvasprintf_const+0x8d/0xb0 [] kobject_set_name_vargs+0x3c/0xa0 [] dev_set_name+0x3c/0x40 [] scsi_host_alloc+0x327/0x4b0 [] srp_create_target+0x4e/0x8a0 [ib_srp] [] dev_attr_store+0x1b/0x20 [] sysfs_kf_write+0x4a/0x60 [] kernfs_fop_write+0x14e/0x180 [] __vfs_write+0x2f/0xf0 [] vfs_write+0xa4/0x100 [] SyS_write+0x54/0xc0 [] entry_SYSCALL_64_fastpath+0x12/0x6f Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Sagi Grimberg Reviewed-by: Lee Duncan Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: stable Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8bb173e..7d647a3 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -326,6 +326,17 @@ static void scsi_host_dev_release(struct device *dev) kfree(queuedata); } + if (shost->shost_state == SHOST_CREATED) { + /* + * Free the shost_dev device name here if scsi_host_alloc() + * and scsi_host_put() have been called but neither + * scsi_host_add() nor scsi_host_remove() has been called. + * This avoids that the memory allocated for the shost_dev + * name is leaked. + */ + kfree(dev_name(&shost->shost_dev)); + } + scsi_destroy_command_freelist(shost); if (shost_use_blk_mq(shost)) { if (shost->tag_set.tags) -- cgit v0.10.2 From b840c3627b6f4f856b333a14a72f8ed86da2f86c Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 30 Nov 2015 20:36:08 -0500 Subject: mpt3sas: Add dummy Kconfig option for backwards compatibility The mpt2sas driver was recently folded into mpt3sas to reduce code duplication. To avoid problems for people that only have CONFIG_SCSI_MPT2SAS in their .config we introduce a dummy option that will select MPT3SAS if MPT2SAS was previously enabled. This is a temporary measure and we will deprecate this config option in 4.6. Reported-by: Peter Zijlstra Acked-by: Christoph Hellwig Acked-by: James Bottomley CC: Ingo Molnar Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig index 2906146..25dc38f 100644 --- a/drivers/scsi/mpt3sas/Kconfig +++ b/drivers/scsi/mpt3sas/Kconfig @@ -71,3 +71,11 @@ config SCSI_MPT3SAS_MAX_SGE MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this can be 256. However, it may decreased down to 16. Decreasing this parameter will reduce memory requirements on a per controller instance. + +config SCSI_MPT2SAS + tristate "Legacy MPT2SAS config option" + default n + select SCSI_MPT3SAS + ---help--- + Dummy config option for backwards compatiblity: configure the MPT3SAS + driver instead. -- cgit v0.10.2 From 3b7e2a7d9d6220dad2950d8166f9495ef4c69b2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2015 17:34:12 +0100 Subject: ALSA: hda - Correct codec names for 14f1:50f1 and 14f1:50f3 The numbers aren't always linear, just like in the real world. Correct to the right numbers stated in the datasheet (although we can't trust the datasheet as well). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c8b8ef5..89d9e8c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -972,9 +972,9 @@ static const struct hda_device_id snd_hda_id_conexant[] = { HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f1, "CX20721", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto), - HDA_CODEC_ENTRY(0x14f150f3, "CX20723", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto), -- cgit v0.10.2 From bcdda2ec28c31fe62d5d85c8b603f202a2c85fac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2015 17:36:02 +0100 Subject: ALSA: hda - Add Conexant CX8200 (14f1:2008) codec entry It's supposed to be equivalent with CX20724. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 89d9e8c..ef19890 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -955,6 +955,7 @@ static int patch_conexant_auto(struct hda_codec *codec) */ static const struct hda_device_id snd_hda_id_conexant[] = { + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto), -- cgit v0.10.2 From bb6d19846d1cee7cc977ce3aa736ec60d7163d3a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Nov 2015 13:31:42 +0000 Subject: drm/i915: Check the timeout passed to i915_wait_request We have relied upon the sole caller (wait_ioctl) validating the timeout argument. However, when waiting for multiple requests I forgot to ensure that the timeout was still positive on the later requests. This is more simply done inside __i915_wait_request. Fixes regression introduced in commit b47161858ba13c9c7e03333132230d66e008dd55 Author: Chris Wilson Date: Mon Apr 27 13:41:17 2015 +0100 drm/i915: Implement inter-engine read-read optimisations The impact of the regression is 1 jiffie for each extra active ring for a wait_ioctl with a timeout -- I don't think anyone has noticed. Signed-off-by: Chris Wilson Cc: Lionel Landwerlin Cc: Tvrtko Ursulin Cc: Daniel Vetter Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1448544702-5594-1-git-send-email-chris@chris-wilson.co.uk Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 91bb1fc..32e6aad 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1210,8 +1210,16 @@ int __i915_wait_request(struct drm_i915_gem_request *req, if (i915_gem_request_completed(req, true)) return 0; - timeout_expire = timeout ? - jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0; + timeout_expire = 0; + if (timeout) { + if (WARN_ON(*timeout < 0)) + return -EINVAL; + + if (*timeout == 0) + return -ETIME; + + timeout_expire = jiffies + nsecs_to_jiffies_timeout(*timeout); + } if (INTEL_INFO(dev_priv)->gen >= 6) gen6_rps_boost(dev_priv, rps, req->emitted_jiffies); -- cgit v0.10.2 From 48111b79b77f9fb1f139e1878b3cfcd56b46b789 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Nov 2015 13:52:13 +0100 Subject: pinctrl: sh-pfc: sh7734: Add missing cfg macro parameter to fix build When building for SH7734: drivers/pinctrl/sh-pfc/pfc-sh7734.c:586:1: error: macro "_GP_DATA" passed 5 arguments, but takes just 4 drivers/pinctrl/sh-pfc/pfc-sh7734.c:586:2: error: '_GP_DATA' undeclared here (not in a function) drivers/pinctrl/sh-pfc/pfc-sh7734.c:586:1: error: macro "_GP_DATA" passed 5 arguments, but takes just 4 drivers/pinctrl/sh-pfc/pfc-sh7734.c:586:1: error: macro "_GP_DATA" passed 5 arguments, but takes just 4 ... drivers/pinctrl/sh-pfc/pfc-sh7734.c:2389:1: error: macro "_GP_INOUTSEL" passed 5 arguments, but takes just 4 drivers/pinctrl/sh-pfc/pfc-sh7734.c:2389:53: error: '_GP_INOUTSEL' undeclared here (not in a function) drivers/pinctrl/sh-pfc/pfc-sh7734.c:2389:2: warning: initialization makes integer from pointer without a cast [enabled by default] drivers/pinctrl/sh-pfc/pfc-sh7734.c:2389:2: warning: (near initialization for '(anonymous)[0]') [enabled by default] ... drivers/pinctrl/sh-pfc/pfc-sh7734.c:2416:1: error: macro "_GP_INDT" passed 5 arguments, but takes just 4 drivers/pinctrl/sh-pfc/pfc-sh7734.c:2416:47: error: '_GP_INDT' undeclared here (not in a function) drivers/pinctrl/sh-pfc/pfc-sh7734.c:2416:2: warning: initialization makes integer from pointer without a cast [enabled by default] drivers/pinctrl/sh-pfc/pfc-sh7734.c:2416:2: warning: (near initialization for '(anonymous)[0]') [enabled by default] ... Add the missing "cfg" macro parameters to the sh7734-specific _GP_DATA(), _GP_INOUTSEL(), and _GP_INDT() macros to fix this. Fixes: 22768fc60abbf58b ("pinctrl: sh-pfc: Add macros defining GP ports with config flags") Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index e7deb51..9842bb1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -31,11 +31,11 @@ PORT_GP_12(5, fn, sfx) #undef _GP_DATA -#define _GP_DATA(bank, pin, name, sfx) \ +#define _GP_DATA(bank, pin, name, sfx, cfg) \ PINMUX_DATA(name##_DATA, name##_FN, name##_IN, name##_OUT) -#define _GP_INOUTSEL(bank, pin, name, sfx) name##_IN, name##_OUT -#define _GP_INDT(bank, pin, name, sfx) name##_DATA +#define _GP_INOUTSEL(bank, pin, name, sfx, cfg) name##_IN, name##_OUT +#define _GP_INDT(bank, pin, name, sfx, cfg) name##_DATA #define GP_INOUTSEL(bank) PORT_GP_32_REV(bank, _GP_INOUTSEL, unused) #define GP_INDT(bank) PORT_GP_32_REV(bank, _GP_INDT, unused) -- cgit v0.10.2 From d7b53fd9e37a4127077720f4fef10330e284107c Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Fri, 6 Nov 2015 13:22:24 +0100 Subject: drm/rockchip: vop: Correct enabled clocks during setup When doing the initial setup both the hclk and the aclk need to be enabled otherwise the board will simply hang. This only occurs when building the vop driver as a module, when its built-in the initial setup happens to run before the clock framework shuts of unused clocks (including the aclk). While there also switch to doing prepare and enable in one step rather then separate steps to reduce the amount of code required. Signed-off-by: Sjoerd Simons Acked-by: Mark Yao Tested-by: Yakir Yang Tested-by: Romain Perier diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 5d8ae5e..48719df 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1575,32 +1575,25 @@ static int vop_initial(struct vop *vop) return PTR_ERR(vop->dclk); } - ret = clk_prepare(vop->hclk); - if (ret < 0) { - dev_err(vop->dev, "failed to prepare hclk\n"); - return ret; - } - ret = clk_prepare(vop->dclk); if (ret < 0) { dev_err(vop->dev, "failed to prepare dclk\n"); - goto err_unprepare_hclk; + return ret; } - ret = clk_prepare(vop->aclk); + /* Enable both the hclk and aclk to setup the vop */ + ret = clk_prepare_enable(vop->hclk); if (ret < 0) { - dev_err(vop->dev, "failed to prepare aclk\n"); + dev_err(vop->dev, "failed to prepare/enable hclk\n"); goto err_unprepare_dclk; } - /* - * enable hclk, so that we can config vop register. - */ - ret = clk_enable(vop->hclk); + ret = clk_prepare_enable(vop->aclk); if (ret < 0) { - dev_err(vop->dev, "failed to prepare aclk\n"); - goto err_unprepare_aclk; + dev_err(vop->dev, "failed to prepare/enable aclk\n"); + goto err_disable_hclk; } + /* * do hclk_reset, reset all vop registers. */ @@ -1608,7 +1601,7 @@ static int vop_initial(struct vop *vop) if (IS_ERR(ahb_rst)) { dev_err(vop->dev, "failed to get ahb reset\n"); ret = PTR_ERR(ahb_rst); - goto err_disable_hclk; + goto err_disable_aclk; } reset_control_assert(ahb_rst); usleep_range(10, 20); @@ -1634,26 +1627,25 @@ static int vop_initial(struct vop *vop) if (IS_ERR(vop->dclk_rst)) { dev_err(vop->dev, "failed to get dclk reset\n"); ret = PTR_ERR(vop->dclk_rst); - goto err_unprepare_aclk; + goto err_disable_aclk; } reset_control_assert(vop->dclk_rst); usleep_range(10, 20); reset_control_deassert(vop->dclk_rst); clk_disable(vop->hclk); + clk_disable(vop->aclk); vop->is_enabled = false; return 0; +err_disable_aclk: + clk_disable_unprepare(vop->aclk); err_disable_hclk: - clk_disable(vop->hclk); -err_unprepare_aclk: - clk_unprepare(vop->aclk); + clk_disable_unprepare(vop->hclk); err_unprepare_dclk: clk_unprepare(vop->dclk); -err_unprepare_hclk: - clk_unprepare(vop->hclk); return ret; } -- cgit v0.10.2 From 3c395a969acc690f331d5fb91ec99ea8eb5155dd Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 1 Dec 2015 11:48:17 +0100 Subject: null_blk: set a separate timer for each command For the Timer IRQ mode (i.e., when command completions are delayed), there is one timer for each CPU. Each of these timers . has a completion queue associated with it, containing all the command completions to be executed when the timer fires; . is set, and a new completion-to-execute is inserted into its completion queue, every time the dispatch code for a new command happens to be executed on the CPU related to the timer. This implies that, if the dispatch of a new command happens to be executed on a CPU whose timer has already been set, but has not yet fired, then the timer is set again, to the completion time of the newly arrived command. When the timer eventually fires, all its queued completions are executed. This way of handling delayed command completions entails the following problem: if more than one command completion is inserted into the queue of a timer before the timer fires, then the expiration time for the timer is moved forward every time each of these completions is enqueued. As a consequence, only the last completion enqueued enjoys a correct execution time, while all previous completions are unjustly delayed until the last completion is executed (and at that time they are executed all together). Specifically, if all the above completions are enqueued almost at the same time, then the problem is negligible. On the opposite end, if every completion is enqueued a while after the previous completion was enqueued (in the extreme case, it is enqueued only right before the timer would have expired), then every enqueued completion, except for the last one, experiences an inflated delay, proportional to the number of completions enqueued after it. In the end, commands, and thus I/O requests, may be completed at an arbitrarily lower rate than the desired one. This commit addresses this issue by replacing per-CPU timers with per-command timers, i.e., by associating an individual timer with each command. Signed-off-by: Paolo Valente Signed-off-by: Arianna Avanzini Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 5c8ba54..08932f5 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -18,6 +18,7 @@ struct nullb_cmd { struct bio *bio; unsigned int tag; struct nullb_queue *nq; + struct hrtimer timer; }; struct nullb_queue { @@ -49,17 +50,6 @@ static int null_major; static int nullb_indexes; static struct kmem_cache *ppa_cache; -struct completion_queue { - struct llist_head list; - struct hrtimer timer; -}; - -/* - * These are per-cpu for now, they will need to be configured by the - * complete_queues parameter and appropriately mapped. - */ -static DEFINE_PER_CPU(struct completion_queue, completion_queues); - enum { NULL_IRQ_NONE = 0, NULL_IRQ_SOFTIRQ = 1, @@ -180,6 +170,8 @@ static void free_cmd(struct nullb_cmd *cmd) put_tag(cmd->nq, cmd->tag); } +static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer); + static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) { struct nullb_cmd *cmd; @@ -190,6 +182,11 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) cmd = &nq->cmds[tag]; cmd->tag = tag; cmd->nq = nq; + if (irqmode == NULL_IRQ_TIMER) { + hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + cmd->timer.function = null_cmd_timer_expired; + } return cmd; } @@ -238,47 +235,28 @@ static void end_cmd(struct nullb_cmd *cmd) static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) { - struct completion_queue *cq; - struct llist_node *entry; - struct nullb_cmd *cmd; - - cq = &per_cpu(completion_queues, smp_processor_id()); - - while ((entry = llist_del_all(&cq->list)) != NULL) { - entry = llist_reverse_order(entry); - do { - struct request_queue *q = NULL; + struct nullb_cmd *cmd = container_of(timer, struct nullb_cmd, timer); + struct request_queue *q = NULL; - cmd = container_of(entry, struct nullb_cmd, ll_list); - entry = entry->next; - if (cmd->rq) - q = cmd->rq->q; - end_cmd(cmd); + if (cmd->rq) + q = cmd->rq->q; - if (q && !q->mq_ops && blk_queue_stopped(q)) { - spin_lock(q->queue_lock); - if (blk_queue_stopped(q)) - blk_start_queue(q); - spin_unlock(q->queue_lock); - } - } while (entry); + if (q && !q->mq_ops && blk_queue_stopped(q)) { + spin_lock(q->queue_lock); + if (blk_queue_stopped(q)) + blk_start_queue(q); + spin_unlock(q->queue_lock); } + end_cmd(cmd); return HRTIMER_NORESTART; } static void null_cmd_end_timer(struct nullb_cmd *cmd) { - struct completion_queue *cq = &per_cpu(completion_queues, get_cpu()); - - cmd->ll_list.next = NULL; - if (llist_add(&cmd->ll_list, &cq->list)) { - ktime_t kt = ktime_set(0, completion_nsec); + ktime_t kt = ktime_set(0, completion_nsec); - hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL_PINNED); - } - - put_cpu(); + hrtimer_start(&cmd->timer, kt, HRTIMER_MODE_REL); } static void null_softirq_done_fn(struct request *rq) @@ -376,6 +354,10 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx, { struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq); + if (irqmode == NULL_IRQ_TIMER) { + hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cmd->timer.function = null_cmd_timer_expired; + } cmd->rq = bd->rq; cmd->nq = hctx->driver_data; @@ -813,19 +795,6 @@ static int __init null_init(void) mutex_init(&lock); - /* Initialize a separate list for each CPU for issuing softirqs */ - for_each_possible_cpu(i) { - struct completion_queue *cq = &per_cpu(completion_queues, i); - - init_llist_head(&cq->list); - - if (irqmode != NULL_IRQ_TIMER) - continue; - - hrtimer_init(&cq->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - cq->timer.function = null_cmd_timer_expired; - } - null_major = register_blkdev(0, "nullb"); if (null_major < 0) return null_major; -- cgit v0.10.2 From cf8ecc5a8455266f8d516426b2acd36f9bdfa061 Mon Sep 17 00:00:00 2001 From: Arianna Avanzini Date: Tue, 1 Dec 2015 11:48:18 +0100 Subject: null_blk: guarantee device restart in all irq modes In single-queue (block layer) mode,the function null_rq_prep_fn stops the device if alloc_cmd fails. Then, once stopped, the device must be restarted on the next command completion, so that the request(s) for which alloc_cmd failed can be requeued. Otherwise the device hangs. Unfortunately, device restart is currently performed only for delayed completions, i.e., in irqmode==2. This fact causes hangs, for the above reasons, with the other irqmodes in combination with single-queue block layer. This commits addresses this issue by making sure that, if stopped, the device is properly restarted for all irqmodes on completions. Signed-off-by: Paolo Valente Signed-off-by: Arianna AVanzini Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 08932f5..cf65619 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -217,6 +217,8 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) static void end_cmd(struct nullb_cmd *cmd) { + struct request_queue *q = NULL; + switch (queue_mode) { case NULL_Q_MQ: blk_mq_end_request(cmd->rq, 0); @@ -227,27 +229,28 @@ static void end_cmd(struct nullb_cmd *cmd) break; case NULL_Q_BIO: bio_endio(cmd->bio); - break; + goto free_cmd; } - free_cmd(cmd); -} - -static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) -{ - struct nullb_cmd *cmd = container_of(timer, struct nullb_cmd, timer); - struct request_queue *q = NULL; - if (cmd->rq) q = cmd->rq->q; + /* Restart queue if needed, as we are freeing a tag */ if (q && !q->mq_ops && blk_queue_stopped(q)) { - spin_lock(q->queue_lock); + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); if (blk_queue_stopped(q)) blk_start_queue(q); - spin_unlock(q->queue_lock); + spin_unlock_irqrestore(q->queue_lock, flags); } - end_cmd(cmd); +free_cmd: + free_cmd(cmd); +} + +static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) +{ + end_cmd(container_of(timer, struct nullb_cmd, timer)); return HRTIMER_NORESTART; } -- cgit v0.10.2 From dbac117542b7e814245c43daa638a3626230cb2a Mon Sep 17 00:00:00 2001 From: Arianna Avanzini Date: Tue, 1 Dec 2015 11:48:19 +0100 Subject: null_blk: change type of completion_nsec to unsigned long This commit at least doubles the maximum value for completion_nsec. This helps in special cases where one wants/needs to emulate an extremely slow I/O (for example to spot bugs). Signed-off-by: Paolo Valente Signed-off-by: Arianna Avanzini Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index cf65619..0c3940e 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -132,8 +132,8 @@ static const struct kernel_param_ops null_irqmode_param_ops = { device_param_cb(irqmode, &null_irqmode_param_ops, &irqmode, S_IRUGO); MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer"); -static int completion_nsec = 10000; -module_param(completion_nsec, int, S_IRUGO); +static unsigned long completion_nsec = 10000; +module_param(completion_nsec, ulong, S_IRUGO); MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns"); static int hw_queue_depth = 64; -- cgit v0.10.2 From df36c5bede207f734e4750beb2b14fb892050280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Tue, 24 Nov 2015 16:02:04 +0100 Subject: USB: quirks: Fix another ELAN touchscreen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like other buggy models that had their fixes [1], the touchscreen with id 04f3:21b8 from ELAN Microelectronics needs the device-qualifier quirk. Otherwise, it fails to respond, blocks the boot for a random amount of time and pollutes dmesg with: [ 2887.373196] usb 1-5: new full-speed USB device number 41 using xhci_hcd [ 2889.502000] usb 1-5: unable to read config index 0 descriptor/start: -71 [ 2889.502005] usb 1-5: can't read configurations, error -71 [ 2889.654571] usb 1-5: new full-speed USB device number 42 using xhci_hcd [ 2891.783438] usb 1-5: unable to read config index 0 descriptor/start: -71 [ 2891.783443] usb 1-5: can't read configurations, error -71 [1]: See commits c68929f, 876af5d, d749947, a32c99e and dc703ec. Tested-by: Adrien Vergé Signed-off-by: Adrien Vergé Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f5a3819..fcd6ac0 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -125,6 +125,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04f3, 0x016f), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, + { USB_DEVICE(0x04f3, 0x21b8), .driver_info = + USB_QUIRK_DEVICE_QUALIFIER }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, -- cgit v0.10.2 From 9fa62b1a31c96715aef34f25000e882ed4ac4876 Mon Sep 17 00:00:00 2001 From: Dmitry Katsubo Date: Fri, 20 Nov 2015 01:30:44 +0100 Subject: usb-storage: Fix scsi-sd failure "Invalid field in cdb" for USB adapter JMicron The patch extends the family of SATA-to-USB JMicron adapters that need FUA to be disabled and applies the same policy for uas driver. See details in http://unix.stackexchange.com/questions/237204/ Signed-off-by: Dmitry Katsubo Tested-by: Dmitry Katsubo Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index e691516..5c66d3f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -796,6 +796,10 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; + /* A few buggy USB-ATA bridges don't understand FUA */ + if (devinfo->flags & US_FL_BROKEN_FUA) + sdev->broken_fua = 1; + scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 6b24791..7ffe420 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1987,7 +1987,7 @@ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, US_FL_IGNORE_RESIDUE ), /* Reported by Michael Büsch */ -UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0114, +UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0116, "JMicron", "USB to ATA/ATAPI Bridge", USB_SC_DEVICE, USB_PR_DEVICE, NULL, diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index c85ea53..ccc113e 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -132,7 +132,7 @@ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999, "JMicron", "JMS567", USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_REPORT_OPCODES), + US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES), /* Reported-by: Hans de Goede */ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, -- cgit v0.10.2 From 304d888b29cf96f1dd53511ee686499cd8cdf249 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 27 Nov 2015 18:17:05 +0100 Subject: Revert "ipv6: ndisc: inherit metadata dst when creating ndisc requests" This reverts commit ab450605b35caa768ca33e86db9403229bf42be4. In IPv6, we cannot inherit the dst of the original dst. ndisc packets are IPv6 packets and may take another route than the original packet. This patch breaks the following scenario: a packet comes from eth0 and is forwarded through vxlan1. The encapsulated packet triggers an NS which cannot be sent because of the wrong route. CC: Jiri Benc CC: Thomas Graf Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller diff --git a/include/net/ndisc.h b/include/net/ndisc.h index bf39374..2d8edaa 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -181,8 +181,7 @@ void ndisc_cleanup(void); int ndisc_rcv(struct sk_buff *skb); void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, - const struct in6_addr *daddr, const struct in6_addr *saddr, - struct sk_buff *oskb); + const struct in6_addr *daddr, const struct in6_addr *saddr); void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d84742f..61f2685 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3642,7 +3642,7 @@ static void addrconf_dad_work(struct work_struct *w) /* send a neighbour solicitation for our addr */ addrconf_addr_solict_mult(&ifp->addr, &mcaddr); - ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any, NULL); + ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any); out: in6_ifa_put(ifp); rtnl_unlock(); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3e0f855..d6161e1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -556,8 +556,7 @@ static void ndisc_send_unsol_na(struct net_device *dev) } void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, - const struct in6_addr *daddr, const struct in6_addr *saddr, - struct sk_buff *oskb) + const struct in6_addr *daddr, const struct in6_addr *saddr) { struct sk_buff *skb; struct in6_addr addr_buf; @@ -593,9 +592,6 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr); - if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE) && oskb) - skb_dst_copy(skb, oskb); - ndisc_send_skb(skb, daddr, saddr); } @@ -682,12 +678,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) "%s: trying to ucast probe in NUD_INVALID: %pI6\n", __func__, target); } - ndisc_send_ns(dev, target, target, saddr, skb); + ndisc_send_ns(dev, target, target, saddr); } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { neigh_app_ns(neigh); } else { addrconf_addr_solict_mult(target, &mcaddr); - ndisc_send_ns(dev, target, &mcaddr, saddr, skb); + ndisc_send_ns(dev, target, &mcaddr, saddr); } } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6f01fe1..826e6aa 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -523,7 +523,7 @@ static void rt6_probe_deferred(struct work_struct *w) container_of(w, struct __rt6_probe_work, work); addrconf_addr_solict_mult(&work->target, &mcaddr); - ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, NULL); + ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL); dev_put(work->dev); kfree(work); } -- cgit v0.10.2 From 9225c0b7b976dd9ceac2b80727a60d8fcb906a62 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 1 Dec 2015 19:52:12 +0000 Subject: staging: lustre: echo_copy.._lsm() dereferences userland pointers directly missing get_user() Signed-off-by: Al Viro Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index f61ef66..a4a9a76 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -1270,6 +1270,7 @@ static int echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob) { struct lov_stripe_md *ulsm = _ulsm; + struct lov_oinfo **p; int nob, i; nob = offsetof(struct lov_stripe_md, lsm_oinfo[lsm->lsm_stripe_count]); @@ -1279,9 +1280,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob) if (copy_to_user(ulsm, lsm, sizeof(*ulsm))) return -EFAULT; - for (i = 0; i < lsm->lsm_stripe_count; i++) { - if (copy_to_user(ulsm->lsm_oinfo[i], lsm->lsm_oinfo[i], - sizeof(lsm->lsm_oinfo[0]))) + for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) { + struct lov_oinfo __user *up; + if (get_user(up, ulsm->lsm_oinfo + i) || + copy_to_user(up, *p, sizeof(struct lov_oinfo))) return -EFAULT; } return 0; @@ -1289,9 +1291,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob) static int echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm, - void *ulsm, int ulsm_nob) + struct lov_stripe_md __user *ulsm, int ulsm_nob) { struct echo_client_obd *ec = ed->ed_ec; + struct lov_oinfo **p; int i; if (ulsm_nob < sizeof(*lsm)) @@ -1306,11 +1309,10 @@ echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm, ((__u64)lsm->lsm_stripe_size * lsm->lsm_stripe_count > ~0UL)) return -EINVAL; - for (i = 0; i < lsm->lsm_stripe_count; i++) { - if (copy_from_user(lsm->lsm_oinfo[i], - ((struct lov_stripe_md *)ulsm)-> \ - lsm_oinfo[i], - sizeof(lsm->lsm_oinfo[0]))) + for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) { + struct lov_oinfo __user *up; + if (get_user(up, ulsm->lsm_oinfo + i) || + copy_from_user(*p, up, sizeof(struct lov_oinfo))) return -EFAULT; } return 0; -- cgit v0.10.2 From ee9159ddce14bc1dec9435ae4e3bd3153e783706 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 27 Nov 2015 14:18:39 -0500 Subject: wan/x25: Fix use-after-free in x25_asy_open_tty() The N_X25 line discipline may access the previous line discipline's closed and already-freed private data on open [1]. The tty->disc_data field _never_ refers to valid data on entry to the line discipline's open() method. Rather, the ldisc is expected to initialize that field for its own use for the lifetime of the instance (ie. from open() to close() only). [1] [ 634.336761] ================================================================== [ 634.338226] BUG: KASAN: use-after-free in x25_asy_open_tty+0x13d/0x490 at addr ffff8800a743efd0 [ 634.339558] Read of size 4 by task syzkaller_execu/8981 [ 634.340359] ============================================================================= [ 634.341598] BUG kmalloc-512 (Not tainted): kasan: bad access detected ... [ 634.405018] Call Trace: [ 634.405277] dump_stack (lib/dump_stack.c:52) [ 634.405775] print_trailer (mm/slub.c:655) [ 634.406361] object_err (mm/slub.c:662) [ 634.406824] kasan_report_error (mm/kasan/report.c:138 mm/kasan/report.c:236) [ 634.409581] __asan_report_load4_noabort (mm/kasan/report.c:279) [ 634.411355] x25_asy_open_tty (drivers/net/wan/x25_asy.c:559 (discriminator 1)) [ 634.413997] tty_ldisc_open.isra.2 (drivers/tty/tty_ldisc.c:447) [ 634.414549] tty_set_ldisc (drivers/tty/tty_ldisc.c:567) [ 634.415057] tty_ioctl (drivers/tty/tty_io.c:2646 drivers/tty/tty_io.c:2879) [ 634.423524] do_vfs_ioctl (fs/ioctl.c:43 fs/ioctl.c:607) [ 634.427491] SyS_ioctl (fs/ioctl.c:622 fs/ioctl.c:613) [ 634.427945] entry_SYSCALL_64_fastpath (arch/x86/entry/entry_64.S:188) Reported-and-tested-by: Sasha Levin Cc: Signed-off-by: Peter Hurley Signed-off-by: David S. Miller diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 5c47b01..cd39025 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -549,16 +549,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty, static int x25_asy_open_tty(struct tty_struct *tty) { - struct x25_asy *sl = tty->disc_data; + struct x25_asy *sl; int err; if (tty->ops->write == NULL) return -EOPNOTSUPP; - /* First make sure we're not already connected. */ - if (sl && sl->magic == X25_ASY_MAGIC) - return -EEXIST; - /* OK. Find a free X.25 channel to use. */ sl = x25_asy_alloc(); if (sl == NULL) -- cgit v0.10.2 From 5738a09d58d5ad2871f1f9a42bf6a3aa9ece5b3c Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 28 Nov 2015 01:29:30 +0300 Subject: vmxnet3: fix checks for dma mapping errors vmxnet3_drv does not check dma_addr with dma_mapping_error() after mapping dma memory. The patch adds the checks and tries to handle failures. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Shrikrishna Khare Signed-off-by: David S. Miller diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 899ea42..4179037 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -587,6 +587,12 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx, &adapter->pdev->dev, rbi->skb->data, rbi->len, PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + rbi->dma_addr)) { + dev_kfree_skb_any(rbi->skb); + rq->stats.rx_buf_alloc_failure++; + break; + } } else { /* rx buffer skipped by the device */ } @@ -605,13 +611,18 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx, &adapter->pdev->dev, rbi->page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + rbi->dma_addr)) { + put_page(rbi->page); + rq->stats.rx_buf_alloc_failure++; + break; + } } else { /* rx buffers skipped by the device */ } val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT; } - BUG_ON(rbi->dma_addr == 0); gd->rxd.addr = cpu_to_le64(rbi->dma_addr); gd->dword[2] = cpu_to_le32((!ring->gen << VMXNET3_RXD_GEN_SHIFT) | val | rbi->len); @@ -655,7 +666,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd, } -static void +static int vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, struct vmxnet3_tx_queue *tq, struct pci_dev *pdev, struct vmxnet3_adapter *adapter) @@ -715,6 +726,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, tbi->dma_addr = dma_map_single(&adapter->pdev->dev, skb->data + buf_offset, buf_size, PCI_DMA_TODEVICE); + if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr)) + return -EFAULT; tbi->len = buf_size; @@ -755,6 +768,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag, buf_offset, buf_size, DMA_TO_DEVICE); + if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr)) + return -EFAULT; tbi->len = buf_size; @@ -782,6 +797,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, /* set the last buf_info for the pkt */ tbi->skb = skb; tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base; + + return 0; } @@ -1020,7 +1037,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, } /* fill tx descs related to addr & len */ - vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter); + if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter)) + goto unlock_drop_pkt; /* setup the EOP desc */ ctx.eop_txd->dword[3] = cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP); @@ -1231,6 +1249,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, struct vmxnet3_rx_buf_info *rbi; struct sk_buff *skb, *new_skb = NULL; struct page *new_page = NULL; + dma_addr_t new_dma_addr; int num_to_alloc; struct Vmxnet3_RxDesc *rxd; u32 idx, ring_idx; @@ -1287,6 +1306,21 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, skip_page_frags = true; goto rcd_done; } + new_dma_addr = dma_map_single(&adapter->pdev->dev, + new_skb->data, rbi->len, + PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + new_dma_addr)) { + dev_kfree_skb(new_skb); + /* Skb allocation failed, do not handover this + * skb to stack. Reuse it. Drop the existing pkt + */ + rq->stats.rx_buf_alloc_failure++; + ctx->skb = NULL; + rq->stats.drop_total++; + skip_page_frags = true; + goto rcd_done; + } dma_unmap_single(&adapter->pdev->dev, rbi->dma_addr, rbi->len, @@ -1303,9 +1337,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, /* Immediate refill */ rbi->skb = new_skb; - rbi->dma_addr = dma_map_single(&adapter->pdev->dev, - rbi->skb->data, rbi->len, - PCI_DMA_FROMDEVICE); + rbi->dma_addr = new_dma_addr; rxd->addr = cpu_to_le64(rbi->dma_addr); rxd->len = rbi->len; if (adapter->version == 2 && @@ -1348,6 +1380,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, skip_page_frags = true; goto rcd_done; } + new_dma_addr = dma_map_page(&adapter->pdev->dev + , rbi->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + new_dma_addr)) { + put_page(new_page); + rq->stats.rx_buf_alloc_failure++; + dev_kfree_skb(ctx->skb); + ctx->skb = NULL; + skip_page_frags = true; + goto rcd_done; + } dma_unmap_page(&adapter->pdev->dev, rbi->dma_addr, rbi->len, @@ -1357,10 +1402,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, /* Immediate refill */ rbi->page = new_page; - rbi->dma_addr = dma_map_page(&adapter->pdev->dev - , rbi->page, - 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); + rbi->dma_addr = new_dma_addr; rxd->addr = cpu_to_le64(rbi->dma_addr); rxd->len = rbi->len; } @@ -2167,7 +2209,8 @@ vmxnet3_set_mc(struct net_device *netdev) PCI_DMA_TODEVICE); } - if (new_table_pa) { + if (!dma_mapping_error(&adapter->pdev->dev, + new_table_pa)) { new_mode |= VMXNET3_RXM_MCAST; rxConf->mfTablePA = cpu_to_le64(new_table_pa); } else { @@ -3075,6 +3118,11 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); + if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) { + dev_err(&pdev->dev, "Failed to map dma\n"); + err = -EFAULT; + goto err_dma_map; + } adapter->shared = dma_alloc_coherent( &adapter->pdev->dev, sizeof(struct Vmxnet3_DriverShared), @@ -3233,6 +3281,7 @@ err_alloc_queue_desc: err_alloc_shared: dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); +err_dma_map: free_netdev(netdev); return err; } -- cgit v0.10.2 From 1f390c1fde3a96974784be53cb3a645da3e4849c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20G=C3=BCnther?= Date: Tue, 1 Dec 2015 13:23:22 -0700 Subject: nvme: temporary fix for Apple controller reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent patches added basic support for the Apple NVMe controller but still cause resets and data corruption on that particular controller when a specific pattern of read/flush commands occurs. Limiting the queue depth to 2 works around that issue. This patch enforces that limit only for the Apple controller and is considered a temporary fix until we find the root source of that problem. Signed-off-by: Stephan Günther Signed-off-by: Maurice Leclaire Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f3b53af..9e294ff 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2708,6 +2708,18 @@ static int nvme_dev_map(struct nvme_dev *dev) dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH); dev->db_stride = 1 << NVME_CAP_STRIDE(cap); dev->dbs = ((void __iomem *)dev->bar) + 4096; + + /* + * Temporary fix for the Apple controller found in the MacBook8,1 and + * some MacBook7,1 to avoid controller resets and data loss. + */ + if (pdev->vendor == PCI_VENDOR_ID_APPLE && pdev->device == 0x2001) { + dev->q_depth = 2; + dev_warn(dev->dev, "detected Apple NVMe controller, set " + "queue depth=%u to work around controller resets\n", + dev->q_depth); + } + if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) dev->cmb = nvme_map_cmb(dev); -- cgit v0.10.2 From 9cd3e072b0be17446e37d7414eac8a3499e0601e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Nov 2015 20:03:10 -0800 Subject: net: rename SOCK_ASYNC_NOSPACE and SOCK_ASYNC_WAITDATA This patch is a cleanup to make following patch easier to review. Goal is to move SOCK_ASYNC_NOSPACE and SOCK_ASYNC_WAITDATA from (struct socket)->flags to a (struct socket_wq)->flags to benefit from RCU protection in sock_wake_async() To ease backports, we rename both constants. Two new helpers, sk_set_bit(int nr, struct sock *sk) and sk_clear_bit(int net, struct sock *sk) are added so that following patch can change their implementation. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 0aa6fdf..6d4d456 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -125,7 +125,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags) if (flags & MSG_DONTWAIT) return -EAGAIN; - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); for (;;) { if (signal_pending(current)) @@ -139,7 +139,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags) } finish_wait(sk_sleep(sk), &wait); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); return err; } diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index af31a0e..ca9efe1 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -212,7 +212,7 @@ static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags) if (flags & MSG_DONTWAIT) return -EAGAIN; - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); for (;;) { if (signal_pending(current)) @@ -258,7 +258,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags) return -EAGAIN; } - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); for (;;) { if (signal_pending(current)) @@ -272,7 +272,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags) } finish_wait(sk_sleep(sk), &wait); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); return err; } diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 54036ae..0fc5219 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -498,7 +498,7 @@ static void macvtap_sock_write_space(struct sock *sk) wait_queue_head_t *wqueue; if (!sock_writeable(sk) || - !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) + !test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; wqueue = sk_sleep(sk); @@ -585,7 +585,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait) mask |= POLLIN | POLLRDNORM; if (sock_writeable(&q->sk) || - (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &q->sock.flags) && + (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &q->sock.flags) && sock_writeable(&q->sk))) mask |= POLLOUT | POLLWRNORM; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b1878fa..f0db770 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1040,7 +1040,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) mask |= POLLIN | POLLRDNORM; if (sock_writeable(sk) || - (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) && + (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && sock_writeable(sk))) mask |= POLLOUT | POLLWRNORM; @@ -1488,7 +1488,7 @@ static void tun_sock_write_space(struct sock *sk) if (!sock_writeable(sk)) return; - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) + if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; wqueue = sk_sleep(sk); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 87e9d79..3a37bd3 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -421,7 +421,7 @@ static void lowcomms_write_space(struct sock *sk) if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) { con->sock->sk->sk_write_pending--; - clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags); } if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) @@ -1448,7 +1448,7 @@ static void send_to_sock(struct connection *con) msg_flags); if (ret == -EAGAIN || ret == 0) { if (ret == -EAGAIN && - test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) && + test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) && !test_and_set_bit(CF_APP_LIMITED, &con->flags)) { /* Notify TCP that we're limited by the * application window size. diff --git a/include/linux/net.h b/include/linux/net.h index 70ac5e2..f514e4d 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -34,8 +34,8 @@ struct inode; struct file; struct net; -#define SOCK_ASYNC_NOSPACE 0 -#define SOCK_ASYNC_WAITDATA 1 +#define SOCKWQ_ASYNC_NOSPACE 0 +#define SOCKWQ_ASYNC_WAITDATA 1 #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 #define SOCK_PASSSEC 4 @@ -96,7 +96,7 @@ struct socket_wq { * struct socket - general BSD socket * @state: socket state (%SS_CONNECTED, etc) * @type: socket type (%SOCK_STREAM, etc) - * @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc) + * @flags: socket flags (%SOCK_NOSPACE, etc) * @ops: protocol specific socket operations * @file: File back pointer for gc * @sk: internal networking protocol agnostic socket representation diff --git a/include/net/sock.h b/include/net/sock.h index 7f89e4b..c155d09 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2005,6 +2005,16 @@ static inline unsigned long sock_wspace(struct sock *sk) return amt; } +static inline void sk_set_bit(int nr, struct sock *sk) +{ + set_bit(nr, &sk->sk_socket->flags); +} + +static inline void sk_clear_bit(int nr, struct sock *sk) +{ + clear_bit(nr, &sk->sk_socket->flags); +} + static inline void sk_wake_async(struct sock *sk, int how, int band) { if (sock_flag(sk, SOCK_FASYNC)) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index a3bffd1..70306cc 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -271,11 +271,11 @@ static long bt_sock_data_wait(struct sock *sk, long timeo) if (signal_pending(current) || !timeo) break; - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); } __set_current_state(TASK_RUNNING); @@ -441,7 +441,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); return mask; } diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index cc85891..aa209b1 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -323,7 +323,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo) !timeo) break; - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); @@ -331,7 +331,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo) if (sock_flag(sk, SOCK_DEAD)) break; - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); } finish_wait(sk_sleep(sk), &wait); diff --git a/net/core/datagram.c b/net/core/datagram.c index 617088a..d62af69 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -785,7 +785,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); return mask; } diff --git a/net/core/sock.c b/net/core/sock.c index 1e4dd54..9d79569 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1815,7 +1815,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo) { DEFINE_WAIT(wait); - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); for (;;) { if (!timeo) break; @@ -1861,7 +1861,7 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, if (sk_wmem_alloc_get(sk) < sk->sk_sndbuf) break; - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); err = -EAGAIN; if (!timeo) @@ -2048,9 +2048,9 @@ int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb) DEFINE_WAIT(wait); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); finish_wait(sk_sleep(sk), &wait); return rc; } diff --git a/net/core/stream.c b/net/core/stream.c index d70f77a..4330942 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -126,7 +126,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p) current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2; while (1) { - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); @@ -139,7 +139,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p) } if (signal_pending(current)) goto do_interrupted; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); if (sk_stream_memory_free(sk) && !vm_wait) break; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index b5cf13a..41e6580 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -339,8 +339,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock, if (sk_stream_is_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { /* send SIGIO later */ - set_bit(SOCK_ASYNC_NOSPACE, - &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); /* Race breaker. If space is freed after diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 675cf94..eebf5ac 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1747,9 +1747,9 @@ static int dn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, } prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target)); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); finish_wait(sk_sleep(sk), &wait); } @@ -2004,10 +2004,10 @@ static int dn_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) } prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); sk_wait_event(sk, &timeo, !dn_queue_too_long(scp, queue, flags)); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); finish_wait(sk_sleep(sk), &wait); continue; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c172877..c82cca1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -517,8 +517,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) if (sk_stream_is_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { /* send SIGIO later */ - set_bit(SOCK_ASYNC_NOSPACE, - &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); /* Race breaker. If space is freed after @@ -906,7 +905,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, goto out_err; } - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); mss_now = tcp_send_mss(sk, &size_goal, flags); copied = 0; @@ -1134,7 +1133,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) } /* This should be in poll */ - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); mss_now = tcp_send_mss(sk, &size_goal, flags); diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index fcb2752..435608c 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1483,7 +1483,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock, if (sock_writeable(sk) && iucv_below_msglim(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); return mask; } diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index b7de0da..ecf0a01 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -572,7 +572,7 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock, if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); pr_debug("mask 0x%x\n", mask); diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index a40d3af..14c4e12 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -531,7 +531,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); /* this should be in poll */ - clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) return -EPIPE; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 897c01c..2353985 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6458,7 +6458,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) if (sctp_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); /* * Since the socket is not locked, the buffer * might be made available after the writeable check and diff --git a/net/socket.c b/net/socket.c index dd2c247..16be908 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1072,11 +1072,11 @@ int sock_wake_async(struct socket *sock, int how, int band) } switch (how) { case SOCK_WAKE_WAITD: - if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) + if (test_bit(SOCKWQ_ASYNC_WAITDATA, &sock->flags)) break; goto call_kill; case SOCK_WAKE_SPACE: - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) + if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags)) break; /* fall through */ case SOCK_WAKE_IO: diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 1d1a704..2ffaf6a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -398,7 +398,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, if (unlikely(!sock)) return -ENOTSOCK; - clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags); if (base != 0) { addr = NULL; addrlen = 0; @@ -442,7 +442,7 @@ static void xs_nospace_callback(struct rpc_task *task) struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt); transport->inet->sk_write_pending--; - clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); } /** @@ -467,7 +467,7 @@ static int xs_nospace(struct rpc_task *task) /* Don't race with disconnect */ if (xprt_connected(xprt)) { - if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { + if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) { /* * Notify TCP that we're limited by the application * window size @@ -478,7 +478,7 @@ static int xs_nospace(struct rpc_task *task) xprt_wait_for_buffer_space(task, xs_nospace_callback); } } else { - clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); ret = -ENOTCONN; } @@ -626,7 +626,7 @@ process_status: case -EPERM: /* When the server has died, an ICMP port unreachable message * prompts ECONNREFUSED. */ - clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); } return status; @@ -715,7 +715,7 @@ static int xs_tcp_send_request(struct rpc_task *task) case -EADDRINUSE: case -ENOBUFS: case -EPIPE: - clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); + clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags); } return status; @@ -1618,7 +1618,7 @@ static void xs_write_space(struct sock *sk) if (unlikely(!(xprt = xprt_from_sock(sk)))) return; - if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0) + if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0) return; xprt_write_space(xprt); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 6ced746..45aebd9 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2191,7 +2191,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, !timeo) break; - set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); unix_state_unlock(sk); timeo = freezable_schedule_timeout(timeo); unix_state_lock(sk); @@ -2199,7 +2199,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, if (sock_flag(sk, SOCK_DEAD)) break; - clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); } finish_wait(sk_sleep(sk), &wait); @@ -2683,7 +2683,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, if (writable) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); return mask; } -- cgit v0.10.2 From ceb5d58b217098a657f3850b7a2640f995032e62 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Nov 2015 20:03:11 -0800 Subject: net: fix sock_wake_async() rcu protection Dmitry provided a syzkaller (http://github.com/google/syzkaller) triggering a fault in sock_wake_async() when async IO is requested. Said program stressed af_unix sockets, but the issue is generic and should be addressed in core networking stack. The problem is that by the time sock_wake_async() is called, we should not access the @flags field of 'struct socket', as the inode containing this socket might be freed without further notice, and without RCU grace period. We already maintain an RCU protected structure, "struct socket_wq" so moving SOCKWQ_ASYNC_NOSPACE & SOCKWQ_ASYNC_WAITDATA into it is the safe route. It also reduces number of cache lines needing dirtying, so might provide a performance improvement anyway. In followup patches, we might move remaining flags (SOCK_NOSPACE, SOCK_PASSCRED, SOCK_PASSSEC) to save 8 bytes and let 'struct socket' being mostly read and let it being shared between cpus. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/net.h b/include/linux/net.h index f514e4d..0b4ac7d 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -34,6 +34,10 @@ struct inode; struct file; struct net; +/* Historically, SOCKWQ_ASYNC_NOSPACE & SOCKWQ_ASYNC_WAITDATA were located + * in sock->flags, but moved into sk->sk_wq->flags to be RCU protected. + * Eventually all flags will be in sk->sk_wq_flags. + */ #define SOCKWQ_ASYNC_NOSPACE 0 #define SOCKWQ_ASYNC_WAITDATA 1 #define SOCK_NOSPACE 2 @@ -89,6 +93,7 @@ struct socket_wq { /* Note: wait MUST be first field of socket_wq */ wait_queue_head_t wait; struct fasync_struct *fasync_list; + unsigned long flags; /* %SOCKWQ_ASYNC_NOSPACE, etc */ struct rcu_head rcu; } ____cacheline_aligned_in_smp; @@ -202,7 +207,7 @@ enum { SOCK_WAKE_URG, }; -int sock_wake_async(struct socket *sk, int how, int band); +int sock_wake_async(struct socket_wq *sk_wq, int how, int band); int sock_register(const struct net_proto_family *fam); void sock_unregister(int family); int __sock_create(struct net *net, int family, int type, int proto, diff --git a/include/net/sock.h b/include/net/sock.h index c155d09..0434138 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -384,8 +384,10 @@ struct sock { int sk_rcvbuf; struct sk_filter __rcu *sk_filter; - struct socket_wq __rcu *sk_wq; - + union { + struct socket_wq __rcu *sk_wq; + struct socket_wq *sk_wq_raw; + }; #ifdef CONFIG_XFRM struct xfrm_policy *sk_policy[2]; #endif @@ -2005,20 +2007,27 @@ static inline unsigned long sock_wspace(struct sock *sk) return amt; } +/* Note: + * We use sk->sk_wq_raw, from contexts knowing this + * pointer is not NULL and cannot disappear/change. + */ static inline void sk_set_bit(int nr, struct sock *sk) { - set_bit(nr, &sk->sk_socket->flags); + set_bit(nr, &sk->sk_wq_raw->flags); } static inline void sk_clear_bit(int nr, struct sock *sk) { - clear_bit(nr, &sk->sk_socket->flags); + clear_bit(nr, &sk->sk_wq_raw->flags); } -static inline void sk_wake_async(struct sock *sk, int how, int band) +static inline void sk_wake_async(const struct sock *sk, int how, int band) { - if (sock_flag(sk, SOCK_FASYNC)) - sock_wake_async(sk->sk_socket, how, band); + if (sock_flag(sk, SOCK_FASYNC)) { + rcu_read_lock(); + sock_wake_async(rcu_dereference(sk->sk_wq), how, band); + rcu_read_unlock(); + } } /* Since sk_{r,w}mem_alloc sums skb->truesize, even a small frame might diff --git a/net/core/stream.c b/net/core/stream.c index 4330942..b96f7a7 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -39,7 +39,7 @@ void sk_stream_write_space(struct sock *sk) wake_up_interruptible_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT); + sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); rcu_read_unlock(); } } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 2353985..5e35ef3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6801,26 +6801,30 @@ no_packet: static void __sctp_write_space(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; - struct socket *sock = sk->sk_socket; - if ((sctp_wspace(asoc) > 0) && sock) { - if (waitqueue_active(&asoc->wait)) - wake_up_interruptible(&asoc->wait); + if (sctp_wspace(asoc) <= 0) + return; + + if (waitqueue_active(&asoc->wait)) + wake_up_interruptible(&asoc->wait); - if (sctp_writeable(sk)) { - wait_queue_head_t *wq = sk_sleep(sk); + if (sctp_writeable(sk)) { + struct socket_wq *wq; - if (wq && waitqueue_active(wq)) - wake_up_interruptible(wq); + rcu_read_lock(); + wq = rcu_dereference(sk->sk_wq); + if (wq) { + if (waitqueue_active(&wq->wait)) + wake_up_interruptible(&wq->wait); /* Note that we try to include the Async I/O support * here by modeling from the current TCP/UDP code. * We have not tested with it yet. */ if (!(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(sock, - SOCK_WAKE_SPACE, POLL_OUT); + sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); } + rcu_read_unlock(); } } diff --git a/net/socket.c b/net/socket.c index 16be908..456fadb 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1056,27 +1056,20 @@ static int sock_fasync(int fd, struct file *filp, int on) return 0; } -/* This function may be called only under socket lock or callback_lock or rcu_lock */ +/* This function may be called only under rcu_lock */ -int sock_wake_async(struct socket *sock, int how, int band) +int sock_wake_async(struct socket_wq *wq, int how, int band) { - struct socket_wq *wq; - - if (!sock) - return -1; - rcu_read_lock(); - wq = rcu_dereference(sock->wq); - if (!wq || !wq->fasync_list) { - rcu_read_unlock(); + if (!wq || !wq->fasync_list) return -1; - } + switch (how) { case SOCK_WAKE_WAITD: - if (test_bit(SOCKWQ_ASYNC_WAITDATA, &sock->flags)) + if (test_bit(SOCKWQ_ASYNC_WAITDATA, &wq->flags)) break; goto call_kill; case SOCK_WAKE_SPACE: - if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags)) + if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags)) break; /* fall through */ case SOCK_WAKE_IO: @@ -1086,7 +1079,7 @@ call_kill: case SOCK_WAKE_URG: kill_fasync(&wq->fasync_list, SIGURG, band); } - rcu_read_unlock(); + return 0; } EXPORT_SYMBOL(sock_wake_async); -- cgit v0.10.2 From 0f72e37e42a8ce427caa1b96f7f51e450f2ecb82 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 1 Dec 2015 16:08:05 -0500 Subject: tracing: Add sched_wakeup_new and sched_waking tracepoints for pid filter The set_event_pid filter relies on attaching to the sched_switch and sched_wakeup tracepoints to see if it should filter the tracing on schedule tracepoints. By adding the callbacks to sched_wakeup, pids in the set_event_pid file will trace the wakeups of those tasks with those pids. But sched_wakeup_new and sched_waking were missed. These two should also be traced. Luckily, these tracepoints share the same class as sched_wakeup which means they can use the same pre and post callbacks as sched_wakeup does. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 6bbc5f6..4f6ef69 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -582,6 +582,12 @@ static void __ftrace_clear_event_pids(struct trace_array *tr) unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr); unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr); + unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre, tr); + unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post, tr); + + unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_pre, tr); + unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_post, tr); + list_for_each_entry(file, &tr->events, list) { clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags); } @@ -1729,6 +1735,16 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf, tr, INT_MAX); register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr, 0); + + register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre, + tr, INT_MAX); + register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post, + tr, 0); + + register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_pre, + tr, INT_MAX); + register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_post, + tr, 0); } /* -- cgit v0.10.2 From d5d4fdd86f5759924fe54efa793e22eccf508db6 Mon Sep 17 00:00:00 2001 From: Guillaume Delbergue Date: Tue, 1 Dec 2015 18:55:51 +0100 Subject: irqchip/versatile-fpga: Fix PCI IRQ mapping on Versatile PB This patch is specifically for PCI support on the Versatile PB board using a DT. Currently, the dynamic IRQ mapping is broken when using DTs. For example, on QEMU, the SCSI driver is unable to request the IRQ. To fix this issue, this patch replaces the current dynamic mechanism with a static value as is done in the non-DT case. Signed-off-by: Guillaume Delbergue Signed-off-by: Arnd Bergmann Cc: stable@vger.kernel.org diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 598ab3f..cadf104 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -210,7 +210,12 @@ int __init fpga_irq_of_init(struct device_node *node, parent_irq = -1; } +#ifdef CONFIG_ARCH_VERSATILE + fpga_irq_init(base, node->name, IRQ_SIC_START, parent_irq, valid_mask, + node); +#else fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node); +#endif writel(clear_mask, base + IRQ_ENABLE_CLEAR); writel(clear_mask, base + FIQ_ENABLE_CLEAR); -- cgit v0.10.2 From 33bd2dd03dd0bfa1130d11062a9e5f40d0cf1d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Tue, 1 Dec 2015 19:56:48 +0100 Subject: USB: quirks: Apply ALWAYS_POLL to all ELAN devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All ELAN hid devices seem to require the ALWAYS_POLL quirk. Let's use this quirk for all devices from this vendor, rather than maintaining a list of all its known product IDs. Tested-by: Adrien Vergé Signed-off-by: Adrien Vergé Reviewed-by: Benjamin Tissoires Reviewed-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ac1feea..3c7e0c3 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -316,11 +316,6 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_VENDOR_ID_ELAN 0x04f3 -#define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089 -#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B 0x009b -#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103 0x0103 -#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c 0x010c -#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F 0x016f #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 94bb137..78fc94a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -72,11 +72,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL }, - { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL }, - { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL }, - { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c, HID_QUIRK_ALWAYS_POLL }, - { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, @@ -339,7 +335,8 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor, for (; hid_blacklist[n].idVendor; n++) if (hid_blacklist[n].idVendor == idVendor && - hid_blacklist[n].idProduct == idProduct) + (hid_blacklist[n].idProduct == (__u16) HID_ANY_ID || + hid_blacklist[n].idProduct == idProduct)) bl_entry = &hid_blacklist[n]; if (bl_entry != NULL) -- cgit v0.10.2 From d66e5139aee7d8379fc135b00b9ac7c66f9d4c74 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 23:20:28 +0100 Subject: ARM: ixp4xx: fix read{b,w,l} return types On ixp4xx, the readl() function returns an 'unsigned long' output when indirect I/O is used. This is unlike any other platform, and it causes lots of harmless compiler warnings, such as: drivers/ata/libahci.c: In function 'ahci_show_host_version': drivers/ata/libahci.c:254:22: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=] drivers/block/mtip32xx/mtip32xx.c: In function 'mtip_hw_read_registers': drivers/block/mtip32xx/mtip32xx.c:2602:31: warning: format '%X' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=] drivers/block/cciss.c: In function 'print_cfg_table': drivers/block/cciss.c:3845:25: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=] This changes all six of the ixp4xx specific I/O read functions to return the same types that we have in the normal asm/io.h, to avoid the warnings. Signed-off-by: Arnd Bergmann Acked-by: Krzysztof Halasa diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h index b024390..7a0c13b 100644 --- a/arch/arm/mach-ixp4xx/include/mach/io.h +++ b/arch/arm/mach-ixp4xx/include/mach/io.h @@ -143,7 +143,7 @@ static inline void __indirect_writesl(volatile void __iomem *bus_addr, writel(*vaddr++, bus_addr); } -static inline unsigned char __indirect_readb(const volatile void __iomem *p) +static inline u8 __indirect_readb(const volatile void __iomem *p) { u32 addr = (u32)p; u32 n, byte_enables, data; @@ -166,7 +166,7 @@ static inline void __indirect_readsb(const volatile void __iomem *bus_addr, *vaddr++ = readb(bus_addr); } -static inline unsigned short __indirect_readw(const volatile void __iomem *p) +static inline u16 __indirect_readw(const volatile void __iomem *p) { u32 addr = (u32)p; u32 n, byte_enables, data; @@ -189,7 +189,7 @@ static inline void __indirect_readsw(const volatile void __iomem *bus_addr, *vaddr++ = readw(bus_addr); } -static inline unsigned long __indirect_readl(const volatile void __iomem *p) +static inline u32 __indirect_readl(const volatile void __iomem *p) { u32 addr = (__force u32)p; u32 data; @@ -350,7 +350,7 @@ static inline void insl(u32 io_addr, void *p, u32 count) ((unsigned long)p <= (PIO_MASK + PIO_OFFSET))) #define ioread8(p) ioread8(p) -static inline unsigned int ioread8(const void __iomem *addr) +static inline u8 ioread8(const void __iomem *addr) { unsigned long port = (unsigned long __force)addr; if (__is_io_address(port)) @@ -378,7 +378,7 @@ static inline void ioread8_rep(const void __iomem *addr, void *vaddr, u32 count) } #define ioread16(p) ioread16(p) -static inline unsigned int ioread16(const void __iomem *addr) +static inline u16 ioread16(const void __iomem *addr) { unsigned long port = (unsigned long __force)addr; if (__is_io_address(port)) @@ -407,7 +407,7 @@ static inline void ioread16_rep(const void __iomem *addr, void *vaddr, } #define ioread32(p) ioread32(p) -static inline unsigned int ioread32(const void __iomem *addr) +static inline u32 ioread32(const void __iomem *addr) { unsigned long port = (unsigned long __force)addr; if (__is_io_address(port)) -- cgit v0.10.2 From 464ad8c43a9ead98c2b0eaed86bea727f2ad106e Mon Sep 17 00:00:00 2001 From: Hans Yang Date: Tue, 1 Dec 2015 16:54:59 +0800 Subject: usb: core : hub: Fix BOS 'NULL pointer' kernel panic When a USB 3.0 mass storage device is disconnected in transporting state, storage device driver may handle it as a transport error and reset the device by invoking usb_reset_and_verify_device() and following could happen: in usb_reset_and_verify_device(): udev->bos = NULL; For U1/U2 enabled devices, driver will disable LPM, and in some conditions: from usb_unlocked_disable_lpm() --> usb_disable_lpm() --> usb_enable_lpm() udev->bos->ss_cap->bU1devExitLat; And it causes 'NULL pointer' and 'kernel panic': [ 157.976257] Unable to handle kernel NULL pointer dereference at virtual address 00000010 ... [ 158.026400] PC is at usb_enable_link_state+0x34/0x2e0 [ 158.031442] LR is at usb_enable_lpm+0x98/0xac ... [ 158.137368] [] usb_enable_link_state+0x34/0x2e0 [ 158.143451] [] usb_enable_lpm+0x94/0xac [ 158.148840] [] usb_disable_lpm+0xa8/0xb4 ... [ 158.214954] Kernel panic - not syncing: Fatal exception This commit moves 'udev->bos = NULL' behind usb_unlocked_disable_lpm() to prevent from NULL pointer access. Issue can be reproduced by following setup: 1) A SS pen drive behind a SS hub connected to the host. 2) Transporting data between the pen drive and the host. 3) Abruptly disconnect hub and pen drive from host. 4) With a chance it crashes. Signed-off-by: Hans Yang Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bdeadc1..585c3cb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5326,9 +5326,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); - bos = udev->bos; - udev->bos = NULL; - /* Disable LPM and LTM while we reset the device and reinstall the alt * settings. Device-initiated LPM settings, and system exit latency * settings are cleared when the device is reset, so we have to set @@ -5337,15 +5334,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev) ret = usb_unlocked_disable_lpm(udev); if (ret) { dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); - goto re_enumerate; + goto re_enumerate_no_bos; } ret = usb_disable_ltm(udev); if (ret) { dev_err(&udev->dev, "%s Failed to disable LTM\n.", __func__); - goto re_enumerate; + goto re_enumerate_no_bos; } + bos = udev->bos; + udev->bos = NULL; + for (i = 0; i < SET_CONFIG_TRIES; ++i) { /* ep0 maxpacket size may change; let the HCD know about it. @@ -5442,10 +5442,11 @@ done: return 0; re_enumerate: - /* LPM state doesn't matter when we're about to destroy the device. */ - hub_port_logical_disconnect(parent_hub, port1); usb_release_bos_descriptor(udev); udev->bos = bos; +re_enumerate_no_bos: + /* LPM state doesn't matter when we're about to destroy the device. */ + hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } -- cgit v0.10.2 From f9fa1887dcf26bd346665a6ae3d3f53dec54cba1 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 21 Nov 2015 00:36:44 +0300 Subject: USB: whci-hcd: add check for dma mapping error qset_fill_page_list() do not check for dma mapping errors. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index dc31c42..9f1c053 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -377,6 +377,10 @@ static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_f if (std->pl_virt == NULL) return -ENOMEM; std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); + if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) { + kfree(std->pl_virt); + return -EFAULT; + } for (p = 0; p < std->num_pointers; p++) { std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); -- cgit v0.10.2 From 5377adb092664d336ac212499961cac5e8728794 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 18 Nov 2015 02:01:21 +0000 Subject: usb: Use the USB_SS_MULT() macro to decode burst multiplier for log message usb_parse_ss_endpoint_companion() now decodes the burst multiplier correctly in order to check that it's <= 3, but still uses the wrong expression if warning that it's > 3. Fixes: ff30cbc8da42 ("usb: Use the USB_SS_MULT() macro to get the ...") Signed-off-by: Ben Hutchings Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7caff02..5050760 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -115,7 +115,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, USB_SS_MULT(desc->bmAttributes) > 3) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " - "setting to 3\n", desc->bmAttributes + 1, + "setting to 3\n", + USB_SS_MULT(desc->bmAttributes), cfgno, inum, asnum, ep->desc.bEndpointAddress); ep->ss_ep_comp.bmAttributes = 2; } -- cgit v0.10.2 From a8594f20cafadb6ba58f915dea5f2c94a9333b1a Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 9 Nov 2015 20:52:43 +0100 Subject: drm/rockchip: unset pgoff when mmap'ing gems Commit 371f0f085f629 ("ARM: 8426/1: dma-mapping: add missing range check in dma_mmap()") introduced offset-checking for mappings, which collides with the fake-offset the drm sets for gems. Other drm-drivers set this offset to 0 before doing the mapping, so this looks like the correct way to go for rockchip as well. Fixes: 371f0f085f629 ("ARM: 8426/1: dma-mapping: add missing range check in dma_mmap()") Signed-off-by: Heiko Stuebner diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 8caea0a..d908321 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -67,6 +67,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). */ vma->vm_flags &= ~VM_PFNMAP; + vma->vm_pgoff = 0; ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr, obj->size, &rk_obj->dma_attrs); -- cgit v0.10.2 From 72906ce0301fc8a2cbfa52632191b0ba719699b5 Mon Sep 17 00:00:00 2001 From: Dominik Behr Date: Tue, 10 Nov 2015 17:59:10 +0800 Subject: drm/rockchip: vop: fix window origin calculation VOP_WINx_DSP_ST does not require subtracting 1 from the values written to it. It actually causes the screen to be shifted by one pixel. Signed-off-by: Mark Yao Tested-by: Yakir Yang Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Dominik Behr Signed-off-by: Mark Yao diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 48719df..4730ae4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -959,8 +959,8 @@ static int vop_update_plane_event(struct drm_plane *plane, val = (dest.y2 - dest.y1 - 1) << 16; val |= (dest.x2 - dest.x1 - 1) & 0xffff; VOP_WIN_SET(vop, win, dsp_info, val); - val = (dsp_sty - 1) << 16; - val |= (dsp_stx - 1) & 0xffff; + val = dsp_sty << 16; + val |= dsp_stx & 0xffff; VOP_WIN_SET(vop, win, dsp_st, val); VOP_WIN_SET(vop, win, rb_swap, rb_swap); -- cgit v0.10.2 From 3b134ced9c1fb15fa91034fc7787d651155b64f9 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 30 Nov 2015 14:56:56 +0000 Subject: drm/rockchip: Fix module autoload for OF platform driver This platform driver has 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 diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 4730ae4..040559a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -374,6 +374,7 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &rk3288_vop }, {}, }; +MODULE_DEVICE_TABLE(of, vop_driver_dt_match); static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v) { -- cgit v0.10.2 From 727ae8be30b428082d3519817f4fb98b712d457d Mon Sep 17 00:00:00 2001 From: Liu Jiang Date: Fri, 27 Nov 2015 11:12:33 +0800 Subject: x86/PCI/ACPI: Fix regression caused by commit 4d6b4e69a245 Commit 4d6b4e69a245 ("x86/PCI/ACPI: Use common interface to support PCI host bridge") converted x86 to use the common interface acpi_pci_root_create, but the conversion missed on code piece in arch/x86/pci/bus_numa.c, which causes regression on some legacy AMD platforms as reported by Arthur Marsh . The root causes is that acpi_pci_root_create() fails to insert host bridge resources into iomem_resource/ioport_resource because x86_pci_root_bus_resources() has already inserted those resources. So change x86_pci_root_bus_resources() to not insert resources into iomem_resource/ioport_resource. Fixes: 4d6b4e69a245 ("x86/PCI/ACPI: Use common interface to support PCI host bridge") Signed-off-by: Jiang Liu Reported-and-tested-by: Arthur Marsh Reported-and-tested-by: Krzysztof Kolasa Reported-and-tested-by: Keith Busch Reported-and-tested-by: Hans de Bruin Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index 7bcf06a..6eb3c8a 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c @@ -50,18 +50,9 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) if (!found) pci_add_resource(resources, &info->busn); - list_for_each_entry(root_res, &info->resources, list) { - struct resource *res; - struct resource *root; + list_for_each_entry(root_res, &info->resources, list) + pci_add_resource(resources, &root_res->res); - res = &root_res->res; - pci_add_resource(resources, res); - if (res->flags & IORESOURCE_IO) - root = &ioport_resource; - else - root = &iomem_resource; - insert_resource(root, res); - } return; default_resources: diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 850d7bf..ae3fe4e 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -768,6 +768,13 @@ static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info) else continue; + /* + * Some legacy x86 host bridge drivers use iomem_resource and + * ioport_resource as default resource pool, skip it. + */ + if (res == root) + continue; + conflict = insert_resource_conflict(root, res); if (conflict) { dev_info(&info->bridge->dev, -- cgit v0.10.2 From 3b60a26fdc3b32c00d750458df33d414e8f924ce Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 17 Oct 2015 21:05:20 -0700 Subject: ARM: imx: clk-vf610: fix SAI clock tree The Synchronous Audio Interface (SAI) instances are clocked by independent clocks: The bus clock and the audio clock (as shown in Figure 51-1 in the Vybrid Reference Manual). The clock gates in CCGR0/CCGR1 for SAI0 through SAI3 are bus clock gates, as access tests to the registers with/without gating those clocks have shown. The audio clock is gated by the SAIx_EN gates in CCM_CSCDR1, followed by a clock divider (SAIx_DIV). Currently, the parent of the bus clock gates has been assigned to SAIx_DIV, which is not involved in the bus clock path for the SAI instances (see chapter 9.10.12, SAI clocking in the Vybrid Reference Manual). Fix this by define the parent clock of VF610_CLK_SAIx to be the bus clock. If the driver needs the audio clock (when used in master mode), a fixed device tree is required which assign the audio clock properly to VF610_CLK_SAIx_DIV. Signed-off-by: Stefan Agner Acked-by: Stephen Boyd Signed-off-by: Shawn Guo diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index d1b1c95..0a94d96 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -335,22 +335,22 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4); clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16); clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4); - clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15)); + clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15)); clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4); clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17); clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4); - clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0)); + clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0)); clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4); clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18); clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4); - clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1)); + clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1)); clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4); clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19); clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4); - clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2)); + clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2)); clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4); clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9); -- cgit v0.10.2 From 531ee1f4ea7fb5634cb79824e6df6be83596a054 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 17 Oct 2015 21:05:21 -0700 Subject: ARM: dts: vf610: fix clock definition for SAI2 So far, only the bus clock has been assigned, but in reality the SAI IP has for clock inputs. The driver has been updated to make use of the additional clock inputs by c3ecef21c3f2 ("ASoC: fsl_sai: add sai master mode support"). Due to a bug in the clock tree, the audio clock has been enabled none the less by the specified bus clock (see "ARM: imx: clk-vf610: fix SAI clock tree"), which made master mode even without the proper clock assigned working. This patch completes the clock definition for SAI2. On Vybrid, only two MCLK out of the four options are available (the first being the bus clock itself). See chapter 8.10.1.2.3 of the Vybrid Reference manual ("SAI transmitter and receiver options for MCLK selection"). Note: The audio clocks are only required in master mode. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index 0d5acc2..3cd1b27 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -178,8 +178,10 @@ compatible = "fsl,vf610-sai"; reg = <0x40031000 0x1000>; interrupts = <86 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks VF610_CLK_SAI2>; - clock-names = "sai"; + clocks = <&clks VF610_CLK_SAI2>, + <&clks VF610_CLK_SAI2_DIV>, + <&clks 0>, <&clks 0>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; dma-names = "tx", "rx"; dmas = <&edma0 0 21>, <&edma0 0 20>; -- cgit v0.10.2 From c9fbb7f7b5c56752373e4f425d5157815426e233 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 16 Nov 2015 12:50:21 +0000 Subject: drm/rockchip: Use CRTC vblank event interface Passing -1 as the pipe for vblank events now triggers a WARN_ON, but had previously made multi-screen unusable anyway. Pass the correct pipe to the event-send function, and use the new API to make this a bit easier for us. Fixes WARN present since cc1ef118fc for every pageflip event sent: [ 209.549969] ------------[ cut here ]------------ [ 209.554592] WARNING: CPU: 3 PID: 238 at drivers/gpu/drm/drm_irq.c:924 drm_vblank_count_and_time+0x80/0x88 [drm]() [ 209.564832] Modules linked in: [...] [ 209.612401] CPU: 3 PID: 238 Comm: irq/41-ff940000 Tainted: G W 4.3.0-rc6+ #71 [ 209.620647] Hardware name: Rockchip (Device Tree) [ 209.625348] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [ 209.633079] [] (show_stack) from [] (dump_stack+0x8c/0x9c) [ 209.640289] [] (dump_stack) from [] (warn_slowpath_common+0x94/0xc4) [ 209.648364] [] (warn_slowpath_common) from [] (warn_slowpath_null+0x2c/0x34) [ 209.657139] [] (warn_slowpath_null) from [] (drm_vblank_count_and_time+0x80/0x88 [drm]) [ 209.666875] [] (drm_vblank_count_and_time [drm]) from [] (drm_send_vblank_event+0x74/0x7c [drm]) [ 209.677385] [] (drm_send_vblank_event [drm]) from [] (vop_win_state_complete+0x4c/0x70 [rockchip_drm_vop]) [ 209.688757] [] (vop_win_state_complete [rockchip_drm_vop]) from [] (vop_isr_thread+0x170/0x1d4 [rockchip_drm_vop]) [ 209.700822] [] (vop_isr_thread [rockchip_drm_vop]) from [] (irq_thread_fn+0x2c/0x50) [ 209.710284] [] (irq_thread_fn) from [] (irq_thread+0x13c/0x188) [ 209.717927] [] (irq_thread) from [] (kthread+0xec/0x104) [ 209.724965] [] (kthread) from [] (ret_from_fork+0x14/0x3c) [ 209.732171] ---[ end trace 0690bc604f5d535d ]--- Signed-off-by: Daniel Stone Cc: Sjoerd Simons Cc: Thierry Reding Cc: Heiko Stuebner Tested-By: Sjoerd Simons Tested-by: Heiko Stuebner Reviewed-by: Thierry Reding diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 040559a..03c47ee 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1290,7 +1290,7 @@ static void vop_win_state_complete(struct vop_win *vop_win, if (state->event) { spin_lock_irqsave(&drm->event_lock, flags); - drm_send_vblank_event(drm, -1, state->event); + drm_crtc_send_vblank_event(crtc, state->event); spin_unlock_irqrestore(&drm->event_lock, flags); } -- cgit v0.10.2 From fbca9d2d35c6ef1b323fae75cc9545005ba25097 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 30 Nov 2015 13:02:56 +0100 Subject: bpf, array: fix heap out-of-bounds access when updating elements During own review but also reported by Dmitry's syzkaller [1] it has been noticed that we trigger a heap out-of-bounds access on eBPF array maps when updating elements. This happens with each map whose map->value_size (specified during map creation time) is not multiple of 8 bytes. In array_map_alloc(), elem_size is round_up(attr->value_size, 8) and used to align array map slots for faster access. However, in function array_map_update_elem(), we update the element as ... memcpy(array->value + array->elem_size * index, value, array->elem_size); ... where we access 'value' out-of-bounds, since it was allocated from map_update_elem() from syscall side as kmalloc(map->value_size, GFP_USER) and later on copied through copy_from_user(value, uvalue, map->value_size). Thus, up to 7 bytes, we can access out-of-bounds. Same could happen from within an eBPF program, where in worst case we access beyond an eBPF program's designated stack. Since 1be7f75d1668 ("bpf: enable non-root eBPF programs") didn't hit an official release yet, it only affects priviledged users. In case of array_map_lookup_elem(), the verifier prevents eBPF programs from accessing beyond map->value_size through check_map_access(). Also from syscall side map_lookup_elem() only copies map->value_size back to user, so nothing could leak. [1] http://github.com/google/syzkaller Fixes: 28fbcfa08d8e ("bpf: add array type of eBPF maps") Reported-by: Dmitry Vyukov Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 3f4c99e..4c67ce3 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -105,7 +105,7 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value, /* all elements already exist */ return -EEXIST; - memcpy(array->value + array->elem_size * index, value, array->elem_size); + memcpy(array->value + array->elem_size * index, value, map->value_size); return 0; } -- cgit v0.10.2 From 2078665a7e12df5d8ab4d254eac69e15959271e6 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 1 Dec 2015 10:26:24 +0100 Subject: HID: lg: restrict filtering out of first interface to G29 only Looks like 29fae1c85 ("HID: logitech: Add support for G29") was a little bit aggressive and broke other devices. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=108121 Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index c20ac76..c690fae 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -665,8 +665,9 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) struct lg_drv_data *drv_data; int ret; - /* Only work with the 1st interface (G29 presents multiple) */ - if (iface_num != 0) { + /* G29 only work with the 1st interface */ + if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) && + (iface_num != 0)) { dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num); return -ENODEV; } -- cgit v0.10.2 From 64031e3e8a5c042840c5123af695eec89f9e6a24 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Wed, 2 Dec 2015 15:44:22 +0800 Subject: ACPI / property: fix compile error for acpi_node_get_property_reference() when CONFIG_ACPI=n In commit 60ba032ed76e ("ACPI / property: Drop size_prop from acpi_dev_get_property_reference()"), the argument "const char *cells_name" was dropped, but forgot to update the stub function in no-ACPI case, it will lead to compile error when CONFIG_ACPI=n, easliy remove "const char *cells_name" to fix it. Fixes: 60ba032ed76e "ACPI / property: Drop size_prop from acpi_dev_get_property_reference()" Reported-by: Kejian Yan Signed-off-by: Hanjun Guo Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 865d948..9e6f4bb 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -782,8 +782,8 @@ static inline int acpi_dev_get_property(struct acpi_device *adev, } static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, const char *cells_name, - size_t index, struct acpi_reference_args *args) + const char *name, size_t index, + struct acpi_reference_args *args) { return -ENXIO; } -- cgit v0.10.2 From 86f98a3abb237d95fddf2ec857df5a3ac6d71752 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Dec 2015 11:58:40 +0300 Subject: MAINTAINERS: ACPI / video: update a file name in drivers/acpi/ We renamed drivers/acpi/video.c to drivers/acpi/acpi_video.c in commit 14ca7a47d0ab ('acpi-video-detect: video: Make video_detect code part of the video module'). Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki diff --git a/MAINTAINERS b/MAINTAINERS index cba790b..58e2905 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -318,7 +318,7 @@ M: Zhang Rui L: linux-acpi@vger.kernel.org W: https://01.org/linux-acpi S: Supported -F: drivers/acpi/video.c +F: drivers/acpi/acpi_video.c ACPI WMI DRIVER L: platform-driver-x86@vger.kernel.org -- cgit v0.10.2 From 712caed435077966143a1ed2e6ae345916068d2e Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 2 Dec 2015 14:08:27 +0100 Subject: PM / Domains: Validate cases of a non-bound driver in genpd governor Recently genpd removed the requirement of a having a driver bound for its attached devices to allow genpd to power off. That change should also have removed a corresponding validation in the governor, let's correct that. Fixes: 298cd0f08801 (PM / Domains: Remove dev->driver check for runtime) Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index e60dd12..1e937ac 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -160,9 +160,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) struct gpd_timing_data *td; s64 constraint_ns; - if (!pdd->dev->driver) - continue; - /* * Check if the device is allowed to be off long enough for the * domain to turn off and on (that's how much time it will -- cgit v0.10.2 From 06bf403de344a8a0811ebd24992d2a08022c5225 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 30 Nov 2015 21:02:55 +0200 Subject: PCI / PM: Tune down retryable runtime suspend error messages The runtime PM core doesn't treat EBUSY and EAGAIN retvals from the driver suspend hooks as errors, but they still show up as errors in dmesg. Tune them down. See rpm_suspend() for details of handling these return values. Note that we use dev_dbg() for the retryable retvals, so after this change you'll need either CONFIG_DYNAMIC_DEBUG or CONFIG_PCI_DEBUG for them to show up in the log. One problem caused by this was noticed by Daniel: the i915 driver returns EAGAIN to signal a temporary failure to suspend and as a request towards the RPM core for scheduling a suspend again. This is a normal event, but the resulting error message flags a breakage during the driver's automated testing which parses dmesg and picks up the error. Reported-by: Daniel Vetter Link: https://bugs.freedesktop.org/show_bug.cgi?id=92992 Signed-off-by: Imre Deak Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 4446fcb..d7ffd66 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1146,9 +1146,21 @@ static int pci_pm_runtime_suspend(struct device *dev) pci_dev->state_saved = false; pci_dev->no_d3cold = false; error = pm->runtime_suspend(dev); - suspend_report_result(pm->runtime_suspend, error); - if (error) + if (error) { + /* + * -EBUSY and -EAGAIN is used to request the runtime PM core + * to schedule a new suspend, so log the event only with debug + * log level. + */ + if (error == -EBUSY || error == -EAGAIN) + dev_dbg(dev, "can't suspend now (%pf returned %d)\n", + pm->runtime_suspend, error); + else + dev_err(dev, "can't suspend (%pf returned %d)\n", + pm->runtime_suspend, error); + return error; + } if (!pci_dev->d3cold_allowed) pci_dev->no_d3cold = true; -- cgit v0.10.2 From a781ce79d51fc4952870c998937980a042927e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Nov 2015 18:55:25 +0200 Subject: drm/i915: Clean up AUX power domain handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce intel_display_port_aux_power_domain() which simply returns the appropriate AUX power domain for a specific port, and then replace the intel_display_port_power_domain() with calls to the new function in the DP code. As long as we're not actually enabling the port we don't need the lane power domains, and those are handled now purely from modeset_update_crtc_power_domains(). My initial motivation for this was to see if I could keep the DPIO power wells powered down while doing AUX on CHV, but turns out I can't so this doesn't change anything for CHV at least. But I think it's still a worthwile change. v2: Add case for PORT E. Default to POWER_DOMAIN_AUX_D for now. (Ville) Signed-off-by: Ville Syrjälä Reviewed-by: Patrik Jakobsson [Cherry-picked from drm-intel-next-queued 25f78f58 (Imre)] Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1448643329-18675-2-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12a2e9d..19915b1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5199,6 +5199,26 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) } } +static enum intel_display_power_domain port_to_aux_power_domain(enum port port) +{ + switch (port) { + case PORT_A: + return POWER_DOMAIN_AUX_A; + case PORT_B: + return POWER_DOMAIN_AUX_B; + case PORT_C: + return POWER_DOMAIN_AUX_C; + case PORT_D: + return POWER_DOMAIN_AUX_D; + case PORT_E: + /* FIXME: Check VBT for actual wiring of PORT E */ + return POWER_DOMAIN_AUX_D; + default: + WARN_ON_ONCE(1); + return POWER_DOMAIN_AUX_A; + } +} + #define for_each_power_domain(domain, mask) \ for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ if ((1 << (domain)) & (mask)) @@ -5230,6 +5250,29 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder) } } +enum intel_display_power_domain +intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct intel_digital_port *intel_dig_port; + + switch (intel_encoder->type) { + case INTEL_OUTPUT_UNKNOWN: + /* Only DDI platforms should ever use this output type */ + WARN_ON_ONCE(!HAS_DDI(dev)); + case INTEL_OUTPUT_DISPLAYPORT: + case INTEL_OUTPUT_EDP: + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + return port_to_aux_power_domain(intel_dig_port->port); + case INTEL_OUTPUT_DP_MST: + intel_dig_port = enc_to_mst(&intel_encoder->base)->primary; + return port_to_aux_power_domain(intel_dig_port->port); + default: + WARN_ON_ONCE(1); + return POWER_DOMAIN_AUX_A; + } +} + static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d34e643..78b8ec8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -277,7 +277,7 @@ static void pps_lock(struct intel_dp *intel_dp) * See vlv_power_sequencer_reset() why we need * a power domain reference here. */ - power_domain = intel_display_port_power_domain(encoder); + power_domain = intel_display_port_aux_power_domain(encoder); intel_display_power_get(dev_priv, power_domain); mutex_lock(&dev_priv->pps_mutex); @@ -293,7 +293,7 @@ static void pps_unlock(struct intel_dp *intel_dp) mutex_unlock(&dev_priv->pps_mutex); - power_domain = intel_display_port_power_domain(encoder); + power_domain = intel_display_port_aux_power_domain(encoder); intel_display_power_put(dev_priv, power_domain); } @@ -816,8 +816,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, intel_dp_check_edp(intel_dp); - intel_aux_display_runtime_get(dev_priv); - /* Try to wait for any previous AUX channel activity */ for (try = 0; try < 3; try++) { status = I915_READ_NOTRACE(ch_ctl); @@ -926,7 +924,6 @@ done: ret = recv_bytes; out: pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE); - intel_aux_display_runtime_put(dev_priv); if (vdd) edp_panel_vdd_off(intel_dp, false); @@ -1784,7 +1781,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp) if (edp_have_panel_vdd(intel_dp)) return need_to_disable; - power_domain = intel_display_port_power_domain(intel_encoder); + power_domain = intel_display_port_aux_power_domain(intel_encoder); intel_display_power_get(dev_priv, power_domain); DRM_DEBUG_KMS("Turning eDP port %c VDD on\n", @@ -1874,7 +1871,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) if ((pp & POWER_TARGET_ON) == 0) intel_dp->last_power_cycle = jiffies; - power_domain = intel_display_port_power_domain(intel_encoder); + power_domain = intel_display_port_aux_power_domain(intel_encoder); intel_display_power_put(dev_priv, power_domain); } @@ -2025,7 +2022,7 @@ static void edp_panel_off(struct intel_dp *intel_dp) wait_panel_off(intel_dp); /* We got a reference when we enabled the VDD. */ - power_domain = intel_display_port_power_domain(intel_encoder); + power_domain = intel_display_port_aux_power_domain(intel_encoder); intel_display_power_put(dev_priv, power_domain); } @@ -4765,26 +4762,6 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->has_audio = false; } -static enum intel_display_power_domain -intel_dp_power_get(struct intel_dp *dp) -{ - struct intel_encoder *encoder = &dp_to_dig_port(dp)->base; - enum intel_display_power_domain power_domain; - - power_domain = intel_display_port_power_domain(encoder); - intel_display_power_get(to_i915(encoder->base.dev), power_domain); - - return power_domain; -} - -static void -intel_dp_power_put(struct intel_dp *dp, - enum intel_display_power_domain power_domain) -{ - struct intel_encoder *encoder = &dp_to_dig_port(dp)->base; - intel_display_power_put(to_i915(encoder->base.dev), power_domain); -} - static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { @@ -4808,7 +4785,8 @@ intel_dp_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; } - power_domain = intel_dp_power_get(intel_dp); + power_domain = intel_display_port_aux_power_domain(intel_encoder); + intel_display_power_get(to_i915(dev), power_domain); /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) @@ -4853,7 +4831,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) } out: - intel_dp_power_put(intel_dp, power_domain); + intel_display_power_put(to_i915(dev), power_domain); return status; } @@ -4862,6 +4840,7 @@ intel_dp_force(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base; + struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); enum intel_display_power_domain power_domain; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", @@ -4871,11 +4850,12 @@ intel_dp_force(struct drm_connector *connector) if (connector->status != connector_status_connected) return; - power_domain = intel_dp_power_get(intel_dp); + power_domain = intel_display_port_aux_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); intel_dp_set_edid(intel_dp); - intel_dp_power_put(intel_dp, power_domain); + intel_display_power_put(dev_priv, power_domain); if (intel_encoder->type != INTEL_OUTPUT_EDP) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; @@ -5091,7 +5071,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) * indefinitely. */ DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n"); - power_domain = intel_display_port_power_domain(&intel_dig_port->base); + power_domain = intel_display_port_aux_power_domain(&intel_dig_port->base); intel_display_power_get(dev_priv, power_domain); edp_panel_vdd_schedule_off(intel_dp); @@ -5173,7 +5153,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) port_name(intel_dig_port->port), long_hpd ? "long" : "short"); - power_domain = intel_display_port_power_domain(intel_encoder); + power_domain = intel_display_port_aux_power_domain(intel_encoder); intel_display_power_get(dev_priv, power_domain); if (long_hpd) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0598932..449c28a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1169,6 +1169,8 @@ void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); enum intel_display_power_domain intel_display_port_power_domain(struct intel_encoder *intel_encoder); +enum intel_display_power_domain +intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); -- cgit v0.10.2 From ac9b8236551d1177fd07b56aef9b565d1864420d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Nov 2015 18:55:26 +0200 Subject: drm/i915: Introduce a gmbus power domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the gmbus code uses intel_aux_display_runtime_get/put in an effort to make sure the hardware is powered up sufficiently for gmbus. That function only takes the runtime PM reference which on VLV/CHV/BXT is not enough. We need the disp2d/pipe-a well on VLV/CHV and power well 2 on BXT. So add a new power domnain for gmbus and kill off the now unused intel_aux_display_runtime_get/put. And change intel_hdmi_set_edid() to use the gmbus power domain too since that's all we need there. Also toss in a BUILD_BUG_ON() to catch problems if we run out of bits for power domains. We're already really close to the limit... [Patrik: Add gmbus string to debugfs output] Signed-off-by: Ville Syrjälä Reviewed-by: Patrik Jakobsson [Cherry-picked from drm-intel-next-queued f0ab43e6 (Imre)] Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1448643329-18675-3-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a3b22bd..8aab974 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2734,6 +2734,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "AUX_C"; case POWER_DOMAIN_AUX_D: return "AUX_D"; + case POWER_DOMAIN_GMBUS: + return "GMBUS"; case POWER_DOMAIN_INIT: return "INIT"; default: diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 95bb27d..a01e515 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -199,6 +199,7 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_B, POWER_DOMAIN_AUX_C, POWER_DOMAIN_AUX_D, + POWER_DOMAIN_GMBUS, POWER_DOMAIN_INIT, POWER_DOMAIN_NUM, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 449c28a..f2a1142 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1379,8 +1379,6 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); void intel_display_power_put(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); -void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); void intel_runtime_pm_get(struct drm_i915_private *dev_priv); void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv); void intel_runtime_pm_put(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9eafa19..0e5ce70 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1335,21 +1335,17 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct intel_encoder *intel_encoder = - &hdmi_to_dig_port(intel_hdmi)->base; - enum intel_display_power_domain power_domain; struct edid *edid = NULL; bool connected = false; - power_domain = intel_display_port_power_domain(intel_encoder); - intel_display_power_get(dev_priv, power_domain); + intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); if (force) edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); - intel_display_power_put(dev_priv, power_domain); + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); to_intel_connector(connector)->detect_edid = edid; if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 1369fc4..8324654 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -483,7 +483,7 @@ gmbus_xfer(struct i2c_adapter *adapter, int i = 0, inc, try = 0; int ret = 0; - intel_aux_display_runtime_get(dev_priv); + intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); mutex_lock(&dev_priv->gmbus_mutex); if (bus->force_bit) { @@ -595,7 +595,9 @@ timeout: out: mutex_unlock(&dev_priv->gmbus_mutex); - intel_aux_display_runtime_put(dev_priv); + + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); + return ret; } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index d89c1d0..7e23d65 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -362,6 +362,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUDIO) | \ BIT(POWER_DOMAIN_VGA) | \ + BIT(POWER_DOMAIN_GMBUS) | \ BIT(POWER_DOMAIN_INIT)) #define BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS ( \ BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ @@ -1483,6 +1484,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUX_D) | \ + BIT(POWER_DOMAIN_GMBUS) | \ BIT(POWER_DOMAIN_INIT)) #define HSW_DISPLAY_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \ @@ -1845,6 +1847,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) i915.disable_power_well = sanitize_disable_power_well_option(dev_priv, i915.disable_power_well); + BUILD_BUG_ON(POWER_DOMAIN_NUM > 31); + mutex_init(&power_domains->lock); /* @@ -2064,36 +2068,6 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) } /** - * intel_aux_display_runtime_get - grab an auxiliary power domain reference - * @dev_priv: i915 device instance - * - * This function grabs a power domain reference for the auxiliary power domain - * (for access to the GMBUS and DP AUX blocks) and ensures that it and all its - * parents are powered up. Therefore users should only grab a reference to the - * innermost power domain they need. - * - * Any power domain reference obtained by this function must have a symmetric - * call to intel_aux_display_runtime_put() to release the reference again. - */ -void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv) -{ - intel_runtime_pm_get(dev_priv); -} - -/** - * intel_aux_display_runtime_put - release an auxiliary power domain reference - * @dev_priv: i915 device instance - * - * This function drops the auxiliary power domain reference obtained by - * intel_aux_display_runtime_get() and might power down the corresponding - * hardware block right away if this is the last reference. - */ -void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv) -{ - intel_runtime_pm_put(dev_priv); -} - -/** * intel_runtime_pm_get - grab a runtime pm reference * @dev_priv: i915 device instance * -- cgit v0.10.2 From 88747f133b20e1a2b2f303a68c97ebca211eddc1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 27 Nov 2015 18:55:27 +0200 Subject: drm/i915/ddi: fix intel_display_port_aux_power_domain() after HDMI detect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to the current sharing of the DDI encoder between DP and HDMI connectors we can run the DP detection after the HDMI detection has already set the shared encoder's type. For now solve this keeping the current behavior and running the detection in this case too. For a proper solution Ville suggested to split the encoder into an HDMI and DP one, that can be done as a follow-up. This issue triggers the WARN in intel_display_port_aux_power_domain() and was introduced in: commit 25f78f58e5bfb46a270ce4d690fb49dc104558b1 Author: Ville Syrjälä Date: Mon Nov 16 15:01:04 2015 +0100 drm/i915: Clean up AUX power domain handling CC: Patrik Jakobsson CC: Ville Syrjälä Reviewed-by: Patrik Jakobsson [Cherry-picked from drm-intel-next-queued 651174a4 (Imre)] Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1448643329-18675-4-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 19915b1..ea03006 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5258,7 +5258,14 @@ intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder) switch (intel_encoder->type) { case INTEL_OUTPUT_UNKNOWN: - /* Only DDI platforms should ever use this output type */ + case INTEL_OUTPUT_HDMI: + /* + * Only DDI platforms should ever use these output types. + * We can get here after the HDMI detect code has already set + * the type of the shared encoder. Since we can't be sure + * what's the status of the given connectors, play safe and + * run the DP detection too. + */ WARN_ON_ONCE(!HAS_DDI(dev)); case INTEL_OUTPUT_DISPLAYPORT: case INTEL_OUTPUT_EDP: -- cgit v0.10.2 From 8e695444cba743253024ee31abb940778bd65c27 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 27 Nov 2015 18:55:28 +0200 Subject: drm/i915: add MISSING_CASE to a few port/aux power domain helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MISSING_CASE() would have been useful to track down a recent problem in intel_display_port_aux_power_domain(), so add it there and a few related helpers. This was also suggested by Ville in his review of the latest DMC/DC changes, we forgot to address that. Reviewed-by: Ville Syrjälä Reviewed-by: Patrik Jakobsson [Cherry-picked from drm-intel-next-queued b9fec167 (Imre)] Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1448643329-18675-5-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ea03006..22e86d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5194,7 +5194,7 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) case PORT_E: return POWER_DOMAIN_PORT_DDI_E_2_LANES; default: - WARN_ON_ONCE(1); + MISSING_CASE(port); return POWER_DOMAIN_PORT_OTHER; } } @@ -5214,7 +5214,7 @@ static enum intel_display_power_domain port_to_aux_power_domain(enum port port) /* FIXME: Check VBT for actual wiring of PORT E */ return POWER_DOMAIN_AUX_D; default: - WARN_ON_ONCE(1); + MISSING_CASE(port); return POWER_DOMAIN_AUX_A; } } @@ -5275,7 +5275,7 @@ intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder) intel_dig_port = enc_to_mst(&intel_encoder->base)->primary; return port_to_aux_power_domain(intel_dig_port->port); default: - WARN_ON_ONCE(1); + MISSING_CASE(intel_encoder->type); return POWER_DOMAIN_AUX_A; } } -- cgit v0.10.2 From 0f5a9be15797f78c9a34e432f26c796165b6e49a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 27 Nov 2015 18:55:29 +0200 Subject: drm/i915: take a power domain reference while checking the HDMI live status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are platforms that don't need the full GMBUS power domain (BXT) while others do (PCH, VLV/CHV). For optimizing this we would need to add a new power domain, but it's not clear how much we would benefit given the short time we hold the reference. So for now let's keep things simple. This fixes a regression introduced in commit 237ed86c693d8a8e4db476976aeb30df4deac74b Author: Sonika Jindal Date: Tue Sep 15 09:44:20 2015 +0530 drm/i915: Check live status before reading edid v2: - fix commit message, PCH won't take any redundant power resource after this change (Ville) Reviewed-by: Ville Syrjälä [fix commit message in v2 (Imre)] [Cherry-picked from drm-intel-next-queued 29bb94bb (Imre)] Signed-off-by: Imre Deak Link: http://patchwork.freedesktop.org/patch/msgid/1448643329-18675-6-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 0e5ce70..81cdd9f 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1379,6 +1379,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); + while (!live_status && --retry) { live_status = intel_digital_port_connected(dev_priv, hdmi_to_dig_port(intel_hdmi)); @@ -1398,6 +1400,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) } else status = connector_status_disconnected; + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); + return status; } -- cgit v0.10.2 From 83e4bf7a7486532df2dc3db27e0e07a250990ed2 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 30 Nov 2015 12:31:43 +0100 Subject: openvswitch: properly refcount vport-vxlan module After 614732eaa12d, no refcount is maintained for the vport-vxlan module. This allows the userspace to remove such module while vport-vxlan devices still exist, which leads to later oops. v1 -> v2: - move vport 'owner' initialization in ovs_vport_ops_register() and make such function a macro Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index efb736b..e41cd12 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -117,7 +117,6 @@ static struct vport_ops ovs_geneve_vport_ops = { .destroy = ovs_netdev_tunnel_destroy, .get_options = geneve_get_options, .send = dev_queue_xmit, - .owner = THIS_MODULE, }; static int __init ovs_geneve_tnl_init(void) diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index c3257d7..7f8897f 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -89,7 +89,6 @@ static struct vport_ops ovs_gre_vport_ops = { .create = gre_create, .send = dev_queue_xmit, .destroy = ovs_netdev_tunnel_destroy, - .owner = THIS_MODULE, }; static int __init ovs_gre_tnl_init(void) diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index e194c10a..31cbc8c 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -71,7 +71,7 @@ static struct hlist_head *hash_bucket(const struct net *net, const char *name) return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)]; } -int ovs_vport_ops_register(struct vport_ops *ops) +int __ovs_vport_ops_register(struct vport_ops *ops) { int err = -EEXIST; struct vport_ops *o; @@ -87,7 +87,7 @@ errout: ovs_unlock(); return err; } -EXPORT_SYMBOL_GPL(ovs_vport_ops_register); +EXPORT_SYMBOL_GPL(__ovs_vport_ops_register); void ovs_vport_ops_unregister(struct vport_ops *ops) { diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index bdfd82a..8ea3a96 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -196,7 +196,13 @@ static inline const char *ovs_vport_name(struct vport *vport) return vport->dev->name; } -int ovs_vport_ops_register(struct vport_ops *ops); +int __ovs_vport_ops_register(struct vport_ops *ops); +#define ovs_vport_ops_register(ops) \ + ({ \ + (ops)->owner = THIS_MODULE; \ + __ovs_vport_ops_register(ops); \ + }) + void ovs_vport_ops_unregister(struct vport_ops *ops); static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, -- cgit v0.10.2 From 30ce6e1cc5a0f781d60227e9096c86e188d2c2bd Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 23 Nov 2015 16:24:45 -0500 Subject: dm btree: fix leak of bufio-backed block in btree_split_sibling error path The block allocated at the start of btree_split_sibling() is never released if later insert_at() fails. Fix this by releasing the previously allocated bufio block using unlock_block(). Reported-by: Mikulas Patocka Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index c573402..0918a7c 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -473,8 +473,10 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index, r = insert_at(sizeof(__le64), pn, parent_index + 1, le64_to_cpu(rn->keys[0]), &location); - if (r) + if (r) { + unlock_block(s->info, right); return r; + } if (key < le64_to_cpu(rn->keys[0])) { unlock_block(s->info, right); -- cgit v0.10.2 From 993ceab91986e2e737ce9a3e23bebc8cce649240 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 2 Dec 2015 12:24:39 +0000 Subject: dm thin metadata: fix bug in dm_thin_remove_range() dm_btree_remove_leaves() only unmaps a contiguous region so we need a loop, in __remove_range(), to handle ranges that contain multiple regions. A new btree function, dm_btree_lookup_next(), is introduced which is more efficiently able to skip over regions of the thin device which aren't mapped. __remove_range() uses dm_btree_lookup_next() for each iteration of __remove_range()'s loop. Also, improve description of dm_btree_remove_leaves(). Fixes: 6550f075 ("dm thin metadata: add dm_thin_remove_range()") Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 4.1+ diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 1fa4569..67871e7 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1538,7 +1538,7 @@ static int __remove(struct dm_thin_device *td, dm_block_t block) static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end) { int r; - unsigned count; + unsigned count, total_count = 0; struct dm_pool_metadata *pmd = td->pmd; dm_block_t keys[1] = { td->id }; __le64 value; @@ -1561,11 +1561,29 @@ static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_ if (r) return r; - r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count); - if (r) - return r; + /* + * Remove leaves stops at the first unmapped entry, so we have to + * loop round finding mapped ranges. + */ + while (begin < end) { + r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value); + if (r == -ENODATA) + break; + + if (r) + return r; + + if (begin >= end) + break; + + r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count); + if (r) + return r; + + total_count += count; + } - td->mapped_blocks -= count; + td->mapped_blocks -= total_count; td->changed = 1; /* diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index 0918a7c..7e5b7f1 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -63,6 +63,11 @@ int lower_bound(struct btree_node *n, uint64_t key) return bsearch(n, key, 0); } +static int upper_bound(struct btree_node *n, uint64_t key) +{ + return bsearch(n, key, 1); +} + void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, struct dm_btree_value_type *vt) { @@ -392,6 +397,82 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root, } EXPORT_SYMBOL_GPL(dm_btree_lookup); +static int dm_btree_lookup_next_single(struct dm_btree_info *info, dm_block_t root, + uint64_t key, uint64_t *rkey, void *value_le) +{ + int r, i; + uint32_t flags, nr_entries; + struct dm_block *node; + struct btree_node *n; + + r = bn_read_lock(info, root, &node); + if (r) + return r; + + n = dm_block_data(node); + flags = le32_to_cpu(n->header.flags); + nr_entries = le32_to_cpu(n->header.nr_entries); + + if (flags & INTERNAL_NODE) { + i = lower_bound(n, key); + if (i < 0 || i >= nr_entries) { + r = -ENODATA; + goto out; + } + + r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); + if (r == -ENODATA && i < (nr_entries - 1)) { + i++; + r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); + } + + } else { + i = upper_bound(n, key); + if (i < 0 || i >= nr_entries) { + r = -ENODATA; + goto out; + } + + *rkey = le64_to_cpu(n->keys[i]); + memcpy(value_le, value_ptr(n, i), info->value_type.size); + } +out: + dm_tm_unlock(info->tm, node); + return r; +} + +int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root, + uint64_t *keys, uint64_t *rkey, void *value_le) +{ + unsigned level; + int r = -ENODATA; + __le64 internal_value_le; + struct ro_spine spine; + + init_ro_spine(&spine, info); + for (level = 0; level < info->levels - 1u; level++) { + r = btree_lookup_raw(&spine, root, keys[level], + lower_bound, rkey, + &internal_value_le, sizeof(uint64_t)); + if (r) + goto out; + + if (*rkey != keys[level]) { + r = -ENODATA; + goto out; + } + + root = le64_to_cpu(internal_value_le); + } + + r = dm_btree_lookup_next_single(info, root, keys[level], rkey, value_le); +out: + exit_ro_spine(&spine); + return r; +} + +EXPORT_SYMBOL_GPL(dm_btree_lookup_next); + /* * Splits a node by creating a sibling node and shifting half the nodes * contents across. Assumes there is a parent node, and it has room for diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h index 11d8cf7..c74301f 100644 --- a/drivers/md/persistent-data/dm-btree.h +++ b/drivers/md/persistent-data/dm-btree.h @@ -110,6 +110,13 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root, uint64_t *keys, void *value_le); /* + * Tries to find the first key where the bottom level key is >= to that + * given. Useful for skipping empty sections of the btree. + */ +int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root, + uint64_t *keys, uint64_t *rkey, void *value_le); + +/* * Insertion (or overwrite an existing value). O(ln(n)) */ int dm_btree_insert(struct dm_btree_info *info, dm_block_t root, @@ -135,9 +142,10 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, uint64_t *keys, dm_block_t *new_root); /* - * Removes values between 'keys' and keys2, where keys2 is keys with the - * final key replaced with 'end_key'. 'end_key' is the one-past-the-end - * value. 'keys' may be altered. + * Removes a _contiguous_ run of values starting from 'keys' and not + * reaching keys2 (where keys2 is keys with the final key replaced with + * 'end_key'). 'end_key' is the one-past-the-end value. 'keys' may be + * altered. */ int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root, uint64_t *keys, uint64_t end_key, -- cgit v0.10.2 From e619e6cbecb7fe97a924d625e848605333457b13 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 20 Nov 2015 14:11:01 -0800 Subject: Revert "scsi: Fix a bdi reregistration race" The SCSI sd driver probes SCSI devices asynchronously. The sd_remove() function, called indirectly by device_del(), waits until asynchronous probing has finished. Since the block layer queue must only be cleaned up after probing has finished, device_del() has to be called before blk_cleanup_queue(). Hence revert commit bf2cf3baa20b. Signed-off-by: Bart Van Assche Cc: Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8d23122..f5ace2b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1110,7 +1110,9 @@ void __scsi_remove_device(struct scsi_device *sdev) device_unregister(&sdev->sdev_dev); transport_remove_device(dev); scsi_dh_remove_device(sdev); - } + device_del(dev); + } else + put_device(&sdev->sdev_dev); /* * Stop accepting new requests and wait until all queuecommand() and @@ -1121,16 +1123,6 @@ void __scsi_remove_device(struct scsi_device *sdev) blk_cleanup_queue(sdev->request_queue); cancel_work_sync(&sdev->requeue_work); - /* - * Remove the device after blk_cleanup_queue() has been called such - * a possible bdi_register() call with the same name occurs after - * blk_cleanup_queue() has called bdi_destroy(). - */ - if (sdev->is_visible) - device_del(dev); - else - put_device(&sdev->sdev_dev); - if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); -- cgit v0.10.2 From e2f784fa8a3b1fbf6999ba44f7327bd9d29f2c5b Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Thu, 26 Nov 2015 16:33:58 +0800 Subject: drm/amdgpu: add err check for pin userptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missing error check if the operation failed. Signed-off-by: Chunming Zhou Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index d4bac5f..8051cb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -587,9 +587,13 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm, uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem); int r; - if (gtt->userptr) - amdgpu_ttm_tt_pin_userptr(ttm); - + if (gtt->userptr) { + r = amdgpu_ttm_tt_pin_userptr(ttm); + if (r) { + DRM_ERROR("failed to pin userptr\n"); + return r; + } + } gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); if (!ttm->num_pages) { WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", -- cgit v0.10.2 From 07df04dfcfe51a45239d056d43cbc09702262c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Wed, 2 Dec 2015 17:35:12 +0100 Subject: drm/amdgpu: fix race condition in amd_sched_entity_push_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As soon as we leave the spinlock after the job has been added to the job queue, we can no longer rely on the job's data to be available. I have seen a null-pointer dereference due to sched == NULL in amd_sched_wakeup via amd_sched_entity_push_job and amd_sched_ib_submit_kernel_helper. Since the latter initializes sched_job->sched with the address of the ring scheduler, which is guaranteed to be non-NULL, this race appears to be a likely culprit. Signed-off-by: Nicolai Hähnle Bugzilla: https://bugs.freedesktop.org/attachment.cgi?bugid=93079 Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 651129f..3a4820e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -288,6 +288,7 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity) */ static bool amd_sched_entity_in(struct amd_sched_job *sched_job) { + struct amd_gpu_scheduler *sched = sched_job->sched; struct amd_sched_entity *entity = sched_job->s_entity; bool added, first = false; @@ -302,7 +303,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job) /* first job wakes up scheduler */ if (first) - amd_sched_wakeup(sched_job->sched); + amd_sched_wakeup(sched); return added; } @@ -318,9 +319,9 @@ void amd_sched_entity_push_job(struct amd_sched_job *sched_job) { struct amd_sched_entity *entity = sched_job->s_entity; + trace_amd_sched_job(sched_job); wait_event(entity->sched->job_scheduled, amd_sched_entity_in(sched_job)); - trace_amd_sched_job(sched_job); } /** -- cgit v0.10.2 From 723cda5b055851f5e8bf61aacd8008c43c99e801 Mon Sep 17 00:00:00 2001 From: Thanneeru Srinivasulu Date: Wed, 2 Dec 2015 15:36:13 +0530 Subject: net: thunderx: Force to load octeon-mdio before bgx driver. Signed-off-by: Thanneeru Srinivasulu Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 180aa9f..2574a7e 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1009,6 +1009,9 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct bgx *bgx = NULL; u8 lmac; + /* Load octeon mdio driver */ + octeon_mdiobus_force_mod_depencency(); + bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL); if (!bgx) return -ENOMEM; diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index 07b7ec66..89a02fa 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -182,6 +182,7 @@ enum MCAST_MODE { #define BCAST_ACCEPT 1 #define CAM_ACCEPT 1 +void octeon_mdiobus_force_mod_depencency(void); void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac); unsigned bgx_get_map(int node); int bgx_get_lmac_count(int node, int bgx); -- cgit v0.10.2 From a7b1f535a8d45816cfe25c0fd900fc726ba5acce Mon Sep 17 00:00:00 2001 From: Thanneeru Srinivasulu Date: Wed, 2 Dec 2015 15:36:14 +0530 Subject: net: thunderx: Wait for delayed work to finish before destroying it While VNIC or BGX driver teardown, wait for already scheduled delayed work to finish before destroying it. Signed-off-by: Thanneeru Srinivasulu Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index c561fdc..cfc24a1 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -1074,8 +1074,7 @@ static void nic_remove(struct pci_dev *pdev) if (nic->check_link) { /* Destroy work Queue */ - cancel_delayed_work(&nic->dwork); - flush_workqueue(nic->check_link); + cancel_delayed_work_sync(&nic->dwork); destroy_workqueue(nic->check_link); } diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 2574a7e..6534b73 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -695,8 +695,7 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid) lmac = &bgx->lmac[lmacid]; if (lmac->check_link) { /* Destroy work queue */ - cancel_delayed_work(&lmac->dwork); - flush_workqueue(lmac->check_link); + cancel_delayed_work_sync(&lmac->dwork); destroy_workqueue(lmac->check_link); } -- cgit v0.10.2 From 006394a7cb20559418c602b8433ec1839b6fc1d3 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 2 Dec 2015 15:36:15 +0530 Subject: net: thunderx: Set CQ timer threshold properly Properly set CQ timer threshold and also set it to 2us. With previous incorrect settings it was set to 0.5us which is too less. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index d3950b2..39ca674 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -120,10 +120,9 @@ * Calculated for SCLK of 700Mhz * value written should be a 1/16th of what is expected * - * 1 tick per 0.05usec = value of 2.2 - * This 10% would be covered in CQ timer thresh value + * 1 tick per 0.025usec */ -#define NICPF_CLK_PER_INT_TICK 2 +#define NICPF_CLK_PER_INT_TICK 1 /* Time to wait before we decide that a SQ is stuck. * diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index e404ea8..206b6a7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -592,7 +592,7 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs, /* Set threshold value for interrupt generation */ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh); nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2, - qidx, nic->cq_coalesce_usecs); + qidx, CMP_QUEUE_TIMER_THRESH); } /* Configures transmit queue */ diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index fb4957d..033e830 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -76,7 +76,7 @@ #define CMP_QSIZE CMP_QUEUE_SIZE2 #define CMP_QUEUE_LEN (1ULL << (CMP_QSIZE + 10)) #define CMP_QUEUE_CQE_THRESH 0 -#define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */ +#define CMP_QUEUE_TIMER_THRESH 80 /* ~2usec */ #define RBDR_SIZE RBDR_SIZE0 #define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13)) -- cgit v0.10.2 From 0b72a9a1060e7547e71e7f600849a2d3006bf63a Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 2 Dec 2015 15:36:16 +0530 Subject: net: thunderx: Switchon carrier only upon interface link up Call netif_carrier_on() only if interface's link is up. Switching this on upon IFF_UP by default, is causing issues with ethernet channel bonding in LACP mode. Initial NETDEV_CHANGE notification was being skipped. Also fixed some issues with link/speed/duplex reporting via ethtool. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index af54c10..a12b2e3 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c @@ -112,6 +112,13 @@ static int nicvf_get_settings(struct net_device *netdev, cmd->supported = 0; cmd->transceiver = XCVR_EXTERNAL; + + if (!nic->link_up) { + cmd->duplex = DUPLEX_UNKNOWN; + ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); + return 0; + } + if (nic->speed <= 1000) { cmd->port = PORT_MII; cmd->autoneg = AUTONEG_ENABLE; @@ -125,6 +132,13 @@ static int nicvf_get_settings(struct net_device *netdev, return 0; } +static u32 nicvf_get_link(struct net_device *netdev) +{ + struct nicvf *nic = netdev_priv(netdev); + + return nic->link_up; +} + static void nicvf_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { @@ -660,7 +674,7 @@ static int nicvf_set_channels(struct net_device *dev, static const struct ethtool_ops nicvf_ethtool_ops = { .get_settings = nicvf_get_settings, - .get_link = ethtool_op_get_link, + .get_link = nicvf_get_link, .get_drvinfo = nicvf_get_drvinfo, .get_msglevel = nicvf_get_msglevel, .set_msglevel = nicvf_set_msglevel, diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 7f709cb..dde8dc7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1057,6 +1057,7 @@ int nicvf_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_tx_stop_all_queues(nic->netdev); + nic->link_up = false; /* Teardown secondary qsets first */ if (!nic->sqs_mode) { @@ -1211,9 +1212,6 @@ int nicvf_open(struct net_device *netdev) nic->drv_stats.txq_stop = 0; nic->drv_stats.txq_wake = 0; - netif_carrier_on(netdev); - netif_tx_start_all_queues(netdev); - return 0; cleanup: nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0); diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 6534b73..d77e41a 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -612,6 +612,8 @@ static void bgx_poll_for_link(struct work_struct *work) lmac->last_duplex = 1; } else { lmac->link_up = 0; + lmac->last_speed = SPEED_UNKNOWN; + lmac->last_duplex = DUPLEX_UNKNOWN; } if (lmac->last_link != lmac->link_up) { -- cgit v0.10.2 From bc69fdfc6c13b7350be9bcb48328d8f231ed98bb Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Wed, 2 Dec 2015 15:36:17 +0530 Subject: net: thunderx: Enable BGX LMAC's RX/TX only after VF is up Enable or disable BGX LMAC's RX/TX based on corresponding VF's status. If otherwise, when multiple LMAC's physical link is up then packets from all LMAC's whose corresponding VF is not yet initialized will get forwarded to VF0. This is due to VNIC's default configuration where CPI, RSSI e.t.c point to VF0/QSET0/RQ0. This patch will prevent multiple copies of packets on VF0. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index cfc24a1..4b7fd63 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -37,6 +37,7 @@ struct nicpf { #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) #define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) u8 vf_lmac_map[MAX_LMAC]; + u8 lmac_cnt; struct delayed_work dwork; struct workqueue_struct *check_link; u8 link[MAX_LMAC]; @@ -279,6 +280,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic) u64 lmac_credit; nic->num_vf_en = 0; + nic->lmac_cnt = 0; for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) { if (!(bgx_map & (1 << bgx))) @@ -288,6 +290,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic) nic->vf_lmac_map[next_bgx_lmac++] = NIC_SET_VF_LMAC_MAP(bgx, lmac); nic->num_vf_en += lmac_cnt; + nic->lmac_cnt += lmac_cnt; /* Program LMAC credits */ lmac_credit = (1ull << 1); /* channel credit enable */ @@ -715,6 +718,13 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) case NIC_MBOX_MSG_CFG_DONE: /* Last message of VF config msg sequence */ nic->vf_enabled[vf] = true; + if (vf >= nic->lmac_cnt) + goto unlock; + + bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + + bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, true); goto unlock; case NIC_MBOX_MSG_SHUTDOWN: /* First msg in VF teardown sequence */ @@ -722,6 +732,14 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) if (vf >= nic->num_vf_en) nic->sqs_used[vf - nic->num_vf_en] = false; nic->pqs_vf[vf] = 0; + + if (vf >= nic->lmac_cnt) + break; + + bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + + bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, false); break; case NIC_MBOX_MSG_ALLOC_SQS: nic_alloc_sqs(nic, &mbx.sqs_alloc); @@ -940,7 +958,7 @@ static void nic_poll_for_link(struct work_struct *work) mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; - for (vf = 0; vf < nic->num_vf_en; vf++) { + for (vf = 0; vf < nic->lmac_cnt; vf++) { /* Poll only if VF is UP */ if (!nic->vf_enabled[vf]) continue; diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index d77e41a..9df26c2 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -186,6 +186,23 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac) } EXPORT_SYMBOL(bgx_set_lmac_mac); +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) +{ + struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx]; + u64 cfg; + + if (!bgx) + return; + + cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG); + if (enable) + cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN; + else + cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN); + bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg); +} +EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); + static void bgx_sgmii_change_link_state(struct lmac *lmac) { struct bgx *bgx = lmac->bgx; @@ -656,8 +673,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) } /* Enable lmac */ - bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, - CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN); + bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN); /* Restore default cfg, incase low level firmware changed it */ bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03); diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index 89a02fa..149e179 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -183,6 +183,7 @@ enum MCAST_MODE { #define CAM_ACCEPT 1 void octeon_mdiobus_force_mod_depencency(void); +void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable); void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac); unsigned bgx_get_map(int node); int bgx_get_lmac_count(int node, int bgx); -- cgit v0.10.2 From 835112b28919d88d989a0a9313e323ad82e18b59 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 17 Nov 2015 10:24:40 +0200 Subject: mac80211: don't teardown sdata on sdata stop Interfaces are being initialized (setup) on addition, and torn down on removal. However, p2p device is being torn down when stopped, resulting in the next p2p start operation being done on uninitialized interface. Solve it by calling ieee80211_teardown_sdata() only on interface removal (for the non-netdev case). Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach [squashed in fix to call teardown after unregister] Signed-off-by: Johannes Berg diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 53ee049..c9e325d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1862,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) unregister_netdevice(sdata->dev); } else { cfg80211_unregister_wdev(&sdata->wdev); + ieee80211_teardown_sdata(sdata); kfree(sdata); } } @@ -1871,7 +1872,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state))) return; ieee80211_do_stop(sdata, true); - ieee80211_teardown_sdata(sdata); } void ieee80211_remove_interfaces(struct ieee80211_local *local) -- cgit v0.10.2 From 4e39ccac0d678eacb5dd6ffc5057531af33c12d6 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 21 Nov 2015 18:13:40 +0800 Subject: mac80211: do not actively scan DFS channels DFS channels should not be actively scanned as we can't be sure if we are allowed or not. If the current channel is in the DFS band, active scan might be performed after CSA, but we have no guarantee about other channels, therefore it is safer to prevent active scanning at all. Cc: stable@vger.kernel.org Signed-off-by: Antonio Quartulli Signed-off-by: Johannes Berg diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4aeca4b..a413e52 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -597,8 +597,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, /* We need to ensure power level is at max for scanning. */ ieee80211_hw_config(local, 0); - if ((req->channels[0]->flags & - IEEE80211_CHAN_NO_IR) || + if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR | + IEEE80211_CHAN_RADAR)) || !req->n_ssids) { next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; } else { @@ -645,7 +645,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) * TODO: channel switching also consumes quite some time, * add that delay as well to get a better estimation */ - if (chan->flags & IEEE80211_CHAN_NO_IR) + if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) return IEEE80211_PASSIVE_CHANNEL_TIME; return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; } @@ -777,7 +777,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, * * In any case, it is not necessary for a passive scan. */ - if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) { + if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) || + !scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; return; -- cgit v0.10.2 From c1df932c0574c13ab3ce72e969c9647ff3aaad68 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Nov 2015 21:59:41 +0100 Subject: mac80211: fix off-channel mgmt-tx uninitialized variable usage In the last change here, I neglected to update the cookie in one code path: when a mgmt-tx has no real cookie sent to userspace as it doesn't wait for a response, but is off-channel. The original code used the SKB pointer as the cookie and always assigned the cookie to the TX SKB in ieee80211_start_roc_work(), but my change turned this around and made the code rely on a valid cookie being passed in. Unfortunately, the off-channel no-wait TX path wasn't assigning one at all, resulting in an uninitialized stack value being used. This wasn't handed back to userspace as a cookie (since in the no-wait case there isn't a cookie), but it was tested for non-zero to distinguish between mgmt-tx and off-channel. Fix this by assigning a dummy non-zero cookie unconditionally, and get rid of a misleading comment and some dead code while at it. I'll clean up the ACK SKB handling separately later. Fixes: 3b79af973cf4 ("mac80211: stop using pointers as userspace cookies") Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c2bd1b6..da471ee 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3454,8 +3454,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, goto out_unlock; } } else { - /* for cookie below */ - ack_skb = skb; + /* Assign a dummy non-zero cookie, it's not sent to + * userspace in this case but we rely on its value + * internally in the need_offchan case to distinguish + * mgmt-tx from remain-on-channel. + */ + *cookie = 0xffffffff; } if (!need_offchan) { -- cgit v0.10.2 From 69030dd1c3671625c6f766af0b64a4bb4409ac3b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 1 Dec 2015 16:52:14 -0800 Subject: cpufreq: use last policy after online for drivers with ->setpolicy For cpufreq drivers which use setpolicy interface, after offline->online the policy is set to default. This can be reproduced by setting the default policy of intel_pstate or longrun to ondemand and then change to "performance". After offline and online, the setpolicy will be called with the policy=ondemand. For drivers using governors this condition is handled by storing last_governor, during offline and restoring during online. The same should be done for drivers using setpolicy interface. Storing last_policy during offline and restoring during online. Signed-off-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a83c995..8412ce5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -976,10 +976,14 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy) new_policy.governor = gov; - /* Use the default policy if its valid. */ - if (cpufreq_driver->setpolicy) - cpufreq_parse_governor(gov->name, &new_policy.policy, NULL); - + /* Use the default policy if there is no last_policy. */ + if (cpufreq_driver->setpolicy) { + if (policy->last_policy) + new_policy.policy = policy->last_policy; + else + cpufreq_parse_governor(gov->name, &new_policy.policy, + NULL); + } /* set default policy */ return cpufreq_set_policy(policy, &new_policy); } @@ -1330,6 +1334,8 @@ static void cpufreq_offline_prepare(unsigned int cpu) if (has_target()) strncpy(policy->last_governor, policy->governor->name, CPUFREQ_NAME_LEN); + else + policy->last_policy = policy->policy; } else if (cpu == policy->cpu) { /* Nominate new CPU */ policy->cpu = cpumask_any(policy->cpus); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index ef4c5b1..177c768 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -77,6 +77,7 @@ struct cpufreq_policy { unsigned int suspend_freq; /* freq to set during suspend */ unsigned int policy; /* see above */ + unsigned int last_policy; /* policy before unplug */ struct cpufreq_governor *governor; /* see below */ void *governor_data; bool governor_enabled; /* governor start/stop flag */ -- cgit v0.10.2 From db6ba9a5371f173489df126739d0a1c2a50f347b Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:41 +0100 Subject: net: mvneta: add configuration for MBUS windows access protection This commit adds missing configuration of MBUS windows access protection in mvneta_conf_mbus_windows function - a dedicated variable for that purpose remained there unused since v3.8 initial mvneta support. Because of that the register contents were inherited from the bootloader. Signed-off-by: Marcin Wojtas Reviewed-by: Gregory CLEMENT Fixes: c5aff18204da ("net: mvneta: driver for Marvell Armada 370/XP network unit") Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e84c7f2..2d80256 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -62,6 +62,7 @@ #define MVNETA_WIN_SIZE(w) (0x2204 + ((w) << 3)) #define MVNETA_WIN_REMAP(w) (0x2280 + ((w) << 2)) #define MVNETA_BASE_ADDR_ENABLE 0x2290 +#define MVNETA_ACCESS_PROTECT_ENABLE 0x2294 #define MVNETA_PORT_CONFIG 0x2400 #define MVNETA_UNI_PROMISC_MODE BIT(0) #define MVNETA_DEF_RXQ(q) ((q) << 1) @@ -3191,6 +3192,7 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp, } mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable); + mvreg_write(pp, MVNETA_ACCESS_PROTECT_ENABLE, win_protect); } /* Power up the port */ -- cgit v0.10.2 From e5bdf689d32fcf3aaf548c71e715b303ba20b5d1 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:42 +0100 Subject: net: mvneta: fix bit assignment in MVNETA_RXQ_CONFIG_REG MVNETA_RXQ_HW_BUF_ALLOC bit which controls enabling hardware buffer allocation was mistakenly set as BIT(1). This commit fixes the assignment. Signed-off-by: Marcin Wojtas Reviewed-by: Gregory CLEMENT Fixes: c5aff18204da ("net: mvneta: driver for Marvell Armada 370/XP network unit") Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 2d80256..64c46f0 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -36,7 +36,7 @@ /* Registers */ #define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2)) -#define MVNETA_RXQ_HW_BUF_ALLOC BIT(1) +#define MVNETA_RXQ_HW_BUF_ALLOC BIT(0) #define MVNETA_RXQ_PKT_OFFSET_ALL_MASK (0xf << 8) #define MVNETA_RXQ_PKT_OFFSET_MASK(offs) ((offs) << 8) #define MVNETA_RXQ_THRESHOLD_REG(q) (0x14c0 + ((q) << 2)) -- cgit v0.10.2 From dc1aadf6f1e7609590fadf7a0252413732289b2e Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:43 +0100 Subject: net: mvneta: fix bit assignment for RX packet irq enable A value originally defined in the driver was inappropriate. Even though the ingress was somehow working, writing MVNETA_RXQ_INTR_ENABLE_ALL_MASK to MVNETA_INTR_ENABLE didn't make any effect, because the bits [31:16] are reserved and read-only. This commit updates MVNETA_RXQ_INTR_ENABLE_ALL_MASK to be compliant with the controller's documentation. Signed-off-by: Marcin Wojtas Fixes: c5aff18204da ("net: mvneta: driver for Marvell Armada 370/XP network unit") Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 64c46f0..5dffb683 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -160,7 +160,7 @@ #define MVNETA_INTR_ENABLE 0x25b8 #define MVNETA_TXQ_INTR_ENABLE_ALL_MASK 0x0000ff00 -#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 // note: neta says it's 0x000000FF +#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0x000000ff #define MVNETA_RXQ_CMD 0x2680 #define MVNETA_RXQ_DISABLE_SHIFT 8 -- cgit v0.10.2 From 26c17a179f3f64f92de6e837c14279a6431a7ab6 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:44 +0100 Subject: net: mvneta: fix error path for building skb In the actual RX processing, there is same error path for both descriptor ring refilling and building skb fails. This is not correct, because after successful refill, the ring is already updated with newly allocated buffer. Then, in case of build_skb() fail, hitherto code left the original buffer unmapped. This patch fixes above situation by swapping error check of skb build with DMA-unmap of original buffer. Signed-off-by: Marcin Wojtas Acked-by: Simon Guinot Cc: # v4.2+ Fixes a84e32894191 ("net: mvneta: fix refilling for Rx DMA buffers") Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 5dffb683..5a98c5d 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1580,12 +1580,16 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo, } skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size); - if (!skb) - goto err_drop_frame; + /* After refill old buffer has to be unmapped regardless + * the skb is successfully built or not. + */ dma_unmap_single(dev->dev.parent, phys_addr, MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE); + if (!skb) + goto err_drop_frame; + rcvd_pkts++; rcvd_bytes += rx_bytes; -- cgit v0.10.2 From 9110ee07762a8f04835878863be2449362c63508 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:45 +0100 Subject: net: mvneta: enable setting custom TX IP checksum limit Since Armada 38x SoC can support IP checksum for jumbo frames only on a single port, it means that this feature should be enabled per-port, rather than for the whole SoC. This patch enables setting custom TX IP checksum limit by adding new optional property to the mvneta device tree node. If not used, by default 1600B is set for "marvell,armada-370-neta" and 9800B for other strings, which ensures backward compatibility. Binding documentation is updated accordingly. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt index f5a8ca2..aeea50c 100644 --- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt +++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt @@ -8,6 +8,11 @@ Required properties: - phy-mode: See ethernet.txt file in the same directory - clocks: a pointer to the reference clock for this device. +Optional properties: +- tx-csum-limit: maximum mtu supported by port that allow TX checksum. + Value is presented in bytes. If not used, by default 1600B is set for + "marvell,armada-370-neta" and 9800B for others. + Example: ethernet@d0070000 { @@ -15,6 +20,7 @@ ethernet@d0070000 { reg = <0xd0070000 0x2500>; interrupts = <8>; clocks = <&gate_clk 4>; + tx-csum-limit = <9800> status = "okay"; phy = <&phy0>; phy-mode = "rgmii-id"; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 5a98c5d..ed622fa 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -243,6 +243,7 @@ #define MVNETA_VLAN_TAG_LEN 4 #define MVNETA_CPU_D_CACHE_LINE_SIZE 32 +#define MVNETA_TX_CSUM_DEF_SIZE 1600 #define MVNETA_TX_CSUM_MAX_SIZE 9800 #define MVNETA_ACC_MODE_EXT 1 @@ -3256,6 +3257,7 @@ static int mvneta_probe(struct platform_device *pdev) char hw_mac_addr[ETH_ALEN]; const char *mac_from; const char *managed; + int tx_csum_limit; int phy_mode; int err; int cpu; @@ -3356,8 +3358,21 @@ static int mvneta_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(dn, "marvell,armada-370-neta")) - pp->tx_csum_limit = 1600; + if (!of_property_read_u32(dn, "tx-csum-limit", &tx_csum_limit)) { + if (tx_csum_limit < 0 || + tx_csum_limit > MVNETA_TX_CSUM_MAX_SIZE) { + tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE; + dev_info(&pdev->dev, + "Wrong TX csum limit in DT, set to %dB\n", + MVNETA_TX_CSUM_DEF_SIZE); + } + } else if (of_device_is_compatible(dn, "marvell,armada-370-neta")) { + tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE; + } else { + tx_csum_limit = MVNETA_TX_CSUM_MAX_SIZE; + } + + pp->tx_csum_limit = tx_csum_limit; pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; -- cgit v0.10.2 From c4a25007cfccbf19e6481885af378bca5e681683 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 30 Nov 2015 13:27:46 +0100 Subject: mvebu: dts: enable IP checksum with jumbo frames for Armada 38x on Port0 The Ethernet controller found in the Armada 38x SoC's family support TCP/IP checksumming with frame sizes larger than 1600 bytes, however only on port 0. This commit enables it by setting 'tx-csum-limit' to 9800B in 'ethernet@70000' node. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index c6a0e9d..e8b7f67 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -498,6 +498,7 @@ reg = <0x70000 0x4000>; interrupts-extended = <&mpic 8>; clocks = <&gateclk 4>; + tx-csum-limit = <9800>; status = "disabled"; }; -- cgit v0.10.2 From 01b3f52157ff5a47d6d8d796f396a4b34a53c61d Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Sun, 29 Nov 2015 16:59:35 -0800 Subject: bpf: fix allocation warnings in bpf maps and integer overflow For large map->value_size the user space can trigger memory allocation warnings like: WARNING: CPU: 2 PID: 11122 at mm/page_alloc.c:2989 __alloc_pages_nodemask+0x695/0x14e0() Call Trace: [< inline >] __dump_stack lib/dump_stack.c:15 [] dump_stack+0x68/0x92 lib/dump_stack.c:50 [] warn_slowpath_common+0xd9/0x140 kernel/panic.c:460 [] warn_slowpath_null+0x29/0x30 kernel/panic.c:493 [< inline >] __alloc_pages_slowpath mm/page_alloc.c:2989 [] __alloc_pages_nodemask+0x695/0x14e0 mm/page_alloc.c:3235 [] alloc_pages_current+0xee/0x340 mm/mempolicy.c:2055 [< inline >] alloc_pages include/linux/gfp.h:451 [] alloc_kmem_pages+0x16/0xf0 mm/page_alloc.c:3414 [] kmalloc_order+0x19/0x60 mm/slab_common.c:1007 [] kmalloc_order_trace+0x1f/0xa0 mm/slab_common.c:1018 [< inline >] kmalloc_large include/linux/slab.h:390 [] __kmalloc+0x234/0x250 mm/slub.c:3525 [< inline >] kmalloc include/linux/slab.h:463 [< inline >] map_update_elem kernel/bpf/syscall.c:288 [< inline >] SYSC_bpf kernel/bpf/syscall.c:744 To avoid never succeeding kmalloc with order >= MAX_ORDER check that elem->value_size and computed elem_size are within limits for both hash and array type maps. Also add __GFP_NOWARN to kmalloc(value_size | elem_size) to avoid OOM warnings. Note kmalloc(key_size) is highly unlikely to trigger OOM, since key_size <= 512, so keep those kmalloc-s as-is. Large value_size can cause integer overflows in elem_size and map.pages formulas, so check for that as well. Fixes: aaac3ba95e4c ("bpf: charge user for creation of BPF maps and programs") Reported-by: Dmitry Vyukov Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 4c67ce3..b0799bc 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -28,11 +28,17 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) attr->value_size == 0) return ERR_PTR(-EINVAL); + if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1)) + /* if value_size is bigger, the user space won't be able to + * access the elements. + */ + return ERR_PTR(-E2BIG); + elem_size = round_up(attr->value_size, 8); /* check round_up into zero and u32 overflow */ if (elem_size == 0 || - attr->max_entries > (U32_MAX - sizeof(*array)) / elem_size) + attr->max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size) return ERR_PTR(-ENOMEM); array_size = sizeof(*array) + attr->max_entries * elem_size; diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 19909b2..34777b3 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -64,12 +64,35 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) */ goto free_htab; - err = -ENOMEM; + if (htab->map.value_size >= (1 << (KMALLOC_SHIFT_MAX - 1)) - + MAX_BPF_STACK - sizeof(struct htab_elem)) + /* if value_size is bigger, the user space won't be able to + * access the elements via bpf syscall. This check also makes + * sure that the elem_size doesn't overflow and it's + * kmalloc-able later in htab_map_update_elem() + */ + goto free_htab; + + htab->elem_size = sizeof(struct htab_elem) + + round_up(htab->map.key_size, 8) + + htab->map.value_size; + /* prevent zero size kmalloc and check for u32 overflow */ if (htab->n_buckets == 0 || htab->n_buckets > U32_MAX / sizeof(struct hlist_head)) goto free_htab; + if ((u64) htab->n_buckets * sizeof(struct hlist_head) + + (u64) htab->elem_size * htab->map.max_entries >= + U32_MAX - PAGE_SIZE) + /* make sure page count doesn't overflow */ + goto free_htab; + + htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) + + htab->elem_size * htab->map.max_entries, + PAGE_SIZE) >> PAGE_SHIFT; + + err = -ENOMEM; htab->buckets = kmalloc_array(htab->n_buckets, sizeof(struct hlist_head), GFP_USER | __GFP_NOWARN); @@ -85,13 +108,6 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) raw_spin_lock_init(&htab->lock); htab->count = 0; - htab->elem_size = sizeof(struct htab_elem) + - round_up(htab->map.key_size, 8) + - htab->map.value_size; - - htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) + - htab->elem_size * htab->map.max_entries, - PAGE_SIZE) >> PAGE_SHIFT; return &htab->map; free_htab: @@ -222,7 +238,7 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value, WARN_ON_ONCE(!rcu_read_lock_held()); /* allocate new element outside of lock */ - l_new = kmalloc(htab->elem_size, GFP_ATOMIC); + l_new = kmalloc(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN); if (!l_new) return -ENOMEM; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4a8f3c1..3b39550 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -240,7 +240,7 @@ static int map_lookup_elem(union bpf_attr *attr) goto free_key; err = -ENOMEM; - value = kmalloc(map->value_size, GFP_USER); + value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN); if (!value) goto free_key; @@ -299,7 +299,7 @@ static int map_update_elem(union bpf_attr *attr) goto free_key; err = -ENOMEM; - value = kmalloc(map->value_size, GFP_USER); + value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN); if (!value) goto free_key; -- cgit v0.10.2 From 45f6fad84cc305103b28d73482b344d7f5b76f39 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Nov 2015 19:37:57 -0800 Subject: ipv6: add complete rcu protection around np->opt This patch addresses multiple problems : UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions while socket is not locked : Other threads can change np->opt concurrently. Dmitry posted a syzkaller (http://github.com/google/syzkaller) program desmonstrating use-after-free. Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock() and dccp_v6_request_recv_sock() also need to use RCU protection to dereference np->opt once (before calling ipv6_dup_options()) This patch adds full RCU protection to np->opt Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 0ef2a97..402753b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -227,7 +227,7 @@ struct ipv6_pinfo { struct ipv6_ac_socklist *ipv6_ac_list; struct ipv6_fl_socklist __rcu *ipv6_fl_list; - struct ipv6_txoptions *opt; + struct ipv6_txoptions __rcu *opt; struct sk_buff *pktoptions; struct sk_buff *rxpmtu; struct inet6_cork cork; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index ea5a13e..9a5c9f0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock; */ struct ipv6_txoptions { + atomic_t refcnt; /* Length of this structure */ int tot_len; @@ -217,7 +218,7 @@ struct ipv6_txoptions { struct ipv6_opt_hdr *dst0opt; struct ipv6_rt_hdr *srcrt; /* Routing Header */ struct ipv6_opt_hdr *dst1opt; - + struct rcu_head rcu; /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ }; @@ -252,6 +253,24 @@ struct ipv6_fl_socklist { struct rcu_head rcu; }; +static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np) +{ + struct ipv6_txoptions *opt; + + rcu_read_lock(); + opt = rcu_dereference(np->opt); + if (opt && !atomic_inc_not_zero(&opt->refcnt)) + opt = NULL; + rcu_read_unlock(); + return opt; +} + +static inline void txopt_put(struct ipv6_txoptions *opt) +{ + if (opt && atomic_dec_and_test(&opt->refcnt)) + kfree_rcu(opt, rcu); +} + struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, struct ip6_flowlabel *fl, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index db5fc24..e7e0b9b 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -202,7 +202,9 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req security_req_classify_flow(req, flowi6_to_flowi(&fl6)); - final_p = fl6_update_dst(&fl6, np->opt, &final); + rcu_read_lock(); + final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final); + rcu_read_unlock(); dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { @@ -219,7 +221,10 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req &ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr); fl6.daddr = ireq->ir_v6_rmt_addr; - err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); + rcu_read_lock(); + err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), + np->tclass); + rcu_read_unlock(); err = net_xmit_eval(err); } @@ -387,6 +392,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, struct inet_request_sock *ireq = inet_rsk(req); struct ipv6_pinfo *newnp; const struct ipv6_pinfo *np = inet6_sk(sk); + struct ipv6_txoptions *opt; struct inet_sock *newinet; struct dccp6_sock *newdp6; struct sock *newsk; @@ -488,13 +494,15 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, * Yes, keeping reference count would be much more clever, but we make * one more one thing there: reattach optmem to newsk. */ - if (np->opt != NULL) - newnp->opt = ipv6_dup_options(newsk, np->opt); - + opt = rcu_dereference(np->opt); + if (opt) { + opt = ipv6_dup_options(newsk, opt); + RCU_INIT_POINTER(newnp->opt, opt); + } inet_csk(newsk)->icsk_ext_hdr_len = 0; - if (newnp->opt != NULL) - inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + - newnp->opt->opt_flen); + if (opt) + inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + + opt->opt_flen; dccp_sync_mss(newsk, dst_mtu(dst)); @@ -757,6 +765,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, struct ipv6_pinfo *np = inet6_sk(sk); struct dccp_sock *dp = dccp_sk(sk); struct in6_addr *saddr = NULL, *final_p, final; + struct ipv6_txoptions *opt; struct flowi6 fl6; struct dst_entry *dst; int addr_type; @@ -856,7 +865,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.fl6_sport = inet->inet_sport; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - final_p = fl6_update_dst(&fl6, np->opt, &final); + opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); + final_p = fl6_update_dst(&fl6, opt, &final); dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { @@ -876,9 +886,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, __ip6_dst_store(sk, dst, NULL, NULL); icsk->icsk_ext_hdr_len = 0; - if (np->opt != NULL) - icsk->icsk_ext_hdr_len = (np->opt->opt_flen + - np->opt->opt_nflen); + if (opt) + icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; inet->inet_dport = usin->sin6_port; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 44bb66b..38d66dd 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -428,9 +428,11 @@ void inet6_destroy_sock(struct sock *sk) /* Free tx options */ - opt = xchg(&np->opt, NULL); - if (opt) - sock_kfree_s(sk, opt, opt->tot_len); + opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); + if (opt) { + atomic_sub(opt->tot_len, &sk->sk_omem_alloc); + txopt_put(opt); + } } EXPORT_SYMBOL_GPL(inet6_destroy_sock); @@ -659,7 +661,10 @@ int inet6_sk_rebuild_header(struct sock *sk) fl6.fl6_sport = inet->inet_sport; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - final_p = fl6_update_dst(&fl6, np->opt, &final); + rcu_read_lock(); + final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), + &final); + rcu_read_unlock(); dst = ip6_dst_lookup_flow(sk, &fl6, final_p); if (IS_ERR(dst)) { diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index d70b023..517c55b 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -167,8 +167,10 @@ ipv4_connected: security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - opt = flowlabel ? flowlabel->opt : np->opt; + rcu_read_lock(); + opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt); final_p = fl6_update_dst(&fl6, opt, &final); + rcu_read_unlock(); dst = ip6_dst_lookup_flow(sk, &fl6, final_p); err = 0; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index ce203b0..ea7c4d6 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt) *((char **)&opt2->dst1opt) += dif; if (opt2->srcrt) *((char **)&opt2->srcrt) += dif; + atomic_set(&opt2->refcnt, 1); } return opt2; } @@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, return ERR_PTR(-ENOBUFS); memset(opt2, 0, tot_len); - + atomic_set(&opt2->refcnt, 1); opt2->tot_len = tot_len; p = (char *)(opt2 + 1); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 5d1c7ce..3ff5208 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk, memset(fl6, 0, sizeof(*fl6)); fl6->flowi6_proto = proto; fl6->daddr = ireq->ir_v6_rmt_addr; - final_p = fl6_update_dst(fl6, np->opt, &final); + rcu_read_lock(); + final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); + rcu_read_unlock(); fl6->saddr = ireq->ir_v6_loc_addr; fl6->flowi6_oif = ireq->ir_iif; fl6->flowi6_mark = ireq->ir_mark; @@ -142,7 +144,9 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, fl6->fl6_dport = inet->inet_dport; security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); - final_p = fl6_update_dst(fl6, np->opt, &final); + rcu_read_lock(); + final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); + rcu_read_unlock(); dst = __inet6_csk_dst_check(sk, np->dst_cookie); if (!dst) { @@ -175,7 +179,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused /* Restore final destination back after routing done */ fl6.daddr = sk->sk_v6_daddr; - res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); + res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), + np->tclass); rcu_read_unlock(); return res; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 63e6956..4449ad1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -111,7 +111,8 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); } } - opt = xchg(&inet6_sk(sk)->opt, opt); + opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, + opt); sk_dst_reset(sk); return opt; @@ -231,9 +232,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } - opt = xchg(&np->opt, NULL); - if (opt) - sock_kfree_s(sk, opt, opt->tot_len); + opt = xchg((__force struct ipv6_txoptions **)&np->opt, + NULL); + if (opt) { + atomic_sub(opt->tot_len, &sk->sk_omem_alloc); + txopt_put(opt); + } pktopt = xchg(&np->pktoptions, NULL); kfree_skb(pktopt); @@ -403,7 +407,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) break; - opt = ipv6_renew_options(sk, np->opt, optname, + opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); + opt = ipv6_renew_options(sk, opt, optname, (struct ipv6_opt_hdr __user *)optval, optlen); if (IS_ERR(opt)) { @@ -432,8 +437,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, retv = 0; opt = ipv6_update_options(sk, opt); sticky_done: - if (opt) - sock_kfree_s(sk, opt, opt->tot_len); + if (opt) { + atomic_sub(opt->tot_len, &sk->sk_omem_alloc); + txopt_put(opt); + } break; } @@ -486,6 +493,7 @@ sticky_done: break; memset(opt, 0, sizeof(*opt)); + atomic_set(&opt->refcnt, 1); opt->tot_len = sizeof(*opt) + optlen; retv = -EFAULT; if (copy_from_user(opt+1, optval, optlen)) @@ -502,8 +510,10 @@ update: retv = 0; opt = ipv6_update_options(sk, opt); done: - if (opt) - sock_kfree_s(sk, opt, opt->tot_len); + if (opt) { + atomic_sub(opt->tot_len, &sk->sk_omem_alloc); + txopt_put(opt); + } break; } case IPV6_UNICAST_HOPS: @@ -1110,10 +1120,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, case IPV6_RTHDR: case IPV6_DSTOPTS: { + struct ipv6_txoptions *opt; lock_sock(sk); - len = ipv6_getsockopt_sticky(sk, np->opt, - optname, optval, len); + opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); + len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); release_sock(sk); /* check if ipv6_getsockopt_sticky() returns err code */ if (len < 0) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index dc65ec1..9914098 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -733,6 +733,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd, static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { + struct ipv6_txoptions *opt_to_free = NULL; struct ipv6_txoptions opt_space; DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); struct in6_addr *daddr, *final_p, final; @@ -839,8 +840,10 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (!(opt->opt_nflen|opt->opt_flen)) opt = NULL; } - if (!opt) - opt = np->opt; + if (!opt) { + opt = txopt_get(np); + opt_to_free = opt; + } if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); @@ -906,6 +909,7 @@ done: dst_release(dst); out: fl6_sock_release(flowlabel); + txopt_put(opt_to_free); return err < 0 ? err : len; do_confirm: dst_confirm(dst); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index bb8f2fa..eaf7ac4 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -222,7 +222,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_proto = IPPROTO_TCP; fl6.daddr = ireq->ir_v6_rmt_addr; - final_p = fl6_update_dst(&fl6, np->opt, &final); + final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final); fl6.saddr = ireq->ir_v6_loc_addr; fl6.flowi6_oif = sk->sk_bound_dev_if; fl6.flowi6_mark = ireq->ir_mark; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c5429a6..6a50bb4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -120,6 +120,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, struct ipv6_pinfo *np = inet6_sk(sk); struct tcp_sock *tp = tcp_sk(sk); struct in6_addr *saddr = NULL, *final_p, final; + struct ipv6_txoptions *opt; struct flowi6 fl6; struct dst_entry *dst; int addr_type; @@ -235,7 +236,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, fl6.fl6_dport = usin->sin6_port; fl6.fl6_sport = inet->inet_sport; - final_p = fl6_update_dst(&fl6, np->opt, &final); + opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); + final_p = fl6_update_dst(&fl6, opt, &final); security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); @@ -263,9 +265,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, tcp_fetch_timewait_stamp(sk, dst); icsk->icsk_ext_hdr_len = 0; - if (np->opt) - icsk->icsk_ext_hdr_len = (np->opt->opt_flen + - np->opt->opt_nflen); + if (opt) + icsk->icsk_ext_hdr_len = opt->opt_flen + + opt->opt_nflen; tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); @@ -461,7 +463,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, if (np->repflow && ireq->pktopts) fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); - err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); + err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), + np->tclass); err = net_xmit_eval(err); } @@ -972,6 +975,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * struct inet_request_sock *ireq; struct ipv6_pinfo *newnp; const struct ipv6_pinfo *np = inet6_sk(sk); + struct ipv6_txoptions *opt; struct tcp6_sock *newtcp6sk; struct inet_sock *newinet; struct tcp_sock *newtp; @@ -1098,13 +1102,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * but we make one more one thing there: reattach optmem to newsk. */ - if (np->opt) - newnp->opt = ipv6_dup_options(newsk, np->opt); - + opt = rcu_dereference(np->opt); + if (opt) { + opt = ipv6_dup_options(newsk, opt); + RCU_INIT_POINTER(newnp->opt, opt); + } inet_csk(newsk)->icsk_ext_hdr_len = 0; - if (newnp->opt) - inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + - newnp->opt->opt_flen); + if (opt) + inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + + opt->opt_flen; tcp_ca_openreq_child(newsk, dst); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 01bcb49..9da3287 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1110,6 +1110,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); struct in6_addr *daddr, *final_p, final; struct ipv6_txoptions *opt = NULL; + struct ipv6_txoptions *opt_to_free = NULL; struct ip6_flowlabel *flowlabel = NULL; struct flowi6 fl6; struct dst_entry *dst; @@ -1263,8 +1264,10 @@ do_udp_sendmsg: opt = NULL; connected = 0; } - if (!opt) - opt = np->opt; + if (!opt) { + opt = txopt_get(np); + opt_to_free = opt; + } if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); @@ -1373,6 +1376,7 @@ release_dst: out: dst_release(dst); fl6_sock_release(flowlabel); + txopt_put(opt_to_free); if (!err) return len; /* diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index aca38d8..a2c8747 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -486,6 +486,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); struct in6_addr *daddr, *final_p, final; struct ipv6_pinfo *np = inet6_sk(sk); + struct ipv6_txoptions *opt_to_free = NULL; struct ipv6_txoptions *opt = NULL; struct ip6_flowlabel *flowlabel = NULL; struct dst_entry *dst = NULL; @@ -575,8 +576,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) opt = NULL; } - if (opt == NULL) - opt = np->opt; + if (!opt) { + opt = txopt_get(np); + opt_to_free = opt; + } if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); opt = ipv6_fixup_options(&opt_space, opt); @@ -631,6 +634,7 @@ done: dst_release(dst); out: fl6_sock_release(flowlabel); + txopt_put(opt_to_free); return err < 0 ? err : len; -- cgit v0.10.2 From 38ee8fb67c3457f36f5137073c4b8ac2436d2393 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Mon, 30 Nov 2015 12:17:06 -0200 Subject: sctp: convert sack_needed and sack_generation to bits They don't need to be any bigger than that and with this we start a new bitfield for tracking association runtime stuff, like zero window situation. Signed-off-by: Marcelo Ricardo Leitner Acked-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 495c87e..7bbb710 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -775,10 +775,10 @@ struct sctp_transport { hb_sent:1, /* Is the Path MTU update pending on this tranport */ - pmtu_pending:1; + pmtu_pending:1, - /* Has this transport moved the ctsn since we last sacked */ - __u32 sack_generation; + /* Has this transport moved the ctsn since we last sacked */ + sack_generation:1; u32 dst_cookie; struct flowi fl; @@ -1482,19 +1482,19 @@ struct sctp_association { prsctp_capable:1, /* Can peer do PR-SCTP? */ auth_capable:1; /* Is peer doing SCTP-AUTH? */ - /* Ack State : This flag indicates if the next received + /* sack_needed : This flag indicates if the next received * : packet is to be responded to with a - * : SACK. This is initializedto 0. When a packet - * : is received it is incremented. If this value + * : SACK. This is initialized to 0. When a packet + * : is received sack_cnt is incremented. If this value * : reaches 2 or more, a SACK is sent and the * : value is reset to 0. Note: This is used only * : when no DATA chunks are received out of * : order. When DATA chunks are out of order, * : SACK's are not delayed (see Section 6). */ - __u8 sack_needed; /* Do we need to sack the peer? */ + __u8 sack_needed:1, /* Do we need to sack the peer? */ + sack_generation:1; __u32 sack_cnt; - __u32 sack_generation; __u32 adaptation_ind; /* Adaptation Code point. */ -- cgit v0.10.2 From cacc06215271104b40773c99547c506095db6ad4 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Mon, 30 Nov 2015 14:32:54 -0200 Subject: sctp: use GFP_USER for user-controlled kmalloc Dmitry Vyukov reported that the user could trigger a kernel warning by using a large len value for getsockopt SCTP_GET_LOCAL_ADDRS, as that value directly affects the value used as a kmalloc() parameter. This patch thus switches the allocation flags from all user-controllable kmalloc size to GFP_USER to put some more restrictions on it and also disables the warn, as they are not necessary. Signed-off-by: Marcelo Ricardo Leitner Acked-by: Daniel Borkmann Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5e35ef3..f6161e3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -972,7 +972,7 @@ static int sctp_setsockopt_bindx(struct sock *sk, return -EFAULT; /* Alloc space for the address array in kernel memory. */ - kaddrs = kmalloc(addrs_size, GFP_KERNEL); + kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN); if (unlikely(!kaddrs)) return -ENOMEM; @@ -4928,7 +4928,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, to = optval + offsetof(struct sctp_getaddrs, addrs); space_left = len - offsetof(struct sctp_getaddrs, addrs); - addrs = kmalloc(space_left, GFP_KERNEL); + addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN); if (!addrs) return -ENOMEM; -- cgit v0.10.2 From 6adc5fd6a142c6e2c80574c1db0c7c17dedaa42e Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 1 Dec 2015 01:14:48 +0300 Subject: net/neighbour: fix crash at dumping device-agnostic proxy entries Proxy entries could have null pointer to net-device. Signed-off-by: Konstantin Khlebnikov Fixes: 84920c1420e2 ("net: Allow ipv6 proxies and arp proxies be shown with iproute2") Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e6af42d..f18ae91 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2215,7 +2215,7 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn, ndm->ndm_pad2 = 0; ndm->ndm_flags = pn->flags | NTF_PROXY; ndm->ndm_type = RTN_UNICAST; - ndm->ndm_ifindex = pn->dev->ifindex; + ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0; ndm->ndm_state = NUD_NONE; if (nla_put(skb, NDA_DST, tbl->key_len, pn->key)) @@ -2333,7 +2333,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, if (h > s_h) s_idx = 0; for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { - if (dev_net(n->dev) != net) + if (pneigh_net(n) != net) continue; if (idx < s_idx) goto next; -- cgit v0.10.2 From 59f0ec231f397001801264063db3b6dcc3eef590 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 1 Dec 2015 12:14:52 +0100 Subject: clk: sunxi: pll2: Fix clock running too fast Contrary to what the datasheet says, the pre divider doesn't seem to be incremented by one in the PLL2, but just uses the value from the register, with 0 being a bypass. This fixes the audio playing too fast. Since we now have the same pre-divider flags, and the only difference with the A10 is the post-divider offset, also remove the structure to just pass the offset as an argument. Signed-off-by: Maxime Ripard Fixes: eb662f854710 ("clk: sunxi: pll2: Add A13 support") Signed-off-by: Stephen Boyd diff --git a/drivers/clk/sunxi/clk-a10-pll2.c b/drivers/clk/sunxi/clk-a10-pll2.c index 5484c31e..0ee1f36 100644 --- a/drivers/clk/sunxi/clk-a10-pll2.c +++ b/drivers/clk/sunxi/clk-a10-pll2.c @@ -41,15 +41,10 @@ #define SUN4I_PLL2_OUTPUTS 4 -struct sun4i_pll2_data { - u32 post_div_offset; - u32 pre_div_flags; -}; - static DEFINE_SPINLOCK(sun4i_a10_pll2_lock); static void __init sun4i_pll2_setup(struct device_node *node, - struct sun4i_pll2_data *data) + int post_div_offset) { const char *clk_name = node->name, *parent; struct clk **clks, *base_clk, *prediv_clk; @@ -76,7 +71,7 @@ static void __init sun4i_pll2_setup(struct device_node *node, parent, 0, reg, SUN4I_PLL2_PRE_DIV_SHIFT, SUN4I_PLL2_PRE_DIV_WIDTH, - data->pre_div_flags, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &sun4i_a10_pll2_lock); if (!prediv_clk) { pr_err("Couldn't register the prediv clock\n"); @@ -127,7 +122,7 @@ static void __init sun4i_pll2_setup(struct device_node *node, */ val = readl(reg); val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV_SHIFT); - val |= (SUN4I_PLL2_POST_DIV_VALUE - data->post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT; + val |= (SUN4I_PLL2_POST_DIV_VALUE - post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT; writel(val, reg); of_property_read_string_index(node, "clock-output-names", @@ -191,25 +186,17 @@ err_unmap: iounmap(reg); } -static struct sun4i_pll2_data sun4i_a10_pll2_data = { - .pre_div_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, -}; - static void __init sun4i_a10_pll2_setup(struct device_node *node) { - sun4i_pll2_setup(node, &sun4i_a10_pll2_data); + sun4i_pll2_setup(node, 0); } CLK_OF_DECLARE(sun4i_a10_pll2, "allwinner,sun4i-a10-pll2-clk", sun4i_a10_pll2_setup); -static struct sun4i_pll2_data sun5i_a13_pll2_data = { - .post_div_offset = 1, -}; - static void __init sun5i_a13_pll2_setup(struct device_node *node) { - sun4i_pll2_setup(node, &sun5i_a13_pll2_data); + sun4i_pll2_setup(node, 1); } CLK_OF_DECLARE(sun5i_a13_pll2, "allwinner,sun5i-a13-pll2-clk", -- cgit v0.10.2 From 599c963a0f19b14132065788322207eaa58bc7f8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 3 Dec 2015 10:18:21 -0500 Subject: cgroup_freezer: simplify propagation of CGROUP_FROZEN clearing in freezer_attach() If one or more tasks get moved into a frozen css, the frozen state is cleared up from the destination css so that it can be reasserted once the migrated tasks are frozen. freezer_attach() implements this in two separate steps - clearing CGROUP_FROZEN on the target css while processing each task and propagating the clearing upwards after the task loop is done if necessary. This patch merges the two steps. Propagation now takes place inside the task loop. This simplifies the code and prepares it for the fix of multi-destination migration. Signed-off-by: Tejun Heo diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index f1b30ad..ff02a8e 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -158,9 +158,7 @@ static void freezer_css_free(struct cgroup_subsys_state *css) static void freezer_attach(struct cgroup_subsys_state *new_css, struct cgroup_taskset *tset) { - struct freezer *freezer = css_freezer(new_css); struct task_struct *task; - bool clear_frozen = false; mutex_lock(&freezer_mutex); @@ -175,21 +173,20 @@ static void freezer_attach(struct cgroup_subsys_state *new_css, * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. */ cgroup_taskset_for_each(task, tset) { + struct freezer *freezer = css_freezer(new_css); + if (!(freezer->state & CGROUP_FREEZING)) { __thaw_task(task); } else { freeze_task(task); - freezer->state &= ~CGROUP_FROZEN; - clear_frozen = true; + /* clear FROZEN and propagate upwards */ + while (freezer && (freezer->state & CGROUP_FROZEN)) { + freezer->state &= ~CGROUP_FROZEN; + freezer = parent_freezer(freezer); + } } } - /* propagate FROZEN clearing upwards */ - while (clear_frozen && (freezer = parent_freezer(freezer))) { - freezer->state &= ~CGROUP_FROZEN; - clear_frozen = freezer->state & CGROUP_FREEZING; - } - mutex_unlock(&freezer_mutex); } -- cgit v0.10.2 From 1f7dd3e5a6e4f093017fff12232572ee1aa4639b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 3 Dec 2015 10:18:21 -0500 Subject: cgroup: fix handling of multi-destination migration from subtree_control enabling Consider the following v2 hierarchy. P0 (+memory) --- P1 (-memory) --- A \- B P0 has memory enabled in its subtree_control while P1 doesn't. If both A and B contain processes, they would belong to the memory css of P1. Now if memory is enabled on P1's subtree_control, memory csses should be created on both A and B and A's processes should be moved to the former and B's processes the latter. IOW, enabling controllers can cause atomic migrations into different csses. The core cgroup migration logic has been updated accordingly but the controller migration methods haven't and still assume that all tasks migrate to a single target css; furthermore, the methods were fed the css in which subtree_control was updated which is the parent of the target csses. pids controller depends on the migration methods to move charges and this made the controller attribute charges to the wrong csses often triggering the following warning by driving a counter negative. WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40() Modules linked in: CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29 ... ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000 ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00 ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8 Call Trace: [] dump_stack+0x4e/0x82 [] warn_slowpath_common+0x82/0xc0 [] warn_slowpath_null+0x1a/0x20 [] pids_cancel.constprop.6+0x31/0x40 [] pids_can_attach+0x6d/0xf0 [] cgroup_taskset_migrate+0x6c/0x330 [] cgroup_migrate+0xf5/0x190 [] cgroup_attach_task+0x176/0x200 [] __cgroup_procs_write+0x2ad/0x460 [] cgroup_procs_write+0x14/0x20 [] cgroup_file_write+0x35/0x1c0 [] kernfs_fop_write+0x141/0x190 [] __vfs_write+0x28/0xe0 [] vfs_write+0xac/0x1a0 [] SyS_write+0x49/0xb0 [] entry_SYSCALL_64_fastpath+0x12/0x76 This patch fixes the bug by removing @css parameter from the three migration methods, ->can_attach, ->cancel_attach() and ->attach() and updating cgroup_taskset iteration helpers also return the destination css in addition to the task being migrated. All controllers are updated accordingly. * Controllers which don't care whether there are one or multiple target csses can be converted trivially. cpu, io, freezer, perf, netclassid and netprio fall in this category. * cpuset's current implementation assumes that there's single source and destination and thus doesn't support v2 hierarchy already. The only change made by this patchset is how that single destination css is obtained. * memory migration path already doesn't do anything on v2. How the single destination css is obtained is updated and the prep stage of mem_cgroup_can_attach() is reordered to accomodate the change. * pids is the only controller which was affected by this bug. It now correctly handles multi-destination migrations and no longer causes counter underflow from incorrect accounting. Signed-off-by: Tejun Heo Reported-and-tested-by: Daniel Wagner Cc: Aleksa Sarai diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 5bcdfc1..5a37188 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1127,15 +1127,15 @@ void blkcg_exit_queue(struct request_queue *q) * of the main cic data structures. For now we allow a task to change * its cgroup only if it's the only owner of its ioc. */ -static int blkcg_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int blkcg_can_attach(struct cgroup_taskset *tset) { struct task_struct *task; + struct cgroup_subsys_state *dst_css; struct io_context *ioc; int ret = 0; /* task_lock() is needed to avoid races with exit_io_context() */ - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, dst_css, tset) { task_lock(task); ioc = task->io_context; if (ioc && atomic_read(&ioc->nr_tasks) > 1) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 869fd4a..06b77f9d 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -422,12 +422,9 @@ struct cgroup_subsys { void (*css_reset)(struct cgroup_subsys_state *css); void (*css_e_css_changed)(struct cgroup_subsys_state *css); - int (*can_attach)(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset); - void (*cancel_attach)(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset); - void (*attach)(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset); + int (*can_attach)(struct cgroup_taskset *tset); + void (*cancel_attach)(struct cgroup_taskset *tset); + void (*attach)(struct cgroup_taskset *tset); int (*can_fork)(struct task_struct *task, void **priv_p); void (*cancel_fork)(struct task_struct *task, void *priv); void (*fork)(struct task_struct *task, void *priv); diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index f640830..cb91b44 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -120,8 +120,10 @@ struct cgroup_subsys_state *css_rightmost_descendant(struct cgroup_subsys_state struct cgroup_subsys_state *css_next_descendant_post(struct cgroup_subsys_state *pos, struct cgroup_subsys_state *css); -struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset); -struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset); +struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset, + struct cgroup_subsys_state **dst_cssp); +struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, + struct cgroup_subsys_state **dst_cssp); void css_task_iter_start(struct cgroup_subsys_state *css, struct css_task_iter *it); @@ -236,30 +238,39 @@ void css_task_iter_end(struct css_task_iter *it); /** * cgroup_taskset_for_each - iterate cgroup_taskset * @task: the loop cursor + * @dst_css: the destination css * @tset: taskset to iterate * * @tset may contain multiple tasks and they may belong to multiple - * processes. When there are multiple tasks in @tset, if a task of a - * process is in @tset, all tasks of the process are in @tset. Also, all - * are guaranteed to share the same source and destination csses. + * processes. + * + * On the v2 hierarchy, there may be tasks from multiple processes and they + * may not share the source or destination csses. + * + * On traditional hierarchies, when there are multiple tasks in @tset, if a + * task of a process is in @tset, all tasks of the process are in @tset. + * Also, all are guaranteed to share the same source and destination csses. * * Iteration is not in any specific order. */ -#define cgroup_taskset_for_each(task, tset) \ - for ((task) = cgroup_taskset_first((tset)); (task); \ - (task) = cgroup_taskset_next((tset))) +#define cgroup_taskset_for_each(task, dst_css, tset) \ + for ((task) = cgroup_taskset_first((tset), &(dst_css)); \ + (task); \ + (task) = cgroup_taskset_next((tset), &(dst_css))) /** * cgroup_taskset_for_each_leader - iterate group leaders in a cgroup_taskset * @leader: the loop cursor + * @dst_css: the destination css * @tset: takset to iterate * * Iterate threadgroup leaders of @tset. For single-task migrations, @tset * may not contain any. */ -#define cgroup_taskset_for_each_leader(leader, tset) \ - for ((leader) = cgroup_taskset_first((tset)); (leader); \ - (leader) = cgroup_taskset_next((tset))) \ +#define cgroup_taskset_for_each_leader(leader, dst_css, tset) \ + for ((leader) = cgroup_taskset_first((tset), &(dst_css)); \ + (leader); \ + (leader) = cgroup_taskset_next((tset), &(dst_css))) \ if ((leader) != (leader)->group_leader) \ ; \ else diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5cea63f..470f653 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2237,6 +2237,9 @@ struct cgroup_taskset { struct list_head src_csets; struct list_head dst_csets; + /* the subsys currently being processed */ + int ssid; + /* * Fields for cgroup_taskset_*() iteration. * @@ -2299,25 +2302,29 @@ static void cgroup_taskset_add(struct task_struct *task, /** * cgroup_taskset_first - reset taskset and return the first task * @tset: taskset of interest + * @dst_cssp: output variable for the destination css * * @tset iteration is initialized and the first task is returned. */ -struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset) +struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset, + struct cgroup_subsys_state **dst_cssp) { tset->cur_cset = list_first_entry(tset->csets, struct css_set, mg_node); tset->cur_task = NULL; - return cgroup_taskset_next(tset); + return cgroup_taskset_next(tset, dst_cssp); } /** * cgroup_taskset_next - iterate to the next task in taskset * @tset: taskset of interest + * @dst_cssp: output variable for the destination css * * Return the next task in @tset. Iteration must have been initialized * with cgroup_taskset_first(). */ -struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset) +struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, + struct cgroup_subsys_state **dst_cssp) { struct css_set *cset = tset->cur_cset; struct task_struct *task = tset->cur_task; @@ -2332,6 +2339,18 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset) if (&task->cg_list != &cset->mg_tasks) { tset->cur_cset = cset; tset->cur_task = task; + + /* + * This function may be called both before and + * after cgroup_taskset_migrate(). The two cases + * can be distinguished by looking at whether @cset + * has its ->mg_dst_cset set. + */ + if (cset->mg_dst_cset) + *dst_cssp = cset->mg_dst_cset->subsys[tset->ssid]; + else + *dst_cssp = cset->subsys[tset->ssid]; + return task; } @@ -2367,7 +2386,8 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset, /* check that we can legitimately attach to the cgroup */ for_each_e_css(css, i, dst_cgrp) { if (css->ss->can_attach) { - ret = css->ss->can_attach(css, tset); + tset->ssid = i; + ret = css->ss->can_attach(tset); if (ret) { failed_css = css; goto out_cancel_attach; @@ -2400,9 +2420,12 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset, */ tset->csets = &tset->dst_csets; - for_each_e_css(css, i, dst_cgrp) - if (css->ss->attach) - css->ss->attach(css, tset); + for_each_e_css(css, i, dst_cgrp) { + if (css->ss->attach) { + tset->ssid = i; + css->ss->attach(tset); + } + } ret = 0; goto out_release_tset; @@ -2411,8 +2434,10 @@ out_cancel_attach: for_each_e_css(css, i, dst_cgrp) { if (css == failed_css) break; - if (css->ss->cancel_attach) - css->ss->cancel_attach(css, tset); + if (css->ss->cancel_attach) { + tset->ssid = i; + css->ss->cancel_attach(tset); + } } out_release_tset: spin_lock_bh(&css_set_lock); diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index ff02a8e..2d3df82 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -155,10 +155,10 @@ static void freezer_css_free(struct cgroup_subsys_state *css) * @freezer->lock. freezer_attach() makes the new tasks conform to the * current state and all following state changes can see the new tasks. */ -static void freezer_attach(struct cgroup_subsys_state *new_css, - struct cgroup_taskset *tset) +static void freezer_attach(struct cgroup_taskset *tset) { struct task_struct *task; + struct cgroup_subsys_state *new_css; mutex_lock(&freezer_mutex); @@ -172,7 +172,7 @@ static void freezer_attach(struct cgroup_subsys_state *new_css, * current state before executing the following - !frozen tasks may * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. */ - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, new_css, tset) { struct freezer *freezer = css_freezer(new_css); if (!(freezer->state & CGROUP_FREEZING)) { diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c index de3359a..8e27fc5 100644 --- a/kernel/cgroup_pids.c +++ b/kernel/cgroup_pids.c @@ -162,13 +162,13 @@ revert: return -EAGAIN; } -static int pids_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int pids_can_attach(struct cgroup_taskset *tset) { - struct pids_cgroup *pids = css_pids(css); struct task_struct *task; + struct cgroup_subsys_state *dst_css; - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, dst_css, tset) { + struct pids_cgroup *pids = css_pids(dst_css); struct cgroup_subsys_state *old_css; struct pids_cgroup *old_pids; @@ -187,13 +187,13 @@ static int pids_can_attach(struct cgroup_subsys_state *css, return 0; } -static void pids_cancel_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void pids_cancel_attach(struct cgroup_taskset *tset) { - struct pids_cgroup *pids = css_pids(css); struct task_struct *task; + struct cgroup_subsys_state *dst_css; - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, dst_css, tset) { + struct pids_cgroup *pids = css_pids(dst_css); struct cgroup_subsys_state *old_css; struct pids_cgroup *old_pids; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 10ae736..02a8ea5 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1429,15 +1429,16 @@ static int fmeter_getrate(struct fmeter *fmp) static struct cpuset *cpuset_attach_old_cs; /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */ -static int cpuset_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int cpuset_can_attach(struct cgroup_taskset *tset) { - struct cpuset *cs = css_cs(css); + struct cgroup_subsys_state *css; + struct cpuset *cs; struct task_struct *task; int ret; /* used later by cpuset_attach() */ - cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset)); + cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css)); + cs = css_cs(css); mutex_lock(&cpuset_mutex); @@ -1447,7 +1448,7 @@ static int cpuset_can_attach(struct cgroup_subsys_state *css, (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))) goto out_unlock; - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, css, tset) { ret = task_can_attach(task, cs->cpus_allowed); if (ret) goto out_unlock; @@ -1467,9 +1468,14 @@ out_unlock: return ret; } -static void cpuset_cancel_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void cpuset_cancel_attach(struct cgroup_taskset *tset) { + struct cgroup_subsys_state *css; + struct cpuset *cs; + + cgroup_taskset_first(tset, &css); + cs = css_cs(css); + mutex_lock(&cpuset_mutex); css_cs(css)->attach_in_progress--; mutex_unlock(&cpuset_mutex); @@ -1482,16 +1488,19 @@ static void cpuset_cancel_attach(struct cgroup_subsys_state *css, */ static cpumask_var_t cpus_attach; -static void cpuset_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void cpuset_attach(struct cgroup_taskset *tset) { /* static buf protected by cpuset_mutex */ static nodemask_t cpuset_attach_nodemask_to; struct task_struct *task; struct task_struct *leader; - struct cpuset *cs = css_cs(css); + struct cgroup_subsys_state *css; + struct cpuset *cs; struct cpuset *oldcs = cpuset_attach_old_cs; + cgroup_taskset_first(tset, &css); + cs = css_cs(css); + mutex_lock(&cpuset_mutex); /* prepare for attach */ @@ -1502,7 +1511,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css, guarantee_online_mems(cs, &cpuset_attach_nodemask_to); - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, css, tset) { /* * can_attach beforehand should guarantee that this doesn't * fail. TODO: have a better way to handle failure here @@ -1518,7 +1527,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css, * sleep and should be moved outside migration path proper. */ cpuset_attach_nodemask_to = cs->effective_mems; - cgroup_taskset_for_each_leader(leader, tset) { + cgroup_taskset_for_each_leader(leader, css, tset) { struct mm_struct *mm = get_task_mm(leader); if (mm) { diff --git a/kernel/events/core.c b/kernel/events/core.c index 36babfd..026305d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9456,12 +9456,12 @@ static int __perf_cgroup_move(void *info) return 0; } -static void perf_cgroup_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void perf_cgroup_attach(struct cgroup_taskset *tset) { struct task_struct *task; + struct cgroup_subsys_state *css; - cgroup_taskset_for_each(task, tset) + cgroup_taskset_for_each(task, css, tset) task_function_call(task, __perf_cgroup_move, task); } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4d568ac..a9db4819 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8217,12 +8217,12 @@ static void cpu_cgroup_fork(struct task_struct *task, void *private) sched_move_task(task); } -static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) { struct task_struct *task; + struct cgroup_subsys_state *css; - cgroup_taskset_for_each(task, tset) { + cgroup_taskset_for_each(task, css, tset) { #ifdef CONFIG_RT_GROUP_SCHED if (!sched_rt_can_attach(css_tg(css), task)) return -EINVAL; @@ -8235,12 +8235,12 @@ static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css, return 0; } -static void cpu_cgroup_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void cpu_cgroup_attach(struct cgroup_taskset *tset) { struct task_struct *task; + struct cgroup_subsys_state *css; - cgroup_taskset_for_each(task, tset) + cgroup_taskset_for_each(task, css, tset) sched_move_task(task); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9acfb16..c92a65b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4779,23 +4779,18 @@ static void mem_cgroup_clear_mc(void) spin_unlock(&mc.lock); } -static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int mem_cgroup_can_attach(struct cgroup_taskset *tset) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct cgroup_subsys_state *css; + struct mem_cgroup *memcg; struct mem_cgroup *from; struct task_struct *leader, *p; struct mm_struct *mm; unsigned long move_flags; int ret = 0; - /* - * We are now commited to this value whatever it is. Changes in this - * tunable will only affect upcoming migrations, not the current one. - * So we need to save it, and keep it going. - */ - move_flags = READ_ONCE(memcg->move_charge_at_immigrate); - if (!move_flags) + /* charge immigration isn't supported on the default hierarchy */ + if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) return 0; /* @@ -4805,13 +4800,23 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, * multiple. */ p = NULL; - cgroup_taskset_for_each_leader(leader, tset) { + cgroup_taskset_for_each_leader(leader, css, tset) { WARN_ON_ONCE(p); p = leader; + memcg = mem_cgroup_from_css(css); } if (!p) return 0; + /* + * We are now commited to this value whatever it is. Changes in this + * tunable will only affect upcoming migrations, not the current one. + * So we need to save it, and keep it going. + */ + move_flags = READ_ONCE(memcg->move_charge_at_immigrate); + if (!move_flags) + return 0; + from = mem_cgroup_from_task(p); VM_BUG_ON(from == memcg); @@ -4842,8 +4847,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, return ret; } -static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset) { if (mc.to) mem_cgroup_clear_mc(); @@ -4985,10 +4989,10 @@ retry: atomic_dec(&mc.from->moving_account); } -static void mem_cgroup_move_task(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void mem_cgroup_move_task(struct cgroup_taskset *tset) { - struct task_struct *p = cgroup_taskset_first(tset); + struct cgroup_subsys_state *css; + struct task_struct *p = cgroup_taskset_first(tset, &css); struct mm_struct *mm = get_task_mm(p); if (mm) { @@ -5000,17 +5004,14 @@ static void mem_cgroup_move_task(struct cgroup_subsys_state *css, mem_cgroup_clear_mc(); } #else /* !CONFIG_MMU */ -static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static int mem_cgroup_can_attach(struct cgroup_taskset *tset) { return 0; } -static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset) { } -static void mem_cgroup_move_task(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void mem_cgroup_move_task(struct cgroup_taskset *tset) { } #endif diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 6441f47..81cb3c7 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c @@ -67,14 +67,15 @@ static int update_classid(const void *v, struct file *file, unsigned n) return 0; } -static void cgrp_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void cgrp_attach(struct cgroup_taskset *tset) { - struct cgroup_cls_state *cs = css_cls_state(css); - void *v = (void *)(unsigned long)cs->classid; struct task_struct *p; + struct cgroup_subsys_state *css; + + cgroup_taskset_for_each(p, css, tset) { + struct cgroup_cls_state *cs = css_cls_state(css); + void *v = (void *)(unsigned long)cs->classid; - cgroup_taskset_for_each(p, tset) { task_lock(p); iterate_fd(p->files, 0, update_classid, v); task_unlock(p); diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index cbd0a19..40fd09f 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -218,13 +218,14 @@ static int update_netprio(const void *v, struct file *file, unsigned n) return 0; } -static void net_prio_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) +static void net_prio_attach(struct cgroup_taskset *tset) { struct task_struct *p; - void *v = (void *)(unsigned long)css->cgroup->id; + struct cgroup_subsys_state *css; + + cgroup_taskset_for_each(p, css, tset) { + void *v = (void *)(unsigned long)css->cgroup->id; - cgroup_taskset_for_each(p, tset) { task_lock(p); iterate_fd(p->files, 0, update_netprio, v); task_unlock(p); -- cgit v0.10.2 From 67cde9c4938945b9510730c64e68d2f1dd7bc0aa Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 3 Dec 2015 10:18:21 -0500 Subject: cgroup_pids: don't account for the root cgroup Because accounting resources for the root cgroup sometimes incurs measureable overhead for workloads which don't care about cgroup and often ends up calculating a number which is available elsewhere in a slightly different form, cgroup is not in the business of providing system-wide statistics. The pids controller which was introduced recently was exposing "pids.current" at the root. This patch disable accounting for root cgroup and removes the file from the root directory. While this is a userland visible behavior change, pids has been available only in one version and was badly broken there, so I don't think this will be noticeable. If it turns out to be a problem, we can reinstate it for v1 hierarchies. Signed-off-by: Tejun Heo Cc: Aleksa Sarai diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c index 8e27fc5..b50d5a1 100644 --- a/kernel/cgroup_pids.c +++ b/kernel/cgroup_pids.c @@ -106,7 +106,7 @@ static void pids_uncharge(struct pids_cgroup *pids, int num) { struct pids_cgroup *p; - for (p = pids; p; p = parent_pids(p)) + for (p = pids; parent_pids(p); p = parent_pids(p)) pids_cancel(p, num); } @@ -123,7 +123,7 @@ static void pids_charge(struct pids_cgroup *pids, int num) { struct pids_cgroup *p; - for (p = pids; p; p = parent_pids(p)) + for (p = pids; parent_pids(p); p = parent_pids(p)) atomic64_add(num, &p->counter); } @@ -140,7 +140,7 @@ static int pids_try_charge(struct pids_cgroup *pids, int num) { struct pids_cgroup *p, *q; - for (p = pids; p; p = parent_pids(p)) { + for (p = pids; parent_pids(p); p = parent_pids(p)) { int64_t new = atomic64_add_return(num, &p->counter); /* @@ -298,6 +298,7 @@ static struct cftype pids_files[] = { { .name = "current", .read_s64 = pids_current_read, + .flags = CFTYPE_NOT_ON_ROOT, }, { } /* terminate */ }; -- cgit v0.10.2 From c836a8ba93869d6a0290a6ae0047fbef09066871 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Dec 2015 21:48:14 -0800 Subject: ipv6: sctp: add rcu protection around np->opt This patch completes the work I did in commit 45f6fad84cc3 ("ipv6: add complete rcu protection around np->opt"), as I missed sctp part. This simply makes sure np->opt is used with proper RCU locking and accessors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index e917d27..acb45b8 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -209,6 +209,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) struct sock *sk = skb->sk; struct ipv6_pinfo *np = inet6_sk(sk); struct flowi6 *fl6 = &transport->fl.u.ip6; + int res; pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, skb->len, &fl6->saddr, &fl6->daddr); @@ -220,7 +221,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS); - return ip6_xmit(sk, skb, fl6, np->opt, np->tclass); + rcu_read_lock(); + res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass); + rcu_read_unlock(); + return res; } /* Returns the dst cache entry for the given source and destination ip @@ -262,7 +266,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, pr_debug("src=%pI6 - ", &fl6->saddr); } - final_p = fl6_update_dst(fl6, np->opt, &final); + rcu_read_lock(); + final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); + rcu_read_unlock(); + dst = ip6_dst_lookup_flow(sk, fl6, final_p); if (!asoc || saddr) goto out; @@ -321,7 +328,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (baddr) { fl6->saddr = baddr->v6.sin6_addr; fl6->fl6_sport = baddr->v6.sin6_port; - final_p = fl6_update_dst(fl6, np->opt, &final); + final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); dst = ip6_dst_lookup_flow(sk, fl6, final_p); } -- cgit v0.10.2 From 6bd4f355df2eae80b8a5c7b097371cd1e05f20d5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Dec 2015 21:53:57 -0800 Subject: ipv6: kill sk_dst_lock While testing the np->opt RCU conversion, I found that UDP/IPv6 was using a mixture of xchg() and sk_dst_lock to protect concurrent changes to sk->sk_dst_cache, leading to possible corruptions and crashes. ip6_sk_dst_lookup_flow() uses sk_dst_check() anyway, so the simplest way to fix the mess is to remove sk_dst_lock completely, as we did for IPv4. __ip6_dst_store() and ip6_dst_store() share same implementation. sk_setup_caps() being called with socket lock being held or not, we have to use sk_dst_set() instead of __sk_dst_set() Note that I had to move the "np->dst_cookie = rt6_get_cookie(rt);" in ip6_dst_store() before the sk_setup_caps(sk, dst) call. This is because ip6_dst_store() can be called from process context, without any lock held. As soon as the dst is installed in sk->sk_dst_cache, dst can be freed from another cpu doing a concurrent ip6_dst_store() Doing the dst dereference before doing the install is needed to make sure no use after free would trigger. Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Signed-off-by: David S. Miller diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 2bfb2ad..877f682 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -133,27 +133,18 @@ void rt6_clean_tohost(struct net *net, struct in6_addr *gateway); /* * Store a destination cache entry in a socket */ -static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, - const struct in6_addr *daddr, - const struct in6_addr *saddr) +static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, + const struct in6_addr *daddr, + const struct in6_addr *saddr) { struct ipv6_pinfo *np = inet6_sk(sk); - struct rt6_info *rt = (struct rt6_info *) dst; + np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst); sk_setup_caps(sk, dst); np->daddr_cache = daddr; #ifdef CONFIG_IPV6_SUBTREES np->saddr_cache = saddr; #endif - np->dst_cookie = rt6_get_cookie(rt); -} - -static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, - struct in6_addr *daddr, struct in6_addr *saddr) -{ - spin_lock(&sk->sk_dst_lock); - __ip6_dst_store(sk, dst, daddr, saddr); - spin_unlock(&sk->sk_dst_lock); } static inline bool ipv6_unicast_destination(const struct sk_buff *skb) diff --git a/include/net/sock.h b/include/net/sock.h index 0434138..52d27ee 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -254,7 +254,6 @@ struct cg_proto; * @sk_wq: sock wait queue and async head * @sk_rx_dst: receive input route used by early demux * @sk_dst_cache: destination cache - * @sk_dst_lock: destination cache lock * @sk_policy: flow policy * @sk_receive_queue: incoming packets * @sk_wmem_alloc: transmit queue bytes committed @@ -393,7 +392,7 @@ struct sock { #endif struct dst_entry *sk_rx_dst; struct dst_entry __rcu *sk_dst_cache; - spinlock_t sk_dst_lock; + /* Note: 32bit hole on 64bit arches */ atomic_t sk_wmem_alloc; atomic_t sk_omem_alloc; int sk_sndbuf; diff --git a/net/core/sock.c b/net/core/sock.c index 9d79569..e31dfce 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1530,7 +1530,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); - spin_lock_init(&newsk->sk_dst_lock); rwlock_init(&newsk->sk_callback_lock); lockdep_set_class_and_name(&newsk->sk_callback_lock, af_callback_keys + newsk->sk_family, @@ -1607,7 +1606,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) { u32 max_segs = 1; - __sk_dst_set(sk, dst); + sk_dst_set(sk, dst); sk->sk_route_caps = dst->dev->features; if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; @@ -2388,7 +2387,6 @@ void sock_init_data(struct socket *sock, struct sock *sk) } else sk->sk_wq = NULL; - spin_lock_init(&sk->sk_dst_lock); rwlock_init(&sk->sk_callback_lock); lockdep_set_class_and_name(&sk->sk_callback_lock, af_callback_keys + sk->sk_family, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index e7e0b9b..9c6d050 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -459,7 +459,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk, * comment in that function for the gory details. -acme */ - __ip6_dst_store(newsk, dst, NULL, NULL); + ip6_dst_store(newsk, dst, NULL, NULL); newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | NETIF_F_TSO); newdp6 = (struct dccp6_sock *)newsk; @@ -883,7 +883,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, np->saddr = *saddr; inet->inet_rcv_saddr = LOOPBACK4_IPV6; - __ip6_dst_store(sk, dst, NULL, NULL); + ip6_dst_store(sk, dst, NULL, NULL); icsk->icsk_ext_hdr_len = 0; if (opt) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 38d66dd..8ec0df7 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -673,7 +673,7 @@ int inet6_sk_rebuild_header(struct sock *sk) return PTR_ERR(dst); } - __ip6_dst_store(sk, dst, NULL, NULL); + ip6_dst_store(sk, dst, NULL, NULL); } return 0; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 36c5a98..0a37ddc 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -834,11 +834,6 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6, security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); } -/* - * Special lock-class for __icmpv6_sk: - */ -static struct lock_class_key icmpv6_socket_sk_dst_lock_key; - static int __net_init icmpv6_sk_init(struct net *net) { struct sock *sk; @@ -860,15 +855,6 @@ static int __net_init icmpv6_sk_init(struct net *net) net->ipv6.icmp_sk[i] = sk; - /* - * Split off their lock-class, because sk->sk_dst_lock - * gets used from softirqs, which is safe for - * __icmpv6_sk (because those never get directly used - * via userspace syscalls), but unsafe for normal sockets. - */ - lockdep_set_class(&sk->sk_dst_lock, - &icmpv6_socket_sk_dst_lock_key); - /* Enough space for 2 64K ICMP packets, including * sk_buff struct overhead. */ diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 3ff5208..a7ca2cd 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -111,14 +111,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); static inline -void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst, - const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - __ip6_dst_store(sk, dst, daddr, saddr); -} - -static inline struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) { return __sk_dst_check(sk, cookie); @@ -153,7 +145,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, dst = ip6_dst_lookup_flow(sk, fl6, final_p); if (!IS_ERR(dst)) - __inet6_csk_dst_store(sk, dst, NULL, NULL); + ip6_dst_store(sk, dst, NULL, NULL); } return dst; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6a50bb4..e7aab56 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -257,7 +257,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, inet->inet_rcv_saddr = LOOPBACK4_IPV6; sk->sk_gso_type = SKB_GSO_TCPV6; - __ip6_dst_store(sk, dst, NULL, NULL); + ip6_dst_store(sk, dst, NULL, NULL); if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && @@ -1060,7 +1060,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * */ newsk->sk_gso_type = SKB_GSO_TCPV6; - __ip6_dst_store(newsk, dst, NULL, NULL); + ip6_dst_store(newsk, dst, NULL, NULL); inet6_sk_rx_dst_set(newsk, skb); newtcp6sk = (struct tcp6_sock *)newsk; -- cgit v0.10.2 From df849ba3a88cdf4480decd7008f95ff627387c0f Mon Sep 17 00:00:00 2001 From: Yang Shi Date: Mon, 30 Nov 2015 14:24:07 -0800 Subject: arm64: bpf: add 'store immediate' instruction aarch64 doesn't have native store immediate instruction, such operation has to be implemented by the below instruction sequence: Load immediate to register Store register Signed-off-by: Yang Shi CC: Zi Shen Lim CC: Xi Wang Reviewed-by: Zi Shen Lim Signed-off-by: David S. Miller diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7cf032b..b162ad7 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -590,7 +590,25 @@ emit_cond_jmp: case BPF_ST | BPF_MEM | BPF_H: case BPF_ST | BPF_MEM | BPF_B: case BPF_ST | BPF_MEM | BPF_DW: - goto notyet; + /* Load imm to a register then store it */ + ctx->tmp_used = 1; + emit_a64_mov_i(1, tmp2, off, ctx); + emit_a64_mov_i(1, tmp, imm, ctx); + switch (BPF_SIZE(code)) { + case BPF_W: + emit(A64_STR32(tmp, dst, tmp2), ctx); + break; + case BPF_H: + emit(A64_STRH(tmp, dst, tmp2), ctx); + break; + case BPF_B: + emit(A64_STRB(tmp, dst, tmp2), ctx); + break; + case BPF_DW: + emit(A64_STR64(tmp, dst, tmp2), ctx); + break; + } + break; /* STX: *(size *)(dst + off) = src */ case BPF_STX | BPF_MEM | BPF_W: -- cgit v0.10.2 From 602dd62dfbda3e63a2d6a3cbde953ebe82bf5087 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Dec 2015 07:20:07 -0800 Subject: ipv6: sctp: implement sctp_v6_destroy_sock() Dmitry Vyukov reported a memory leak using IPV6 SCTP sockets. We need to call inet6_destroy_sock() to properly release inet6 specific fields. Reported-by: Dmitry Vyukov Signed-off-by: Eric Dumazet Acked-by: Daniel Borkmann Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f6161e3..03c8256 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -7379,6 +7379,13 @@ struct proto sctp_prot = { #if IS_ENABLED(CONFIG_IPV6) +#include +static void sctp_v6_destroy_sock(struct sock *sk) +{ + sctp_destroy_sock(sk); + inet6_destroy_sock(sk); +} + struct proto sctpv6_prot = { .name = "SCTPv6", .owner = THIS_MODULE, @@ -7388,7 +7395,7 @@ struct proto sctpv6_prot = { .accept = sctp_accept, .ioctl = sctp_ioctl, .init = sctp_init_sock, - .destroy = sctp_destroy_sock, + .destroy = sctp_v6_destroy_sock, .shutdown = sctp_shutdown, .setsockopt = sctp_setsockopt, .getsockopt = sctp_getsockopt, -- cgit v0.10.2 From 4eba7bb1d72d9bde67d810d09bf62dc207b63c5c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 1 Dec 2015 16:31:08 +0100 Subject: ipv4: igmp: Allow removing groups from a removed interface When a multicast group is joined on a socket, a struct ip_mc_socklist is appended to the sockets mc_list containing information about the joined group. If the interface is hot unplugged, this entry becomes stale. Prior to commit 52ad353a5344f ("igmp: fix the problem when mc leave group") it was possible to remove the stale entry by performing a IP_DROP_MEMBERSHIP, passing either the old ifindex or ip address on the interface. However, this fix enforces that the interface must still exist. Thus with time, the number of stale entries grows, until sysctl_igmp_max_memberships is reached and then it is not possible to join and more groups. The previous patch fixes an issue where a IP_DROP_MEMBERSHIP is performed without specifying the interface, either by ifindex or ip address. However here we do supply one of these. So loosen the restriction on device existence to only apply when the interface has not been specified. This then restores the ability to clean up the stale entries. Signed-off-by: Andrew Lunn Fixes: 52ad353a5344f "(igmp: fix the problem when mc leave group") Signed-off-by: David S. Miller diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6baf36e..05e4cba 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2126,7 +2126,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) ASSERT_RTNL(); in_dev = ip_mc_find_dev(net, imr); - if (!in_dev) { + if (!imr->imr_ifindex && !imr->imr_address.s_addr && !in_dev) { ret = -ENODEV; goto out; } @@ -2147,7 +2147,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) *imlp = iml->next_rcu; - ip_mc_dec_group(in_dev, group); + if (in_dev) + ip_mc_dec_group(in_dev, group); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); -- cgit v0.10.2 From 3ddda3e4c82dea58933bde8d0f6ef34470c360cb Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 2 Dec 2015 13:36:58 -0800 Subject: mpt3sas: fix Kconfig dependency problem for mpt2sas back compatibility The non-PCI builds of the O day test project are failing: On Thu, 2015-12-03 at 05:02 +0800, kbuild test robot wrote: > warning: (SCSI_MPT2SAS) selects SCSI_MPT3SAS which has unmet direct > dependencies (SCSI_LOWLEVEL && PCI && SCSI) The problem is that select and depend don't interact because Kconfig doesn't have a SAT solver, so depend picks up dependencies and select does onward selects, but select doesn't pick up dependencies. To fix this, we need to add the correct dependencies to the MPT2SAS option like this. Reported-by: kbuild test robot Fixes: b840c3627b6f4f856b333a14a72f8ed86da2f86c Signed-off-by: James Bottomley diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig index 25dc38f..b736dbc 100644 --- a/drivers/scsi/mpt3sas/Kconfig +++ b/drivers/scsi/mpt3sas/Kconfig @@ -76,6 +76,7 @@ config SCSI_MPT2SAS tristate "Legacy MPT2SAS config option" default n select SCSI_MPT3SAS + depends on PCI && SCSI ---help--- Dummy config option for backwards compatiblity: configure the MPT3SAS driver instead. -- cgit v0.10.2 From 13175303024c8f4cd09e51079a8fcbbe572111ec Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 1 Dec 2015 18:33:36 +0100 Subject: openvswitch: fix hangup on vxlan/gre/geneve device deletion Each openvswitch tunnel vport (vxlan,gre,geneve) holds a reference to the underlying tunnel device, but never released it when such device is deleted. Deleting the underlying device via the ip tool cause the kernel to hangup in the netdev_wait_allrefs() loop. This commit ensure that on device unregistration dp_detach_port_notify() is called for all vports that hold the device reference, properly releasing it. Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Fixes: b2acd1dc3949 ("openvswitch: Use regular GRE net_device instead of vport") Fixes: 6b001e682e90 ("openvswitch: Use Geneve device.") Signed-off-by: Paolo Abeni Acked-by: Flavio Leitner Acked-by: Pravin B Shelar Signed-off-by: David S. Miller diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index a7a80a6..653d073 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -58,7 +58,7 @@ void ovs_dp_notify_wq(struct work_struct *work) struct hlist_node *n; hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) { - if (vport->ops->type != OVS_VPORT_TYPE_NETDEV) + if (vport->ops->type == OVS_VPORT_TYPE_INTERNAL) continue; if (!(vport->dev->priv_flags & IFF_OVS_DATAPATH)) diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index b327368..6b0190b 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -180,9 +180,13 @@ void ovs_netdev_tunnel_destroy(struct vport *vport) if (vport->dev->priv_flags & IFF_OVS_DATAPATH) ovs_netdev_detach_dev(vport); - /* Early release so we can unregister the device */ + /* We can be invoked by both explicit vport deletion and + * underlying netdev deregistration; delete the link only + * if it's not already shutting down. + */ + if (vport->dev->reg_state == NETREG_REGISTERED) + rtnl_delete_link(vport->dev); dev_put(vport->dev); - rtnl_delete_link(vport->dev); vport->dev = NULL; rtnl_unlock(); -- cgit v0.10.2 From 4eaf3b84f2881c9c028f1d5e76c52ab575fe3a66 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Dec 2015 20:08:51 -0800 Subject: net_sched: fix qdisc_tree_decrease_qlen() races qdisc_tree_decrease_qlen() suffers from two problems on multiqueue devices. One problem is that it updates sch->q.qlen and sch->qstats.drops on the mq/mqprio root qdisc, while it should not : Daniele reported underflows errors : [ 681.774821] PAX: sch->q.qlen: 0 n: 1 [ 681.774825] PAX: size overflow detected in function qdisc_tree_decrease_qlen net/sched/sch_api.c:769 cicus.693_49 min, count: 72, decl: qlen; num: 0; context: sk_buff_head; [ 681.774954] CPU: 2 PID: 19 Comm: ksoftirqd/2 Tainted: G O 4.2.6.201511282239-1-grsec #1 [ 681.774955] Hardware name: ASUSTeK COMPUTER INC. X302LJ/X302LJ, BIOS X302LJ.202 03/05/2015 [ 681.774956] ffffffffa9a04863 0000000000000000 0000000000000000 ffffffffa990ff7c [ 681.774959] ffffc90000d3bc38 ffffffffa95d2810 0000000000000007 ffffffffa991002b [ 681.774960] ffffc90000d3bc68 ffffffffa91a44f4 0000000000000001 0000000000000001 [ 681.774962] Call Trace: [ 681.774967] [] dump_stack+0x4c/0x7f [ 681.774970] [] report_size_overflow+0x34/0x50 [ 681.774972] [] qdisc_tree_decrease_qlen+0x152/0x160 [ 681.774976] [] fq_codel_dequeue+0x7b1/0x820 [sch_fq_codel] [ 681.774978] [] ? qdisc_peek_dequeued+0xa0/0xa0 [sch_fq_codel] [ 681.774980] [] __qdisc_run+0x4d/0x1d0 [ 681.774983] [] net_tx_action+0xc2/0x160 [ 681.774985] [] __do_softirq+0xf1/0x200 [ 681.774987] [] run_ksoftirqd+0x1e/0x30 [ 681.774989] [] smpboot_thread_fn+0x150/0x260 [ 681.774991] [] ? sort_range+0x40/0x40 [ 681.774992] [] kthread+0xe4/0x100 [ 681.774994] [] ? kthread_worker_fn+0x170/0x170 [ 681.774995] [] ret_from_fork+0x3e/0x70 mq/mqprio have their own ways to report qlen/drops by folding stats on all their queues, with appropriate locking. A second problem is that qdisc_tree_decrease_qlen() calls qdisc_lookup() without proper locking : concurrent qdisc updates could corrupt the list that qdisc_match_from_root() parses to find a qdisc given its handle. Fix first problem adding a TCQ_F_NOPARENT qdisc flag that qdisc_tree_decrease_qlen() can use to abort its tree traversal, as soon as it meets a mq/mqprio qdisc children. Second problem can be fixed by RCU protection. Qdisc are already freed after RCU grace period, so qdisc_list_add() and qdisc_list_del() simply have to use appropriate rcu list variants. A future patch will add a per struct netdev_queue list anchor, so that qdisc_tree_decrease_qlen() can have more efficient lookups. Reported-by: Daniele Fucini Signed-off-by: Eric Dumazet Cc: Cong Wang Cc: Jamal Hadi Salim Signed-off-by: David S. Miller diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 4c79ce8..b2a8e63 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -61,6 +61,9 @@ struct Qdisc { */ #define TCQ_F_WARN_NONWC (1 << 16) #define TCQ_F_CPUSTATS 0x20 /* run using percpu statistics */ +#define TCQ_F_NOPARENT 0x40 /* root of its hierarchy : + * qdisc_tree_decrease_qlen() should stop. + */ u32 limit; const struct Qdisc_ops *ops; struct qdisc_size_table __rcu *stab; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index f43c8f3..7ec667d 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -253,7 +253,8 @@ int qdisc_set_default(const char *name) } /* We know handle. Find qdisc among all qdisc's attached to device - (root qdisc, all its children, children of children etc.) + * (root qdisc, all its children, children of children etc.) + * Note: caller either uses rtnl or rcu_read_lock() */ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) @@ -264,7 +265,7 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) root->handle == handle) return root; - list_for_each_entry(q, &root->list, list) { + list_for_each_entry_rcu(q, &root->list, list) { if (q->handle == handle) return q; } @@ -277,15 +278,18 @@ void qdisc_list_add(struct Qdisc *q) struct Qdisc *root = qdisc_dev(q)->qdisc; WARN_ON_ONCE(root == &noop_qdisc); - list_add_tail(&q->list, &root->list); + ASSERT_RTNL(); + list_add_tail_rcu(&q->list, &root->list); } } EXPORT_SYMBOL(qdisc_list_add); void qdisc_list_del(struct Qdisc *q) { - if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) - list_del(&q->list); + if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { + ASSERT_RTNL(); + list_del_rcu(&q->list); + } } EXPORT_SYMBOL(qdisc_list_del); @@ -750,14 +754,18 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) if (n == 0) return; drops = max_t(int, n, 0); + rcu_read_lock(); while ((parentid = sch->parent)) { if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS)) - return; + break; + if (sch->flags & TCQ_F_NOPARENT) + break; + /* TODO: perform the search on a per txq basis */ sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid)); if (sch == NULL) { - WARN_ON(parentid != TC_H_ROOT); - return; + WARN_ON_ONCE(parentid != TC_H_ROOT); + break; } cops = sch->ops->cl_ops; if (cops->qlen_notify) { @@ -768,6 +776,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) sch->q.qlen -= n; __qdisc_qstats_drop(sch, drops); } + rcu_read_unlock(); } EXPORT_SYMBOL(qdisc_tree_decrease_qlen); @@ -941,7 +950,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, } lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); if (!netif_is_multiqueue(dev)) - sch->flags |= TCQ_F_ONETXQUEUE; + sch->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; } sch->handle = handle; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index cb5d4ad..e82a1ad 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -737,7 +737,7 @@ static void attach_one_default_qdisc(struct net_device *dev, return; } if (!netif_is_multiqueue(dev)) - qdisc->flags |= TCQ_F_ONETXQUEUE; + qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; dev_queue->qdisc_sleeping = qdisc; } diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index f3cbaec..3e82f04 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -63,7 +63,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) if (qdisc == NULL) goto err; priv->qdiscs[ntx] = qdisc; - qdisc->flags |= TCQ_F_ONETXQUEUE; + qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; } sch->flags |= TCQ_F_MQROOT; @@ -156,7 +156,7 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, *old = dev_graft_qdisc(dev_queue, new); if (new) - new->flags |= TCQ_F_ONETXQUEUE; + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; if (dev->flags & IFF_UP) dev_activate(dev); return 0; diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 3811a74..ad70ecf 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -132,7 +132,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) goto err; } priv->qdiscs[i] = qdisc; - qdisc->flags |= TCQ_F_ONETXQUEUE; + qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; } /* If the mqprio options indicate that hardware should own @@ -209,7 +209,7 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, *old = dev_graft_qdisc(dev_queue, new); if (new) - new->flags |= TCQ_F_ONETXQUEUE; + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; if (dev->flags & IFF_UP) dev_activate(dev); -- cgit v0.10.2 From 39198ec98751477313f30569b935503b216f85d0 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 2 Dec 2015 08:12:13 +0200 Subject: net: lpc_eth: remove irq > NR_IRQS check from probe() If the driver is used on an ARM platform with SPARSE_IRQ defined, semantics of NR_IRQS is different (minimal value of virtual irqs) and by default it is set to 16, see arch/arm/include/asm/irq.h. This value may be less than the actual number of virtual irqs, which may break the driver initialization. The check removal allows to use the driver on such a platform, and, if irq controller driver works correctly, the check is not needed on legacy platforms. Fixes a runtime problem: lpc-eth 31060000.ethernet: error getting resources. lpc_eth: lpc-eth: not found (-6). Signed-off-by: Vladimir Zapolskiy Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index b159ef8..0576651 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1326,7 +1326,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) /* Get platform resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if ((!res) || (irq < 0) || (irq >= NR_IRQS)) { + if (!res || irq < 0) { dev_err(&pdev->dev, "error getting resources.\n"); ret = -ENXIO; goto err_exit; -- cgit v0.10.2 From 1fc2cfd03bbf8f1f8b6b90f0858faba8bd6631c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Huang Date: Wed, 2 Dec 2015 01:54:06 -0500 Subject: bnxt_en: Fixed incorrect implementation of ndo_set_mac_address The existing ndo_set_mac_address only copies the new MAC addr and didn't set the new MAC addr to the HW. The correct way is to delete the existing default MAC filter from HW and add the new one. Because of RFS filters are also dependent on the default mac filter l2 context, the driver must go thru close_nic() to delete the default MAC and RFS filters, then open_nic() to set the default MAC address to HW. Signed-off-by: Jeffrey Huang Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index db15c5e..651b587 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5212,13 +5212,22 @@ init_err: static int bnxt_change_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; + struct bnxt *bp = netdev_priv(dev); + int rc = 0; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + if (ether_addr_equal(addr->sa_data, dev->dev_addr)) + return 0; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + if (netif_running(dev)) { + bnxt_close_nic(bp, false, false); + rc = bnxt_open_nic(bp, false, false); + } - return 0; + return rc; } /* rtnl_lock held */ -- cgit v0.10.2 From bdd4347b33f480187b44699cf1caac9400496d6d Mon Sep 17 00:00:00 2001 From: Jeffrey Huang Date: Wed, 2 Dec 2015 01:54:07 -0500 Subject: bnxt_en: enforce proper storing of MAC address For PF, the bp->pf.mac_addr always holds the permanent MAC addr assigned by the HW. For VF, the bp->vf.mac_addr always holds the administrator assigned VF MAC addr. The random generated VF MAC addr should never get stored to bp->vf.mac_addr. This way, when the VF wants to change the MAC address, we can tell if the adminstrator has already set it and disallow the VF from changing it. v2: Fix compile error if CONFIG_BNXT_SRIOV is not set. Signed-off-by: Jeffrey Huang Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 651b587..f0481dc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3625,6 +3625,7 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) pf->fw_fid = le16_to_cpu(resp->fid); pf->port_id = le16_to_cpu(resp->port_id); memcpy(pf->mac_addr, resp->perm_mac_address, ETH_ALEN); + memcpy(bp->dev->dev_addr, pf->mac_addr, ETH_ALEN); pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx); pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings); pf->max_tx_rings = le16_to_cpu(resp->max_tx_rings); @@ -3648,8 +3649,11 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) vf->fw_fid = le16_to_cpu(resp->fid); memcpy(vf->mac_addr, resp->perm_mac_address, ETH_ALEN); - if (!is_valid_ether_addr(vf->mac_addr)) - random_ether_addr(vf->mac_addr); + if (is_valid_ether_addr(vf->mac_addr)) + /* overwrite netdev dev_adr with admin VF MAC */ + memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN); + else + random_ether_addr(bp->dev->dev_addr); vf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx); vf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings); @@ -5218,6 +5222,11 @@ static int bnxt_change_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; +#ifdef CONFIG_BNXT_SRIOV + if (BNXT_VF(bp) && is_valid_ether_addr(bp->vf.mac_addr)) + return -EADDRNOTAVAIL; +#endif + if (ether_addr_equal(addr->sa_data, dev->dev_addr)) return 0; @@ -5695,15 +5704,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); dflt_rings = netif_get_num_default_rss_queues(); - if (BNXT_PF(bp)) { - memcpy(dev->dev_addr, bp->pf.mac_addr, ETH_ALEN); + if (BNXT_PF(bp)) bp->pf.max_irqs = max_irqs; - } else { #if defined(CONFIG_BNXT_SRIOV) - memcpy(dev->dev_addr, bp->vf.mac_addr, ETH_ALEN); + else bp->vf.max_irqs = max_irqs; #endif - } bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings); bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings); bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index f4cf688..7a9af28 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -804,10 +804,9 @@ void bnxt_update_vf_mac(struct bnxt *bp) if (!is_valid_ether_addr(resp->perm_mac_address)) goto update_vf_mac_exit; - if (ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr)) - goto update_vf_mac_exit; - - memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN); + if (!ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr)) + memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN); + /* overwrite netdev dev_adr with admin VF MAC */ memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN); update_vf_mac_exit: mutex_unlock(&bp->hwrm_cmd_lock); -- cgit v0.10.2 From b664f008b0d885db1d5617ed1c51d29a8c04da93 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 2 Dec 2015 01:54:08 -0500 Subject: bnxt_en: Setup uc_list mac filters after resetting the chip. Call bnxt_cfg_rx_mode() in bnxt_init_chip() to setup uc_list and mc_list mac address filters. Before the patch, uc_list is not setup again after chip reset (such as ethtool ring size change) and macvlans don't work any more after that. Modify bnxt_cfg_rx_mode() to return error codes appropriately so that the init chip sequence can detect any failures. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index f0481dc..bdf094f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3884,6 +3884,8 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) #endif } +static int bnxt_cfg_rx_mode(struct bnxt *); + static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) { int rc = 0; @@ -3950,11 +3952,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) bp->vnic_info[0].rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS; - rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0); - if (rc) { - netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc); + rc = bnxt_cfg_rx_mode(bp); + if (rc) goto err_out; - } rc = bnxt_hwrm_set_coal(bp); if (rc) @@ -4869,7 +4869,7 @@ static void bnxt_set_rx_mode(struct net_device *dev) } } -static void bnxt_cfg_rx_mode(struct bnxt *bp) +static int bnxt_cfg_rx_mode(struct bnxt *bp) { struct net_device *dev = bp->dev; struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; @@ -4918,6 +4918,7 @@ static void bnxt_cfg_rx_mode(struct bnxt *bp) netdev_err(bp->dev, "HWRM vnic filter failure rc: %x\n", rc); vnic->uc_filter_count = i; + return rc; } } @@ -4926,6 +4927,8 @@ skip_uc: if (rc) netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc); + + return rc; } static netdev_features_t bnxt_fix_features(struct net_device *dev, -- cgit v0.10.2 From cf18b7788fe1bf99e9c2ab580b065bf2d3cb1a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Thu, 3 Dec 2015 10:02:35 +0100 Subject: net: phy: reset only targeted phy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible to address another chip on same MDIO bus. The case is correctly handled for media advertising. It is taken into account only if mii_data->phy_id == phydev->addr. However, this condition was missing for reset case. Signed-off-by: Jérôme Pouiller Signed-off-by: David S. Miller diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 48ce6ef..47cd306d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -448,7 +448,8 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) mdiobus_write(phydev->bus, mii_data->phy_id, mii_data->reg_num, val); - if (mii_data->reg_num == MII_BMCR && + if (mii_data->phy_id == phydev->addr && + mii_data->reg_num == MII_BMCR && val & BMCR_RESET) return phy_init_hw(phydev); -- cgit v0.10.2 From 265e2cf672aaa9421e7012b4aa30c0ed80f1a447 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 1 Dec 2015 09:39:31 -0800 Subject: PM / Domains: Fix bad of_node_put() in failure paths of genpd_dev_pm_attach() It looks like these meant to be unreffing the of_parse_phandle_with_args() node, since the error paths above it don't do of_node_put. That function returns a new ref in pd_args.np, though, not a new ref on dev->of_node. Also, it would have leaked the ref in the success case. Fixes "ERROR: Bad of_node_put()" on bcm2835 in the -EPROBE_DEFER case. Fixes: aa42240ab254 (PM / Domains: Add generic OF-based PM domain look-up) Signed-off-by: Eric Anholt Acked-by: Ulf Hansson Acked-by: Kevin Hilman Cc: 3.18+ # 3.18+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index f932058..4e3a1f1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1773,10 +1773,10 @@ int genpd_dev_pm_attach(struct device *dev) } pd = of_genpd_get_from_provider(&pd_args); + of_node_put(pd_args.np); if (IS_ERR(pd)) { dev_dbg(dev, "%s() failed to find PM domain: %ld\n", __func__, PTR_ERR(pd)); - of_node_put(dev->of_node); return -EPROBE_DEFER; } @@ -1794,7 +1794,6 @@ int genpd_dev_pm_attach(struct device *dev) if (ret < 0) { dev_err(dev, "failed to add to PM domain %s: %d", pd->name, ret); - of_node_put(dev->of_node); goto out; } -- cgit v0.10.2 From a0af2e538c80f3e47f1d6ddf120a153ad909e8ad Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 2 Dec 2015 09:24:46 -0800 Subject: drm: Fix an unwanted master inheritance v2 A client calling drmSetMaster() using a file descriptor that was opened when another client was master would inherit the latter client's master object and all its authenticated clients. This is unwanted behaviour, and when this happens, instead allocate a brand new master object for the client calling drmSetMaster(). Fixes a BUG() throw in vmw_master_set(). Cc: Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 9362609..7dd6728 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -160,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, goto out_unlock; } + if (!file_priv->allowed_master) { + ret = drm_new_set_master(dev, file_priv); + goto out_unlock; + } + file_priv->minor->master = drm_master_get(file_priv->master); file_priv->is_master = 1; if (dev->driver->master_set) { diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index c59ce4d..6b5625e 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -126,6 +126,60 @@ static int drm_cpu_valid(void) } /** + * drm_new_set_master - Allocate a new master object and become master for the + * associated master realm. + * + * @dev: The associated device. + * @fpriv: File private identifying the client. + * + * This function must be called with dev::struct_mutex held. + * Returns negative error code on failure. Zero on success. + */ +int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv) +{ + struct drm_master *old_master; + int ret; + + lockdep_assert_held_once(&dev->master_mutex); + + /* create a new master */ + fpriv->minor->master = drm_master_create(fpriv->minor); + if (!fpriv->minor->master) + return -ENOMEM; + + /* take another reference for the copy in the local file priv */ + old_master = fpriv->master; + fpriv->master = drm_master_get(fpriv->minor->master); + + if (dev->driver->master_create) { + ret = dev->driver->master_create(dev, fpriv->master); + if (ret) + goto out_err; + } + if (dev->driver->master_set) { + ret = dev->driver->master_set(dev, fpriv, true); + if (ret) + goto out_err; + } + + fpriv->is_master = 1; + fpriv->allowed_master = 1; + fpriv->authenticated = 1; + if (old_master) + drm_master_put(&old_master); + + return 0; + +out_err: + /* drop both references and restore old master on failure */ + drm_master_put(&fpriv->minor->master); + drm_master_put(&fpriv->master); + fpriv->master = old_master; + + return ret; +} + +/** * Called whenever a process opens /dev/drm. * * \param filp file pointer. @@ -189,35 +243,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) mutex_lock(&dev->master_mutex); if (drm_is_primary_client(priv) && !priv->minor->master) { /* create a new master */ - priv->minor->master = drm_master_create(priv->minor); - if (!priv->minor->master) { - ret = -ENOMEM; + ret = drm_new_set_master(dev, priv); + if (ret) goto out_close; - } - - priv->is_master = 1; - /* take another reference for the copy in the local file priv */ - priv->master = drm_master_get(priv->minor->master); - priv->authenticated = 1; - - if (dev->driver->master_create) { - ret = dev->driver->master_create(dev, priv->master); - if (ret) { - /* drop both references if this fails */ - drm_master_put(&priv->minor->master); - drm_master_put(&priv->master); - goto out_close; - } - } - if (dev->driver->master_set) { - ret = dev->driver->master_set(dev, priv, true); - if (ret) { - /* drop both references if this fails */ - drm_master_put(&priv->minor->master); - drm_master_put(&priv->master); - goto out_close; - } - } } else if (drm_is_primary_client(priv)) { /* get a reference to the master */ priv->master = drm_master_get(priv->minor->master); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0b921ae..441b26e 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -309,6 +309,11 @@ struct drm_file { unsigned universal_planes:1; /* true if client understands atomic properties */ unsigned atomic:1; + /* + * This client is allowed to gain master privileges for @master. + * Protected by struct drm_device::master_mutex. + */ + unsigned allowed_master:1; struct pid *pid; kuid_t uid; @@ -910,6 +915,7 @@ extern int drm_open(struct inode *inode, struct file *filp); extern ssize_t drm_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset); extern int drm_release(struct inode *inode, struct file *filp); +extern int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv); /* Mapping support (drm_vm.h) */ extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); -- cgit v0.10.2 From 4fd41a8552afc01054d9d9fc7f1a63c324867d27 Mon Sep 17 00:00:00 2001 From: Ken Xue Date: Tue, 1 Dec 2015 14:45:46 +0800 Subject: SCSI: Fix NULL pointer dereference in runtime PM The routines in scsi_pm.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 checking q->dev in block layer before handle runtime PM. Since ses doesn't define any PM callbacks and call blk_pm_runtime_init(), the crash won't occur. This fixes Bugzilla #101371. https://bugzilla.kernel.org/show_bug.cgi?id=101371 More discussion can be found from below link. http://marc.info/?l=linux-scsi&m=144163730531875&w=2 Signed-off-by: Ken Xue Acked-by: Alan Stern Cc: Xiangliang Yu Cc: James E.J. Bottomley Cc: Jens Axboe Cc: Michael Terry Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index a0af404..3636be4 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -3405,6 +3405,9 @@ int blk_pre_runtime_suspend(struct request_queue *q) { int ret = 0; + if (!q->dev) + return ret; + spin_lock_irq(q->queue_lock); if (q->nr_pending) { ret = -EBUSY; @@ -3432,6 +3435,9 @@ EXPORT_SYMBOL(blk_pre_runtime_suspend); */ void blk_post_runtime_suspend(struct request_queue *q, int err) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); if (!err) { q->rpm_status = RPM_SUSPENDED; @@ -3456,6 +3462,9 @@ EXPORT_SYMBOL(blk_post_runtime_suspend); */ void blk_pre_runtime_resume(struct request_queue *q) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); q->rpm_status = RPM_RESUMING; spin_unlock_irq(q->queue_lock); @@ -3478,6 +3487,9 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); */ void blk_post_runtime_resume(struct request_queue *q, int err) { + if (!q->dev) + return; + spin_lock_irq(q->queue_lock); if (!err) { q->rpm_status = RPM_ACTIVE; -- cgit v0.10.2 From bbc8764f80eb872d2b36302882ddfc9882de4b16 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Nov 2015 17:37:31 +0100 Subject: drm/nouveau: Fix pre-nv50 pageflip events (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently pre-nv50 pageflip events happen before the actual vblank period. Therefore that functionality got semi-disabled in commit af4870e406126b7ac0ae7c7ce5751f25ebe60f28 Author: Mario Kleiner Date: Tue May 13 00:42:08 2014 +0200 drm/nouveau/kms/nv04-nv40: fix pageflip events via special case. Unfortunately that hack got uprooted in commit cc1ef118fc099295ae6aabbacc8af94d8d8885eb Author: Thierry Reding Date: Wed Aug 12 17:00:31 2015 +0200 drm/irq: Make pipe unsigned and name consistent Triggering a warning when trying to sample the vblank timestamp for a non-existing pipe. There's a few ways to fix this: - Open-code the old behaviour, which just enshrines this slight breakage of the userspace ABI. - Revert Mario's commit and again inflict broken timestamps, again not pretty. - Fix this for real by delaying the pageflip TS until the next vblank interrupt, thereby making it accurate. This patch implements the third option. Since having a page flip interrupt that happens when the pageflip gets armed and not when it completes in the next vblank seems to be fairly common (older i915 hw works very similarly) create a new helper to arm vblank events for such drivers. v2 (Mario Kleiner): - Fix function prototypes in drmP.h - Add missing vblank_put() for pageflip completion without pageflip event. - Initialize sequence number for queued pageflip event to avoid trouble in drm_handle_vblank_events(). - Remove dead code and spelling fix. v3 (Mario Kleiner): - Add a signed-off-by and cc stable tag per Ilja's advice. v4 (Thierry Reding): - Fix kerneldoc typo, discovered by Michel Dänzer - Rearrange tags and changelog Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=106431 Cc: Thierry Reding Cc: Mario Kleiner Acked-by: Ben Skeggs Cc: Ilia Mirkin Signed-off-by: Daniel Vetter Reviewed-by: Mario Kleiner Cc: stable@vger.kernel.org # v4.3 Signed-off-by: Mario Kleiner Signed-off-by: Thierry Reding Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 2151ea5..607f493 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -980,7 +980,8 @@ static void send_vblank_event(struct drm_device *dev, struct drm_pending_vblank_event *e, unsigned long seq, struct timeval *now) { - WARN_ON_SMP(!spin_is_locked(&dev->event_lock)); + assert_spin_locked(&dev->event_lock); + e->event.sequence = seq; e->event.tv_sec = now->tv_sec; e->event.tv_usec = now->tv_usec; @@ -993,6 +994,57 @@ static void send_vblank_event(struct drm_device *dev, } /** + * drm_arm_vblank_event - arm vblank event after pageflip + * @dev: DRM device + * @pipe: CRTC index + * @e: the event to prepare to send + * + * A lot of drivers need to generate vblank events for the very next vblank + * interrupt. For example when the page flip interrupt happens when the page + * flip gets armed, but not when it actually executes within the next vblank + * period. This helper function implements exactly the required vblank arming + * behaviour. + * + * Caller must hold event lock. Caller must also hold a vblank reference for + * the event @e, which will be dropped when the next vblank arrives. + * + * This is the legacy version of drm_crtc_arm_vblank_event(). + */ +void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, + struct drm_pending_vblank_event *e) +{ + assert_spin_locked(&dev->event_lock); + + e->pipe = pipe; + e->event.sequence = drm_vblank_count(dev, pipe); + list_add_tail(&e->base.link, &dev->vblank_event_list); +} +EXPORT_SYMBOL(drm_arm_vblank_event); + +/** + * drm_crtc_arm_vblank_event - arm vblank event after pageflip + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * A lot of drivers need to generate vblank events for the very next vblank + * interrupt. For example when the page flip interrupt happens when the page + * flip gets armed, but not when it actually executes within the next vblank + * period. This helper function implements exactly the required vblank arming + * behaviour. + * + * Caller must hold event lock. Caller must also hold a vblank reference for + * the event @e, which will be dropped when the next vblank arrives. + * + * This is the native KMS version of drm_arm_vblank_event(). + */ +void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e); +} +EXPORT_SYMBOL(drm_crtc_arm_vblank_event); + +/** * drm_send_vblank_event - helper to send vblank event after pageflip * @dev: DRM device * @pipe: CRTC index diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index db6bc67..64c8d93 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -829,7 +829,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, struct drm_device *dev = drm->dev; struct nouveau_page_flip_state *s; unsigned long flags; - int crtcid = -1; spin_lock_irqsave(&dev->event_lock, flags); @@ -841,15 +840,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { - /* Vblank timestamps/counts are only correct on >= NV-50 */ - if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) - crtcid = s->crtc; + if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { + drm_arm_vblank_event(dev, s->crtc, s->event); + } else { + drm_send_vblank_event(dev, s->crtc, s->event); - drm_send_vblank_event(dev, crtcid, s->event); + /* Give up ownership of vblank for page-flipped crtc */ + drm_vblank_put(dev, s->crtc); + } + } + else { + /* Give up ownership of vblank for page-flipped crtc */ + drm_vblank_put(dev, s->crtc); } - - /* Give up ownership of vblank for page-flipped crtc */ - drm_vblank_put(dev, s->crtc); list_del(&s->head); if (ps) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 441b26e..0a271ca 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -953,6 +953,10 @@ extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe, struct drm_pending_vblank_event *e); extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e); +extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe, + struct drm_pending_vblank_event *e); +extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe); extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc); extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe); -- cgit v0.10.2 From 70f1528747651b20c7769d3516ade369f9963237 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 30 Nov 2015 11:10:33 +0100 Subject: x86/mm: Fix regression with huge pages on PAE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent PAT patchset has caused issue on 32-bit PAE machines: page:eea45000 count:0 mapcount:-128 mapping: (null) index:0x0 flags: 0x40000000() page dumped because: VM_BUG_ON_PAGE(page_mapcount(page) < 0) ------------[ cut here ]------------ kernel BUG at /home/build/linux-boris/mm/huge_memory.c:1485! invalid opcode: 0000 [#1] SMP [...] Call Trace: unmap_single_vma ? __wake_up unmap_vmas unmap_region do_munmap vm_munmap SyS_munmap do_fast_syscall_32 ? __do_page_fault sysenter_past_esp Code: ... EIP: [] zap_huge_pmd+0x240/0x260 SS:ESP 0068:f6459d98 The problem is in pmd_pfn_mask() and pmd_flags_mask(). These helpers use PMD_PAGE_MASK to calculate resulting mask. PMD_PAGE_MASK is 'unsigned long', not 'unsigned long long' as phys_addr_t is on 32-bit PAE (ARCH_PHYS_ADDR_T_64BIT). As a result, the upper bits of resulting mask get truncated. pud_pfn_mask() and pud_flags_mask() aren't problematic since we don't have PUD page table level on 32-bit systems, but it's reasonable to keep them consistent with PMD counterpart. Introduce PHYSICAL_PMD_PAGE_MASK and PHYSICAL_PUD_PAGE_MASK in addition to existing PHYSICAL_PAGE_MASK and reworks helpers to use them. Reported-and-Tested-by: Boris Ostrovsky Signed-off-by: Kirill A. Shutemov [ Fix -Woverflow warnings from the realmode code. ] Signed-off-by: Borislav Petkov Reviewed-by: Toshi Kani Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jürgen Gross Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: elliott@hpe.com Cc: konrad.wilk@oracle.com Cc: linux-mm Fixes: f70abb0fc3da ("x86/asm: Fix pud/pmd interfaces to handle large PAT bit") Link: http://lkml.kernel.org/r/1448878233-11390-2-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 0033e96..9011a88 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "bitops.h" #include "ctype.h" diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c index aa8a96b..95c7a81 100644 --- a/arch/x86/boot/video-mode.c +++ b/arch/x86/boot/video-mode.c @@ -19,6 +19,8 @@ #include "video.h" #include "vesa.h" +#include + /* * Common variables */ diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 05111bb..77780e3 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -13,6 +13,8 @@ * Select video mode */ +#include + #include "boot.h" #include "video.h" #include "vesa.h" diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index c5b7fb2..cc071c6 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -9,19 +9,21 @@ #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT) +#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1)) + +#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) +#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) + #define __PHYSICAL_MASK ((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1)) #define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) -/* Cast PAGE_MASK to a signed type so that it is sign-extended if +/* Cast *PAGE_MASK to a signed type so that it is sign-extended if virtual addresses are 32-bits but physical addresses are larger (ie, 32-bit PAE). */ #define PHYSICAL_PAGE_MASK (((signed long)PAGE_MASK) & __PHYSICAL_MASK) - -#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT) -#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1)) - -#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) -#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) +#define PHYSICAL_PMD_PAGE_MASK (((signed long)PMD_PAGE_MASK) & __PHYSICAL_MASK) +#define PHYSICAL_PUD_PAGE_MASK (((signed long)PUD_PAGE_MASK) & __PHYSICAL_MASK) #define HPAGE_SHIFT PMD_SHIFT #define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index dd5b0aa..a471cad 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -279,17 +279,14 @@ static inline pmdval_t native_pmd_val(pmd_t pmd) static inline pudval_t pud_pfn_mask(pud_t pud) { if (native_pud_val(pud) & _PAGE_PSE) - return PUD_PAGE_MASK & PHYSICAL_PAGE_MASK; + return PHYSICAL_PUD_PAGE_MASK; else return PTE_PFN_MASK; } static inline pudval_t pud_flags_mask(pud_t pud) { - if (native_pud_val(pud) & _PAGE_PSE) - return ~(PUD_PAGE_MASK & (pudval_t)PHYSICAL_PAGE_MASK); - else - return ~PTE_PFN_MASK; + return ~pud_pfn_mask(pud); } static inline pudval_t pud_flags(pud_t pud) @@ -300,17 +297,14 @@ static inline pudval_t pud_flags(pud_t pud) static inline pmdval_t pmd_pfn_mask(pmd_t pmd) { if (native_pmd_val(pmd) & _PAGE_PSE) - return PMD_PAGE_MASK & PHYSICAL_PAGE_MASK; + return PHYSICAL_PMD_PAGE_MASK; else return PTE_PFN_MASK; } static inline pmdval_t pmd_flags_mask(pmd_t pmd) { - if (native_pmd_val(pmd) & _PAGE_PSE) - return ~(PMD_PAGE_MASK & (pmdval_t)PHYSICAL_PAGE_MASK); - else - return ~PTE_PFN_MASK; + return ~pmd_pfn_mask(pmd); } static inline pmdval_t pmd_flags(pmd_t pmd) diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 48d34d2..cd0fc0c 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -1,7 +1,6 @@ #ifndef _ASM_X86_PLATFORM_H #define _ASM_X86_PLATFORM_H -#include #include struct mpc_bus; -- cgit v0.10.2 From 642c2d671ceff40e9453203ea0c66e991e11e249 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 30 Nov 2015 12:56:15 +0100 Subject: perf: Fix PERF_EVENT_IOC_PERIOD deadlock Dmitry reported a fairly silly recursive lock deadlock for PERF_EVENT_IOC_PERIOD, fix this by explicitly doing the inactive part of __perf_event_period() instead of calling that function. Reported-by: Dmitry Vyukov Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Potapenko Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Eric Dumazet Cc: Jiri Olsa Cc: Kostya Serebryany Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sasha Levin Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: c7999c6f3fed ("perf: Fix PERF_EVENT_IOC_PERIOD migration race") Link: http://lkml.kernel.org/r/20151130115615.GJ17308@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 5854fcf..49a5118 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4225,7 +4225,14 @@ retry: goto retry; } - __perf_event_period(&pe); + if (event->attr.freq) { + event->attr.sample_freq = value; + } else { + event->attr.sample_period = value; + event->hw.sample_period = value; + } + + local64_set(&event->hw.period_left, 0); raw_spin_unlock_irq(&ctx->lock); return 0; -- cgit v0.10.2 From 68985633bccb6066bf1803e316fbc6c1f5b796d6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Dec 2015 14:04:04 +0100 Subject: sched/wait: Fix signal handling in bit wait helpers Vladimir reported getting RCU stall warnings and bisected it back to commit: 743162013d40 ("sched: Remove proliferation of wait_on_bit() action functions") That commit inadvertently reversed the calls to schedule() and signal_pending(), thereby not handling the case where the signal receives while we sleep. Reported-by: Vladimir Murzin Tested-by: Vladimir Murzin Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: mark.rutland@arm.com Cc: neilb@suse.de Cc: oleg@redhat.com Fixes: 743162013d40 ("sched: Remove proliferation of wait_on_bit() action functions") Fixes: cbbce8220949 ("SCHED: add some "wait..on_bit...timeout()" interfaces.") Link: http://lkml.kernel.org/r/20151201130404.GL3816@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 052e026..f10bd87 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -583,18 +583,18 @@ EXPORT_SYMBOL(wake_up_atomic_t); __sched int bit_wait(struct wait_bit_key *word) { - if (signal_pending_state(current->state, current)) - return 1; schedule(); + if (signal_pending(current)) + return -EINTR; return 0; } EXPORT_SYMBOL(bit_wait); __sched int bit_wait_io(struct wait_bit_key *word) { - if (signal_pending_state(current->state, current)) - return 1; io_schedule(); + if (signal_pending(current)) + return -EINTR; return 0; } EXPORT_SYMBOL(bit_wait_io); @@ -602,11 +602,11 @@ EXPORT_SYMBOL(bit_wait_io); __sched int bit_wait_timeout(struct wait_bit_key *word) { unsigned long now = READ_ONCE(jiffies); - if (signal_pending_state(current->state, current)) - return 1; if (time_after_eq(now, word->timeout)) return -EAGAIN; schedule_timeout(word->timeout - now); + if (signal_pending(current)) + return -EINTR; return 0; } EXPORT_SYMBOL_GPL(bit_wait_timeout); @@ -614,11 +614,11 @@ EXPORT_SYMBOL_GPL(bit_wait_timeout); __sched int bit_wait_io_timeout(struct wait_bit_key *word) { unsigned long now = READ_ONCE(jiffies); - if (signal_pending_state(current->state, current)) - return 1; if (time_after_eq(now, word->timeout)) return -EAGAIN; io_schedule_timeout(word->timeout - now); + if (signal_pending(current)) + return -EINTR; return 0; } EXPORT_SYMBOL_GPL(bit_wait_io_timeout); -- cgit v0.10.2 From 119d6f6a3be8b424b200dcee56e74484d5445f7e Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 30 Nov 2015 20:34:20 -0500 Subject: sched/core: Remove false-positive warning from wake_up_process() Because wakeups can (fundamentally) be late, a task might not be in the expected state. Therefore testing against a task's state is racy, and can yield false positives. Signed-off-by: Sasha Levin Signed-off-by: Peter Zijlstra (Intel) Acked-by: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: oleg@redhat.com Fixes: 9067ac85d533 ("wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED task") Link: http://lkml.kernel.org/r/1448933660-23082-1-git-send-email-sasha.levin@oracle.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4d568ac..fc8c987 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2039,7 +2039,6 @@ out: */ int wake_up_process(struct task_struct *p) { - WARN_ON(task_is_stopped_or_traced(p)); return try_to_wake_up(p, TASK_NORMAL, 0); } EXPORT_SYMBOL(wake_up_process); -- cgit v0.10.2 From 8295c69925ad53ec32ca54ac9fc194ff21bc40e2 Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Wed, 2 Dec 2015 19:52:59 +0800 Subject: sched/core: Clear the root_domain cpumasks in init_rootdomain() root_domain::rto_mask allocated through alloc_cpumask_var() contains garbage data, this may cause problems. For instance, When doing pull_rt_task(), it may do useless iterations if rto_mask retains some extra garbage bits. Worse still, this violates the isolated domain rule for clustered scheduling using cpuset, because the tasks(with all the cpus allowed) belongs to one root domain can be pulled away into another root domain. The patch cleans the garbage by using zalloc_cpumask_var() instead of alloc_cpumask_var() for root_domain::rto_mask allocation, thereby addressing the issues. Do the same thing for root_domain's other cpumask memembers: dlo_mask, span, and online. Signed-off-by: Xunlei Pang Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1449057179-29321-1-git-send-email-xlpang@redhat.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index fc8c987..eee4ee6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5846,13 +5846,13 @@ static int init_rootdomain(struct root_domain *rd) { memset(rd, 0, sizeof(*rd)); - if (!alloc_cpumask_var(&rd->span, GFP_KERNEL)) + if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL)) goto out; - if (!alloc_cpumask_var(&rd->online, GFP_KERNEL)) + if (!zalloc_cpumask_var(&rd->online, GFP_KERNEL)) goto free_span; - if (!alloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL)) + if (!zalloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL)) goto free_online; - if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) + if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) goto free_dlo_mask; init_dl_bw(&rd->dl_bw); -- cgit v0.10.2 From 2541117b0cf79977fa11a0d6e17d61010677bd7b Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Thu, 19 Nov 2015 16:47:28 +0100 Subject: sched/cputime: Fix invalid gtime in proc /proc/stats shows invalid gtime when the thread is running in guest. When vtime accounting is not enabled, we cannot get a valid delta. The delta is calculated with now - tsk->vtime_snap, but tsk->vtime_snap is only updated when vtime accounting is runtime enabled. This patch makes task_gtime() just return gtime without computing the buggy non-existing tickless delta when vtime accounting is not enabled. Use context_tracking_is_enabled() to check if vtime is accounting on some cpu, in which case only we need to check the tickless delta. This way we fix the gtime value regression on machines not running nohz full. The kernel config contains CONFIG_VIRT_CPU_ACCOUNTING_GEN=y and CONFIG_NO_HZ_FULL_ALL=n and boot without nohz_full. I ran and stop a busy loop in VM and see the gtime in host. Dump the 43rd field which shows the gtime in every second: # while :; do awk '{print $3" "$43}' /proc/3955/task/4014/stat; sleep 1; done S 4348 R 7064566 R 7064766 R 7064967 R 7065168 S 4759 S 4759 During running busy loop, it returns large value. After applying this patch, we can see right gtime. # while :; do awk '{print $3" "$43}' /proc/10913/task/10956/stat; sleep 1; done S 5338 R 5365 R 5465 R 5566 R 5666 S 5726 S 5726 Signed-off-by: Hiroshi Shimamoto Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra (Intel) Cc: Chris Metcalf Cc: Christoph Lameter Cc: Linus Torvalds Cc: Luiz Capitulino Cc: Mike Galbraith Cc: Paul E . McKenney Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1447948054-28668-2-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 26a5446..05de80b 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -788,6 +788,9 @@ cputime_t task_gtime(struct task_struct *t) unsigned int seq; cputime_t gtime; + if (!context_tracking_is_enabled()) + return t->gtime; + do { seq = read_seqbegin(&t->vtime_seqlock); -- cgit v0.10.2 From b75a22531588e77aa8c2daf228c9723916ae2cd0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 6 Oct 2015 14:36:17 +0200 Subject: sched/core: Better document the try_to_wake_up() barriers Explain how the control dependency and smp_rmb() end up providing ACQUIRE semantics and pair with smp_store_release() in finish_lock_switch(). Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Oleg Nesterov Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index eee4ee6..b64f163 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1953,7 +1953,13 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) while (p->on_cpu) cpu_relax(); /* - * Pairs with the smp_wmb() in finish_lock_switch(). + * Combined with the control dependency above, we have an effective + * smp_load_acquire() without the need for full barriers. + * + * Pairs with the smp_store_release() in finish_lock_switch(). + * + * This ensures that tasks getting woken will be fully ordered against + * their previous state and preserve Program Order. */ smp_rmb(); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index efd3bfc..b242775 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1073,6 +1073,9 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) * We must ensure this doesn't happen until the switch is completely * finished. * + * In particular, the load of prev->state in finish_task_switch() must + * happen before this. + * * Pairs with the control dependency and rmb in try_to_wake_up(). */ smp_store_release(&prev->on_cpu, 0); -- cgit v0.10.2 From ecf7d01c229d11a44609c0067889372c91fb4f36 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 7 Oct 2015 14:14:13 +0200 Subject: sched/core: Fix an SMP ordering race in try_to_wake_up() vs. schedule() Oleg noticed that its possible to falsely observe p->on_cpu == 0 such that we'll prematurely continue with the wakeup and effectively run p on two CPUs at the same time. Even though the overlap is very limited; the task is in the middle of being scheduled out; it could still result in corruption of the scheduler data structures. CPU0 CPU1 set_current_state(...) context_switch(X, Y) prepare_lock_switch(Y) Y->on_cpu = 1; finish_lock_switch(X) store_release(X->on_cpu, 0); try_to_wake_up(X) LOCK(p->pi_lock); t = X->on_cpu; // 0 context_switch(Y, X) prepare_lock_switch(X) X->on_cpu = 1; finish_lock_switch(Y) store_release(Y->on_cpu, 0); schedule(); deactivate_task(X); X->on_rq = 0; if (X->on_rq) // false if (t) while (X->on_cpu) cpu_relax(); context_switch(X, ..) finish_lock_switch(X) store_release(X->on_cpu, 0); Avoid the load of X->on_cpu being hoisted over the X->on_rq load. Reported-by: Oleg Nesterov Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b64f163..7063c6a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1947,6 +1947,25 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) #ifdef CONFIG_SMP /* + * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be + * possible to, falsely, observe p->on_cpu == 0. + * + * One must be running (->on_cpu == 1) in order to remove oneself + * from the runqueue. + * + * [S] ->on_cpu = 1; [L] ->on_rq + * UNLOCK rq->lock + * RMB + * LOCK rq->lock + * [S] ->on_rq = 0; [L] ->on_cpu + * + * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock + * from the consecutive calls to schedule(); the first switching to our + * task, the second putting it to sleep. + */ + smp_rmb(); + + /* * If the owning (remote) cpu is still in the middle of schedule() with * this task as prev, wait until its done referencing the task. */ -- cgit v0.10.2 From 70b16db86f564977df074072143284aec2cb1162 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 27 Nov 2015 19:23:24 +0100 Subject: rbd: don't put snap_context twice in rbd_queue_workfn() Commit 4e752f0ab0e8 ("rbd: access snapshot context and mapping size safely") moved ceph_get_snap_context() out of rbd_img_request_create() and into rbd_queue_workfn(), adding a ceph_put_snap_context() to the error path in rbd_queue_workfn(). However, rbd_img_request_create() consumes a ref on snapc, so calling ceph_put_snap_context() after a successful rbd_img_request_create() leads to an extra put. Fix it. Cc: stable@vger.kernel.org # 3.18+ Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 235708c..81ea69f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3442,6 +3442,7 @@ static void rbd_queue_workfn(struct work_struct *work) goto err_rq; } img_request->rq = rq; + snapc = NULL; /* img_request consumes a ref */ if (op_type == OBJ_OP_DISCARD) result = rbd_img_request_fill(img_request, OBJ_REQUEST_NODATA, -- cgit v0.10.2 From ae5515d66362b9d96cdcfce504567f0b8b7bd83e Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 4 Dec 2015 08:38:42 -0700 Subject: Revert: "vfio: Include No-IOMMU mode" Revert commit 033291eccbdb ("vfio: Include No-IOMMU mode") due to lack of a user. This was originally intended to fill a need for the DPDK driver, but uptake has been slow so rather than support an unproven kernel interface revert it and revisit when userspace catches up. Signed-off-by: Alex Williamson diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig index da6e2ce..850d86c 100644 --- a/drivers/vfio/Kconfig +++ b/drivers/vfio/Kconfig @@ -31,21 +31,6 @@ menuconfig VFIO If you don't know what to do here, say N. -menuconfig VFIO_NOIOMMU - bool "VFIO No-IOMMU support" - depends on VFIO - help - VFIO is built on the ability to isolate devices using the IOMMU. - Only with an IOMMU can userspace access to DMA capable devices be - considered secure. VFIO No-IOMMU mode enables IOMMU groups for - devices without IOMMU backing for the purpose of re-using the VFIO - infrastructure in a non-secure mode. Use of this mode will result - in an unsupportable kernel and will therefore taint the kernel. - Device assignment to virtual machines is also not possible with - this mode since there is no IOMMU to provide DMA translation. - - If you don't know what to do here, say N. - source "drivers/vfio/pci/Kconfig" source "drivers/vfio/platform/Kconfig" source "virt/lib/Kconfig" diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 2760a7b..56bf6db 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -940,13 +940,13 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) return -EINVAL; - group = vfio_iommu_group_get(&pdev->dev); + group = iommu_group_get(&pdev->dev); if (!group) return -EINVAL; vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); if (!vdev) { - vfio_iommu_group_put(group, &pdev->dev); + iommu_group_put(group); return -ENOMEM; } @@ -957,7 +957,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev); if (ret) { - vfio_iommu_group_put(group, &pdev->dev); + iommu_group_put(group); kfree(vdev); return ret; } @@ -993,7 +993,7 @@ static void vfio_pci_remove(struct pci_dev *pdev) if (!vdev) return; - vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); + iommu_group_put(pdev->dev.iommu_group); kfree(vdev); if (vfio_pci_is_vga(pdev)) { diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 9da0703..6070b79 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -62,7 +62,6 @@ struct vfio_container { struct rw_semaphore group_lock; struct vfio_iommu_driver *iommu_driver; void *iommu_data; - bool noiommu; }; struct vfio_unbound_dev { @@ -85,7 +84,6 @@ struct vfio_group { struct list_head unbound_list; struct mutex unbound_lock; atomic_t opened; - bool noiommu; }; struct vfio_device { @@ -97,147 +95,6 @@ struct vfio_device { void *device_data; }; -#ifdef CONFIG_VFIO_NOIOMMU -static bool noiommu __read_mostly; -module_param_named(enable_unsafe_noiommu_support, - noiommu, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel. If you do not know what this is for, step away. (default: false)"); -#endif - -/* - * vfio_iommu_group_{get,put} are only intended for VFIO bus driver probe - * and remove functions, any use cases other than acquiring the first - * reference for the purpose of calling vfio_add_group_dev() or removing - * that symmetric reference after vfio_del_group_dev() should use the raw - * iommu_group_{get,put} functions. In particular, vfio_iommu_group_put() - * removes the device from the dummy group and cannot be nested. - */ -struct iommu_group *vfio_iommu_group_get(struct device *dev) -{ - struct iommu_group *group; - int __maybe_unused ret; - - group = iommu_group_get(dev); - -#ifdef CONFIG_VFIO_NOIOMMU - /* - * With noiommu enabled, an IOMMU group will be created for a device - * that doesn't already have one and doesn't have an iommu_ops on their - * bus. We use iommu_present() again in the main code to detect these - * fake groups. - */ - if (group || !noiommu || iommu_present(dev->bus)) - return group; - - group = iommu_group_alloc(); - if (IS_ERR(group)) - return NULL; - - iommu_group_set_name(group, "vfio-noiommu"); - ret = iommu_group_add_device(group, dev); - iommu_group_put(group); - if (ret) - return NULL; - - /* - * Where to taint? At this point we've added an IOMMU group for a - * device that is not backed by iommu_ops, therefore any iommu_ - * callback using iommu_ops can legitimately Oops. So, while we may - * be about to give a DMA capable device to a user without IOMMU - * protection, which is clearly taint-worthy, let's go ahead and do - * it here. - */ - add_taint(TAINT_USER, LOCKDEP_STILL_OK); - dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n"); -#endif - - return group; -} -EXPORT_SYMBOL_GPL(vfio_iommu_group_get); - -void vfio_iommu_group_put(struct iommu_group *group, struct device *dev) -{ -#ifdef CONFIG_VFIO_NOIOMMU - if (!iommu_present(dev->bus)) - iommu_group_remove_device(dev); -#endif - - iommu_group_put(group); -} -EXPORT_SYMBOL_GPL(vfio_iommu_group_put); - -#ifdef CONFIG_VFIO_NOIOMMU -static void *vfio_noiommu_open(unsigned long arg) -{ - if (arg != VFIO_NOIOMMU_IOMMU) - return ERR_PTR(-EINVAL); - if (!capable(CAP_SYS_RAWIO)) - return ERR_PTR(-EPERM); - - return NULL; -} - -static void vfio_noiommu_release(void *iommu_data) -{ -} - -static long vfio_noiommu_ioctl(void *iommu_data, - unsigned int cmd, unsigned long arg) -{ - if (cmd == VFIO_CHECK_EXTENSION) - return arg == VFIO_NOIOMMU_IOMMU ? 1 : 0; - - return -ENOTTY; -} - -static int vfio_iommu_present(struct device *dev, void *unused) -{ - return iommu_present(dev->bus) ? 1 : 0; -} - -static int vfio_noiommu_attach_group(void *iommu_data, - struct iommu_group *iommu_group) -{ - return iommu_group_for_each_dev(iommu_group, NULL, - vfio_iommu_present) ? -EINVAL : 0; -} - -static void vfio_noiommu_detach_group(void *iommu_data, - struct iommu_group *iommu_group) -{ -} - -static struct vfio_iommu_driver_ops vfio_noiommu_ops = { - .name = "vfio-noiommu", - .owner = THIS_MODULE, - .open = vfio_noiommu_open, - .release = vfio_noiommu_release, - .ioctl = vfio_noiommu_ioctl, - .attach_group = vfio_noiommu_attach_group, - .detach_group = vfio_noiommu_detach_group, -}; - -static struct vfio_iommu_driver vfio_noiommu_driver = { - .ops = &vfio_noiommu_ops, -}; - -/* - * Wrap IOMMU drivers, the noiommu driver is the one and only driver for - * noiommu groups (and thus containers) and not available for normal groups. - */ -#define vfio_for_each_iommu_driver(con, pos) \ - for (pos = con->noiommu ? &vfio_noiommu_driver : \ - list_first_entry(&vfio.iommu_drivers_list, \ - struct vfio_iommu_driver, vfio_next); \ - (con->noiommu ? pos != NULL : \ - &pos->vfio_next != &vfio.iommu_drivers_list); \ - pos = con->noiommu ? NULL : list_next_entry(pos, vfio_next)) -#else -#define vfio_for_each_iommu_driver(con, pos) \ - list_for_each_entry(pos, &vfio.iommu_drivers_list, vfio_next) -#endif - - /** * IOMMU driver registration */ @@ -342,8 +199,7 @@ static void vfio_group_unlock_and_free(struct vfio_group *group) /** * Group objects - create, release, get, put, search */ -static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, - bool noiommu) +static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) { struct vfio_group *group, *tmp; struct device *dev; @@ -361,7 +217,6 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, atomic_set(&group->container_users, 0); atomic_set(&group->opened, 0); group->iommu_group = iommu_group; - group->noiommu = noiommu; group->nb.notifier_call = vfio_iommu_group_notifier; @@ -397,8 +252,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, dev = device_create(vfio.class, NULL, MKDEV(MAJOR(vfio.group_devt), minor), - group, "%s%d", noiommu ? "noiommu-" : "", - iommu_group_id(iommu_group)); + group, "%d", iommu_group_id(iommu_group)); if (IS_ERR(dev)) { vfio_free_group_minor(minor); vfio_group_unlock_and_free(group); @@ -786,8 +640,7 @@ int vfio_add_group_dev(struct device *dev, group = vfio_group_get_from_iommu(iommu_group); if (!group) { - group = vfio_create_group(iommu_group, - !iommu_present(dev->bus)); + group = vfio_create_group(iommu_group); if (IS_ERR(group)) { iommu_group_put(iommu_group); return PTR_ERR(group); @@ -999,7 +852,8 @@ static long vfio_ioctl_check_extension(struct vfio_container *container, */ if (!driver) { mutex_lock(&vfio.iommu_drivers_lock); - vfio_for_each_iommu_driver(container, driver) { + list_for_each_entry(driver, &vfio.iommu_drivers_list, + vfio_next) { if (!try_module_get(driver->ops->owner)) continue; @@ -1068,7 +922,7 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container, } mutex_lock(&vfio.iommu_drivers_lock); - vfio_for_each_iommu_driver(container, driver) { + list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) { void *data; if (!try_module_get(driver->ops->owner)) @@ -1333,9 +1187,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) if (atomic_read(&group->container_users)) return -EINVAL; - if (group->noiommu && !capable(CAP_SYS_RAWIO)) - return -EPERM; - f = fdget(container_fd); if (!f.file) return -EBADF; @@ -1351,13 +1202,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) down_write(&container->group_lock); - /* Real groups and fake groups cannot mix */ - if (!list_empty(&container->group_list) && - container->noiommu != group->noiommu) { - ret = -EPERM; - goto unlock_out; - } - driver = container->iommu_driver; if (driver) { ret = driver->ops->attach_group(container->iommu_data, @@ -1367,7 +1211,6 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) } group->container = container; - container->noiommu = group->noiommu; list_add(&group->container_next, &container->group_list); /* Get a reference on the container and mark a user within the group */ @@ -1398,9 +1241,6 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) !group->container->iommu_driver || !vfio_group_viable(group)) return -EINVAL; - if (group->noiommu && !capable(CAP_SYS_RAWIO)) - return -EPERM; - device = vfio_device_get_from_name(group, buf); if (!device) return -ENODEV; @@ -1443,10 +1283,6 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) fd_install(ret, filep); - if (group->noiommu) - dev_warn(device->dev, "vfio-noiommu device opened by user " - "(%s:%d)\n", current->comm, task_pid_nr(current)); - return ret; } @@ -1535,11 +1371,6 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep) if (!group) return -ENODEV; - if (group->noiommu && !capable(CAP_SYS_RAWIO)) { - vfio_group_put(group); - return -EPERM; - } - /* Do we need multiple instances of the group open? Seems not. */ opened = atomic_cmpxchg(&group->opened, 0, 1); if (opened) { @@ -1702,11 +1533,6 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep) if (!atomic_inc_not_zero(&group->container_users)) return ERR_PTR(-EINVAL); - if (group->noiommu) { - atomic_dec(&group->container_users); - return ERR_PTR(-EPERM); - } - if (!group->container->iommu_driver || !vfio_group_viable(group)) { atomic_dec(&group->container_users); diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 610a86a..ddb4409 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -44,9 +44,6 @@ struct vfio_device_ops { void (*request)(void *device_data, unsigned int count); }; -extern struct iommu_group *vfio_iommu_group_get(struct device *dev); -extern void vfio_iommu_group_put(struct iommu_group *group, struct device *dev); - extern int vfio_add_group_dev(struct device *dev, const struct vfio_device_ops *ops, void *device_data); diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 751b69f..9fd7b5d 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -39,13 +39,6 @@ #define VFIO_SPAPR_TCE_v2_IOMMU 7 /* - * The No-IOMMU IOMMU offers no translation or isolation for devices and - * supports no ioctls outside of VFIO_CHECK_EXTENSION. Use of VFIO's No-IOMMU - * code will taint the host kernel and should be used with extreme caution. - */ -#define VFIO_NOIOMMU_IOMMU 8 - -/* * The IOCTL interface is designed for extensibility by embedding the * structure length (argsz) and flags into structures passed between * kernel and userspace. We therefore use the _IO() macro for these -- cgit v0.10.2 From 84ed91526f9881886d70a082032236edaa20e7d4 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 4 Dec 2015 15:53:42 +0200 Subject: xhci: Fix memory leak in xhci_pme_acpi_rtd3_enable() There is a memory leak because acpi_evaluate_dsm() actually returns an object which the caller is supposed to release. Fix this by calling ACPI_FREE() for the returned object (this expands to kfree() so passing NULL there is fine as well). While there correct indentation in !CONFIG_ACPI case. Signed-off-by: Mika Westerberg Cc: stable # v4.2 Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 17f6897..c621090 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -188,10 +188,14 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) 0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45, 0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23, }; - acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL); + union acpi_object *obj; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, + NULL); + ACPI_FREE(obj); } #else - static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } +static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } #endif /* CONFIG_ACPI */ /* called during probe() after chip reset completes */ -- cgit v0.10.2 From 096b110a3dd3c868e4610937c80d2e3f3357c1a9 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 4 Dec 2015 15:53:43 +0200 Subject: usb: xhci: fix config fail of FS hub behind a HS hub with MTT if a full speed hub connects to a high speed hub which supports MTT, the MTT field of its slot context will be set to 1 when xHCI driver setups an xHCI virtual device in xhci_setup_addressable_virt_dev(); once usb core fetch its hub descriptor, and need to update the xHC's internal data structures for the device, the HUB field of its slot context will be set to 1 too, meanwhile MTT is also set before, this will cause configure endpoint command fail, so in the case, we should clear MTT to 0 for full speed hub according to section 6.2.2 Signed-off-by: Chunfeng Yun Cc: stable Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dfa44d3..3f91270 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4778,8 +4778,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); + /* + * refer to section 6.2.2: MTT should be 0 for full speed hub, + * but it may be already set to 1 when setup an xHCI virtual + * device, so clear it anyway. + */ if (tt->multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); + else if (hdev->speed == USB_SPEED_FULL) + slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT); + if (xhci->hci_version > 0x95) { xhci_dbg(xhci, "xHCI version %x needs hub " "TT think time and number of ports\n", -- cgit v0.10.2 From 6406eeb3f5bb376c7d9674e61f8da34ce7f05e8d Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 3 Dec 2015 17:26:27 -0500 Subject: usb: Quiet down false peer failure messages My recent Intel box is spewing these messages: xhci_hcd 0000:00:14.0: xHCI Host Controller xhci_hcd 0000:00:14.0: new USB bus registered, assigned bus number 2 usb usb2: New USB device found, idVendor=1d6b, idProduct=0003 usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1 usb usb2: Product: xHCI Host Controller usb usb2: Manufacturer: Linux 4.3.0+ xhci-hcd usb usb2: SerialNumber: 0000:00:14.0 hub 2-0:1.0: USB hub found hub 2-0:1.0: 6 ports detected usb: failed to peer usb2-port2 and usb1-port1 by location (usb2-port2:none) (usb1-port1:usb2-port1) usb usb2-port2: failed to peer to usb1-port1 (-16) usb: port power management may be unreliable usb: failed to peer usb2-port3 and usb1-port1 by location (usb2-port3:none) (usb1-port1:usb2-port1) usb usb2-port3: failed to peer to usb1-port1 (-16) usb: failed to peer usb2-port5 and usb1-port1 by location (usb2-port5:none) (usb1-port1:usb2-port1) usb usb2-port5: failed to peer to usb1-port1 (-16) usb: failed to peer usb2-port6 and usb1-port1 by location (usb2-port6:none) (usb1-port1:usb2-port1) usb usb2-port6: failed to peer to usb1-port1 (-16) Diving into the acpi tables, I noticed the EHCI hub has 12 ports while the XHCI hub has 8 ports. Most of those ports are of connect type USB_PORT_NOT_USED (including port 1 of the EHCI hub). Further the unused ports have location data initialized to 0x80000000. Now each unused port on the xhci hub walks the port list and finds a matching peer with port1 of the EHCI hub because the zero'd out group id bits falsely match. After port1 of the XHCI hub, each following matching peer will generate the above warning. These warnings seem to be harmless for this scenario as I don't think it matters that unused ports could not create a peer link. The attached patch utilizes that assumption and just turns the pr_warn into pr_debug to quiet things down. Tested on my Intel box. Signed-off-by: Don Zickus Acked-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 2106183..5487fe308 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -206,7 +206,7 @@ static int link_peers(struct usb_port *left, struct usb_port *right) else method = "default"; - pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", + pr_debug("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", dev_name(&left->dev), dev_name(&right->dev), method, dev_name(&left->dev), lpeer ? dev_name(&lpeer->dev) : "none", @@ -265,7 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right) if (rc == 0) { dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev)); } else { - dev_warn(&left->dev, "failed to peer to %s (%d)\n", + dev_dbg(&left->dev, "failed to peer to %s (%d)\n", dev_name(&right->dev), rc); pr_warn_once("usb: port power management may be unreliable\n"); usb_port_block_power_off = 1; -- cgit v0.10.2 From 4a0c4c36094cefd85cbe489590382ef69516ccef Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 2 Dec 2015 20:36:55 +0100 Subject: USB: host: ohci-at91: fix a crash in ohci_hcd_at91_overcurrent_irq The interrupt handler, ohci_hcd_at91_overcurrent_irq may be called right after registration. At that time, pdev->dev.platform_data is not yet set, leading to a NULL pointer dereference. Fixes: e4df92279fd9 (USB: host: ohci-at91: merge loops in ohci_hcd_at91_drv_probe) Reported-by: Peter Rosin Tested-by: Peter Rosin Signed-off-by: Alexandre Belloni Cc: stable@vger.kernel.org # 4.3+ Acked-by: Nicolas Ferre Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 342ffd1..8c6e15b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -473,6 +473,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; + pdev->dev.platform_data = pdata; + if (!of_property_read_u32(np, "num-ports", &ports)) pdata->ports = ports; @@ -483,6 +485,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) */ if (i >= pdata->ports) { pdata->vbus_pin[i] = -EINVAL; + pdata->overcurrent_pin[i] = -EINVAL; continue; } @@ -513,10 +516,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) } at91_for_each_port(i) { - if (i >= pdata->ports) { - pdata->overcurrent_pin[i] = -EINVAL; - continue; - } + if (i >= pdata->ports) + break; pdata->overcurrent_pin[i] = of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); @@ -552,8 +553,6 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) } } - pdev->dev.platform_data = pdata; - device_init_wakeup(&pdev->dev, 1); return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); } -- cgit v0.10.2 From 3845d2953aacf00ad069806ba8d1495675069f23 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 4 Dec 2015 10:28:14 -0600 Subject: PCI/MSI: Only use the generic MSI layer when domain is hierarchical Since d8a1cb757550 ("PCI/MSI: Let pci_msi_get_domain use struct device::msi_domain"), we use the MSI domain associated with the PCI device. But finding an MSI domain doesn't mean that the domain is implemented using the generic MSI domain API, and a number of MSI controllers are still using arch_setup_msi_irq() and arch_teardown_msi_irqs(). Check that the domain we just obtained is hierarchical. If it is, we can use the new generic MSI stuff. Otherwise we have to fall back to the old arch_setup_msi_irq() and arch_teardown_msi_irqs() interfaces. This avoids an oops in msi_domain_alloc_irqs() on systems with R-Car, Tegra, Armada 370, and probably other DesignWare-based host controllers. Fixes: d8a1cb757550 ("PCI/MSI: Let pci_msi_get_domain use struct device::msi_domain") Reported-by: Phil Edworthy Tested-by: Phil Edworthy Signed-off-by: Marc Zyngier Signed-off-by: Bjorn Helgaas Acked-by: Thomas Gleixner CC: stable@vger.kernel.org # v4.3+ diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 53e4632..7eaa4c8 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -54,7 +54,7 @@ static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) struct irq_domain *domain; domain = pci_msi_get_domain(dev); - if (domain) + if (domain && irq_domain_is_hierarchy(domain)) return pci_msi_domain_alloc_irqs(domain, dev, nvec, type); return arch_setup_msi_irqs(dev, nvec, type); @@ -65,7 +65,7 @@ static void pci_msi_teardown_msi_irqs(struct pci_dev *dev) struct irq_domain *domain; domain = pci_msi_get_domain(dev); - if (domain) + if (domain && irq_domain_is_hierarchy(domain)) pci_msi_domain_free_irqs(domain, dev); else arch_teardown_msi_irqs(dev); -- cgit v0.10.2 From bc45a516fa90b43b1898758d8b53b74c24b954e4 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Fri, 4 Dec 2015 15:03:11 +0300 Subject: arm64: KVM: Correctly handle zero register during MMIO On ARM64 register index of 31 corresponds to both zero register and SP. However, all memory access instructions, use ZR as transfer register. SP is used only as a base register in indirect memory addressing, or by register-register arithmetics, which cannot be trapped here. Correct emulation is achieved by introducing new register accessor functions, which can do special handling for reg_num == 31. These new accessors intentionally do not rely on old vcpu_reg() on ARM64, because it is to be removed. Since the affected code is shared by both ARM flavours, implementations of these accessors are also added to ARM32 code. This patch fixes setting MMIO register to a random value (actually SP) instead of zero by something like: *((volatile int *)reg) = 0; compilers tend to generate "str wzr, [xx]" here [Marc: Fixed 32bit splat] Signed-off-by: Pavel Fedin Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index a9c80a2..3095df0 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -28,6 +28,18 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu); +static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu, + u8 reg_num) +{ + return *vcpu_reg(vcpu, reg_num); +} + +static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, + unsigned long val) +{ + *vcpu_reg(vcpu, reg_num) = val; +} + bool kvm_condition_valid(struct kvm_vcpu *vcpu); void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); void kvm_inject_undefined(struct kvm_vcpu *vcpu); diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c index 974b1c6..3a10c9f 100644 --- a/arch/arm/kvm/mmio.c +++ b/arch/arm/kvm/mmio.c @@ -115,7 +115,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, data); data = vcpu_data_host_to_guest(vcpu, data, len); - *vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data; + vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); } return 0; @@ -186,7 +186,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, rt = vcpu->arch.mmio_decode.rt; if (is_write) { - data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len); + data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), + len); trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); mmio_write_buf(data_buf, len, data); diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 3ca894e..5a182af 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -109,6 +109,19 @@ static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num) return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num]; } +static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu, + u8 reg_num) +{ + return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num]; +} + +static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num, + unsigned long val) +{ + if (reg_num != 31) + vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val; +} + /* Get vcpu SPSR for current mode */ static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu) { -- cgit v0.10.2 From 3fec037d0fb292c4e5b2a7f8d132b5f9d5487ff3 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Fri, 4 Dec 2015 15:03:12 +0300 Subject: arm64: KVM: Remove const from struct sys_reg_params Further rework is going to introduce a dedicated storage for transfer register value in struct sys_reg_params. Before doing this we have to remove 'const' modifiers from it in all accessor functions and their callers. Signed-off-by: Pavel Fedin Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 87a64e8..545a72a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -78,7 +78,7 @@ static u32 get_ccsidr(u32 csselr) * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). */ static bool access_dcsw(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (!p->is_write) @@ -94,7 +94,7 @@ static bool access_dcsw(struct kvm_vcpu *vcpu, * sys_regs and leave it in complete control of the caches. */ static bool access_vm_reg(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { unsigned long val; @@ -122,7 +122,7 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, * for both AArch64 and AArch32 accesses. */ static bool access_gic_sgi(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { u64 val; @@ -137,7 +137,7 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu, } static bool trap_raz_wi(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) @@ -147,7 +147,7 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, } static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) { @@ -159,7 +159,7 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, } static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) { @@ -200,7 +200,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, * now use the debug registers. */ static bool trap_debug_regs(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) { @@ -225,7 +225,7 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, * hyp.S code switches between host and guest values in future. */ static inline void reg_to_dbg(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, u64 *dbg_reg) { u64 val = *vcpu_reg(vcpu, p->Rt); @@ -240,7 +240,7 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu, } static inline void dbg_to_reg(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, u64 *dbg_reg) { u64 val = *dbg_reg; @@ -252,7 +252,7 @@ static inline void dbg_to_reg(struct kvm_vcpu *vcpu, } static inline bool trap_bvr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *rd) { u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; @@ -294,7 +294,7 @@ static inline void reset_bvr(struct kvm_vcpu *vcpu, } static inline bool trap_bcr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *rd) { u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg]; @@ -337,7 +337,7 @@ static inline void reset_bcr(struct kvm_vcpu *vcpu, } static inline bool trap_wvr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *rd) { u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]; @@ -380,7 +380,7 @@ static inline void reset_wvr(struct kvm_vcpu *vcpu, } static inline bool trap_wcr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *rd) { u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg]; @@ -687,7 +687,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { }; static bool trap_dbgidr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) { @@ -706,7 +706,7 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu, } static bool trap_debug32(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) { @@ -731,7 +731,7 @@ static bool trap_debug32(struct kvm_vcpu *vcpu, */ static inline bool trap_xvr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *rd) { u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; @@ -991,7 +991,7 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) * Return 0 if the access has been handled, and -1 if not. */ static int emulate_cp(struct kvm_vcpu *vcpu, - const struct sys_reg_params *params, + struct sys_reg_params *params, const struct sys_reg_desc *table, size_t num) { @@ -1175,7 +1175,7 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run) } static int emulate_sys_reg(struct kvm_vcpu *vcpu, - const struct sys_reg_params *params) + struct sys_reg_params *params) { size_t num; const struct sys_reg_desc *table, *r; diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index eaa324e..953abfc 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -44,7 +44,7 @@ struct sys_reg_desc { /* Trapped access from guest, if non-NULL. */ bool (*access)(struct kvm_vcpu *, - const struct sys_reg_params *, + struct sys_reg_params *, const struct sys_reg_desc *); /* Initialization for vcpu. */ @@ -77,7 +77,7 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu, } static inline bool read_zero(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p) + struct sys_reg_params *p) { *vcpu_reg(vcpu, p->Rt) = 0; return true; diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c index 1e45768..ccd3e35 100644 --- a/arch/arm64/kvm/sys_regs_generic_v8.c +++ b/arch/arm64/kvm/sys_regs_generic_v8.c @@ -31,7 +31,7 @@ #include "sys_regs.h" static bool access_actlr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, + struct sys_reg_params *p, const struct sys_reg_desc *r) { if (p->is_write) -- cgit v0.10.2 From 2ec5be3dbfdcb672cdafde463a5f2c0bfe522c3d Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Fri, 4 Dec 2015 15:03:13 +0300 Subject: arm64: KVM: Correctly handle zero register in system register accesses System register accesses also use zero register for Rt == 31, and therefore using it will also result in getting SP value instead. This patch makes them also using new accessors, introduced by the previous patch. Since register value is no longer directly associated with storage inside vCPU context structure, we introduce a dedicated storage for it in struct sys_reg_params. This refactor also gets rid of "massive hack" in kvm_handle_cp_64(). Signed-off-by: Pavel Fedin Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 545a72a..d2650e8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -97,18 +97,16 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - unsigned long val; bool was_enabled = vcpu_has_cache_enabled(vcpu); BUG_ON(!p->is_write); - val = *vcpu_reg(vcpu, p->Rt); if (!p->is_aarch32) { - vcpu_sys_reg(vcpu, r->reg) = val; + vcpu_sys_reg(vcpu, r->reg) = p->regval; } else { if (!p->is_32bit) - vcpu_cp15_64_high(vcpu, r->reg) = val >> 32; - vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL; + vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval); + vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval); } kvm_toggle_cache(vcpu, was_enabled); @@ -125,13 +123,10 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 val; - if (!p->is_write) return read_from_write_only(vcpu, p); - val = *vcpu_reg(vcpu, p->Rt); - vgic_v3_dispatch_sgi(vcpu, val); + vgic_v3_dispatch_sgi(vcpu, p->regval); return true; } @@ -153,7 +148,7 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, if (p->is_write) { return ignore_write(vcpu, p); } else { - *vcpu_reg(vcpu, p->Rt) = (1 << 3); + p->regval = (1 << 3); return true; } } @@ -167,7 +162,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, } else { u32 val; asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val)); - *vcpu_reg(vcpu, p->Rt) = val; + p->regval = val; return true; } } @@ -204,13 +199,13 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { if (p->is_write) { - vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); + vcpu_sys_reg(vcpu, r->reg) = p->regval; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; } else { - *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg); + p->regval = vcpu_sys_reg(vcpu, r->reg); } - trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt)); + trace_trap_reg(__func__, r->reg, p->is_write, p->regval); return true; } @@ -228,7 +223,7 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu, struct sys_reg_params *p, u64 *dbg_reg) { - u64 val = *vcpu_reg(vcpu, p->Rt); + u64 val = p->regval; if (p->is_32bit) { val &= 0xffffffffUL; @@ -243,12 +238,9 @@ static inline void dbg_to_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p, u64 *dbg_reg) { - u64 val = *dbg_reg; - + p->regval = *dbg_reg; if (p->is_32bit) - val &= 0xffffffffUL; - - *vcpu_reg(vcpu, p->Rt) = val; + p->regval &= 0xffffffffUL; } static inline bool trap_bvr(struct kvm_vcpu *vcpu, @@ -697,10 +689,10 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu, u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1); u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT); - *vcpu_reg(vcpu, p->Rt) = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | - (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | - (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) | - (6 << 16) | (el3 << 14) | (el3 << 12)); + p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | + (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | + (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) + | (6 << 16) | (el3 << 14) | (el3 << 12)); return true; } } @@ -710,10 +702,10 @@ static bool trap_debug32(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { if (p->is_write) { - vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); + vcpu_cp14(vcpu, r->reg) = p->regval; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; } else { - *vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg); + p->regval = vcpu_cp14(vcpu, r->reg); } return true; @@ -740,12 +732,12 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu, u64 val = *dbg_reg; val &= 0xffffffffUL; - val |= *vcpu_reg(vcpu, p->Rt) << 32; + val |= p->regval << 32; *dbg_reg = val; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; } else { - *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32; + p->regval = *dbg_reg >> 32; } trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); @@ -1062,12 +1054,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, { struct sys_reg_params params; u32 hsr = kvm_vcpu_get_hsr(vcpu); + int Rt = (hsr >> 5) & 0xf; int Rt2 = (hsr >> 10) & 0xf; params.is_aarch32 = true; params.is_32bit = false; params.CRm = (hsr >> 1) & 0xf; - params.Rt = (hsr >> 5) & 0xf; params.is_write = ((hsr & 1) == 0); params.Op0 = 0; @@ -1076,15 +1068,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, params.CRn = 0; /* - * Massive hack here. Store Rt2 in the top 32bits so we only - * have one register to deal with. As we use the same trap + * Make a 64-bit value out of Rt and Rt2. As we use the same trap * backends between AArch32 and AArch64, we get away with it. */ if (params.is_write) { - u64 val = *vcpu_reg(vcpu, params.Rt); - val &= 0xffffffff; - val |= *vcpu_reg(vcpu, Rt2) << 32; - *vcpu_reg(vcpu, params.Rt) = val; + params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff; + params.regval |= vcpu_get_reg(vcpu, Rt2) << 32; } if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) @@ -1095,11 +1084,10 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, unhandled_cp_access(vcpu, ¶ms); out: - /* Do the opposite hack for the read side */ + /* Split up the value between registers for the read side */ if (!params.is_write) { - u64 val = *vcpu_reg(vcpu, params.Rt); - val >>= 32; - *vcpu_reg(vcpu, Rt2) = val; + vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval)); + vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval)); } return 1; @@ -1118,21 +1106,24 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, { struct sys_reg_params params; u32 hsr = kvm_vcpu_get_hsr(vcpu); + int Rt = (hsr >> 5) & 0xf; params.is_aarch32 = true; params.is_32bit = true; params.CRm = (hsr >> 1) & 0xf; - params.Rt = (hsr >> 5) & 0xf; + params.regval = vcpu_get_reg(vcpu, Rt); params.is_write = ((hsr & 1) == 0); params.CRn = (hsr >> 10) & 0xf; params.Op0 = 0; params.Op1 = (hsr >> 14) & 0x7; params.Op2 = (hsr >> 17) & 0x7; - if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) - return 1; - if (!emulate_cp(vcpu, ¶ms, global, nr_global)) + if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific) || + !emulate_cp(vcpu, ¶ms, global, nr_global)) { + if (!params.is_write) + vcpu_set_reg(vcpu, Rt, params.regval); return 1; + } unhandled_cp_access(vcpu, ¶ms); return 1; @@ -1230,6 +1221,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) { struct sys_reg_params params; unsigned long esr = kvm_vcpu_get_hsr(vcpu); + int Rt = (esr >> 5) & 0x1f; + int ret; trace_kvm_handle_sys_reg(esr); @@ -1240,10 +1233,14 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) params.CRn = (esr >> 10) & 0xf; params.CRm = (esr >> 1) & 0xf; params.Op2 = (esr >> 17) & 0x7; - params.Rt = (esr >> 5) & 0x1f; + params.regval = vcpu_get_reg(vcpu, Rt); params.is_write = !(esr & 1); - return emulate_sys_reg(vcpu, ¶ms); + ret = emulate_sys_reg(vcpu, ¶ms); + + if (!params.is_write) + vcpu_set_reg(vcpu, Rt, params.regval); + return ret; } /****************************************************************************** diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 953abfc..dbbb01c 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -28,7 +28,7 @@ struct sys_reg_params { u8 CRn; u8 CRm; u8 Op2; - u8 Rt; + u64 regval; bool is_write; bool is_aarch32; bool is_32bit; /* Only valid if is_aarch32 is true */ @@ -79,7 +79,7 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu, static inline bool read_zero(struct kvm_vcpu *vcpu, struct sys_reg_params *p) { - *vcpu_reg(vcpu, p->Rt) = 0; + p->regval = 0; return true; } diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c index ccd3e35..ed90578 100644 --- a/arch/arm64/kvm/sys_regs_generic_v8.c +++ b/arch/arm64/kvm/sys_regs_generic_v8.c @@ -37,7 +37,7 @@ static bool access_actlr(struct kvm_vcpu *vcpu, if (p->is_write) return ignore_write(vcpu, p); - *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1); + p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1); return true; } -- cgit v0.10.2 From f6be563abb60f0fa6978dec46da01164df89a635 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Fri, 4 Dec 2015 15:03:14 +0300 Subject: arm64: KVM: Get rid of old vcpu_reg() Using oldstyle vcpu_reg() accessor is proven to be inappropriate and unsafe on ARM64. This patch converts the rest of use cases to new accessors and completely removes vcpu_reg() on ARM64. Signed-off-by: Pavel Fedin Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 0b55696..a9b3b90 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) unsigned long context_id; phys_addr_t target_pc; - cpu_id = *vcpu_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK; + cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK; if (vcpu_mode_is_32bit(source_vcpu)) cpu_id &= ~((u32) 0); @@ -94,8 +94,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) return PSCI_RET_INVALID_PARAMS; } - target_pc = *vcpu_reg(source_vcpu, 2); - context_id = *vcpu_reg(source_vcpu, 3); + target_pc = vcpu_get_reg(source_vcpu, 2); + context_id = vcpu_get_reg(source_vcpu, 3); kvm_reset_vcpu(vcpu); @@ -114,7 +114,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) * NOTE: We always update r0 (or x0) because for PSCI v0.1 * the general puspose registers are undefined upon CPU_ON. */ - *vcpu_reg(vcpu, 0) = context_id; + vcpu_set_reg(vcpu, 0, context_id); vcpu->arch.power_off = false; smp_mb(); /* Make sure the above is visible */ @@ -134,8 +134,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *tmp; - target_affinity = *vcpu_reg(vcpu, 1); - lowest_affinity_level = *vcpu_reg(vcpu, 2); + target_affinity = vcpu_get_reg(vcpu, 1); + lowest_affinity_level = vcpu_get_reg(vcpu, 2); /* Determine target affinity mask */ target_affinity_mask = psci_affinity_mask(lowest_affinity_level); @@ -209,7 +209,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) { int ret = 1; - unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); + unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); unsigned long val; switch (psci_fn) { @@ -273,13 +273,13 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) break; } - *vcpu_reg(vcpu, 0) = val; + vcpu_set_reg(vcpu, 0, val); return ret; } static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { - unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); + unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); unsigned long val; switch (psci_fn) { @@ -295,7 +295,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) break; } - *vcpu_reg(vcpu, 0) = val; + vcpu_set_reg(vcpu, 0, val); return 1; } diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 5a182af..25a4021 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -100,15 +100,10 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) } /* - * vcpu_reg should always be passed a register number coming from a - * read of ESR_EL2. Otherwise, it may give the wrong result on AArch32 - * with banked registers. + * vcpu_get_reg and vcpu_set_reg should always be passed a register number + * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on + * AArch32 with banked registers. */ -static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num) -{ - return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num]; -} - static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu, u8 reg_num) { diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 68a0759..15f0477 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -37,7 +37,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) { int ret; - trace_kvm_hvc_arm64(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), + trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0), kvm_vcpu_hvc_get_imm(vcpu)); ret = kvm_psci_call(vcpu); -- cgit v0.10.2 From 0de58f852875a0f0dcfb120bb8433e4e73c7803b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 3 Dec 2015 09:25:22 +0100 Subject: ARM/arm64: KVM: correct PTE uncachedness check Commit e6fab5442345 ("ARM/arm64: KVM: test properly for a PTE's uncachedness") modified the logic to test whether a HYP or stage-2 mapping needs flushing, from [incorrectly] interpreting the page table attributes to [incorrectly] checking whether the PFN that backs the mapping is covered by host system RAM. The PFN number is part of the output of the translation, not the input, so we have to use pte_pfn() on the contents of the PTE, not __phys_to_pfn() on the HYP virtual address or stage-2 intermediate physical address. Fixes: e6fab5442345 ("ARM/arm64: KVM: test properly for a PTE's uncachedness") Cc: stable@vger.kernel.org Tested-by: Pavel Fedin Signed-off-by: Ard Biesheuvel Signed-off-by: Marc Zyngier diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 7dace90..61d96a6 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -218,7 +218,7 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, kvm_tlb_flush_vmid_ipa(kvm, addr); /* No need to invalidate the cache for device mappings */ - if (!kvm_is_device_pfn(__phys_to_pfn(addr))) + if (!kvm_is_device_pfn(pte_pfn(old_pte))) kvm_flush_dcache_pte(old_pte); put_page(virt_to_page(pte)); @@ -310,7 +310,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, pte = pte_offset_kernel(pmd, addr); do { - if (!pte_none(*pte) && !kvm_is_device_pfn(__phys_to_pfn(addr))) + if (!pte_none(*pte) && !kvm_is_device_pfn(pte_pfn(*pte))) kvm_flush_dcache_pte(*pte); } while (pte++, addr += PAGE_SIZE, addr != end); } -- cgit v0.10.2 From 863c1ca73f56d3473ff1d06357b31b0063538a96 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 17 Nov 2015 16:25:45 +0100 Subject: ARM: at91/dt: add always-on to 1.8V regulator As the SDHCI controller needs the 1.8V line to be always enabled for some eMMC configurations, set the proper "regulator-always-on" property to the board DTS files. Note that the sdhci classical regulator definitions doesn't suit our controller for this 1.8V purpose. Signed-off-by: Nicolas Ferre Acked-by: Ludovic Desroches Signed-off-by: Alexandre Belloni diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index ad6de73..e74df32 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -184,6 +184,7 @@ regulator-name = "VDD_SDHC_1V8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + regulator-always-on; }; }; }; -- cgit v0.10.2 From 087ffd4eae9929afd06f6a709861df3c3508492a Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Fri, 4 Dec 2015 12:29:28 -0500 Subject: jbd2: fix null committed data return in undo_access introduced jbd2_write_access_granted() to improve write|undo_access speed, but missed to check the status of b_committed_data which caused a kernel panic on ocfs2. [ 6538.405938] ------------[ cut here ]------------ [ 6538.406686] kernel BUG at fs/ocfs2/suballoc.c:2400! [ 6538.406686] invalid opcode: 0000 [#1] SMP [ 6538.406686] Modules linked in: ocfs2 nfsd lockd grace nfs_acl auth_rpcgss sunrpc autofs4 ocfs2_dlmfs ocfs2_stack_o2cb ocfs2_dlm ocfs2_nodemanager ocfs2_stackglue configfs sd_mod sg ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi cxgb3 mdio ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr ipv6 iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi ppdev xen_kbdfront xen_netfront xen_fbfront parport_pc parport pcspkr i2c_piix4 acpi_cpufreq ext4 jbd2 mbcache xen_blkfront floppy pata_acpi ata_generic ata_piix cirrus ttm drm_kms_helper drm fb_sys_fops sysimgblt sysfillrect i2c_core syscopyarea dm_mirror dm_region_hash dm_log dm_mod [ 6538.406686] CPU: 1 PID: 16265 Comm: mmap_truncate Not tainted 4.3.0 #1 [ 6538.406686] Hardware name: Xen HVM domU, BIOS 4.3.1OVM 05/14/2014 [ 6538.406686] task: ffff88007c2bab00 ti: ffff880075b78000 task.ti: ffff880075b78000 [ 6538.406686] RIP: 0010:[] [] ocfs2_block_group_clear_bits+0x23b/0x250 [ocfs2] [ 6538.406686] RSP: 0018:ffff880075b7b7f8 EFLAGS: 00010246 [ 6538.406686] RAX: ffff8800760c5b40 RBX: ffff88006c06a000 RCX: ffffffffa06e6df0 [ 6538.406686] RDX: 0000000000000000 RSI: ffff88007a6f6ea0 RDI: ffff88007a760430 [ 6538.406686] RBP: ffff880075b7b878 R08: 0000000000000002 R09: 0000000000000001 [ 6538.406686] R10: ffffffffa06769be R11: 0000000000000000 R12: 0000000000000001 [ 6538.406686] R13: ffffffffa06a1750 R14: 0000000000000001 R15: ffff88007a6f6ea0 [ 6538.406686] FS: 00007f17fde30720(0000) GS:ffff88007f040000(0000) knlGS:0000000000000000 [ 6538.406686] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 6538.406686] CR2: 0000000000601730 CR3: 000000007aea0000 CR4: 00000000000406e0 [ 6538.406686] Stack: [ 6538.406686] ffff88007c2bb5b0 ffff880075b7b8e0 ffff88007a7604b0 ffff88006c640800 [ 6538.406686] ffff88007a7604b0 ffff880075d77390 0000000075b7b878 ffffffffa06a309d [ 6538.406686] ffff880075d752d8 ffff880075b7b990 ffff880075b7b898 0000000000000000 [ 6538.406686] Call Trace: [ 6538.406686] [] ? ocfs2_read_group_descriptor+0x6d/0xa0 [ocfs2] [ 6538.406686] [] _ocfs2_free_suballoc_bits+0xe4/0x320 [ocfs2] [ 6538.406686] [] ? ocfs2_put_slot+0xf0/0xf0 [ocfs2] [ 6538.406686] [] _ocfs2_free_clusters+0xee/0x210 [ocfs2] [ 6538.406686] [] ? ocfs2_put_slot+0xf0/0xf0 [ocfs2] [ 6538.406686] [] ? ocfs2_put_slot+0xf0/0xf0 [ocfs2] [ 6538.406686] [] ? ocfs2_extend_trans+0x50/0x1a0 [ocfs2] [ 6538.406686] [] ocfs2_free_clusters+0x15/0x20 [ocfs2] [ 6538.406686] [] ocfs2_replay_truncate_records+0xfc/0x290 [ocfs2] [ 6538.406686] [] ? ocfs2_start_trans+0xec/0x1d0 [ocfs2] [ 6538.406686] [] __ocfs2_flush_truncate_log+0x140/0x2d0 [ocfs2] [ 6538.406686] [] ? ocfs2_reserve_blocks_for_rec_trunc.clone.0+0x44/0x170 [ocfs2] [ 6538.406686] [] ocfs2_remove_btree_range+0x374/0x630 [ocfs2] [ 6538.406686] [] ? jbd2_journal_stop+0x25b/0x470 [jbd2] [ 6538.406686] [] ocfs2_commit_truncate+0x305/0x670 [ocfs2] [ 6538.406686] [] ? ocfs2_journal_access_eb+0x20/0x20 [ocfs2] [ 6538.406686] [] ocfs2_truncate_file+0x297/0x380 [ocfs2] [ 6538.406686] [] ? jbd2_journal_begin_ordered_truncate+0x64/0xc0 [jbd2] [ 6538.406686] [] ocfs2_setattr+0x572/0x860 [ocfs2] [ 6538.406686] [] ? current_fs_time+0x3f/0x50 [ 6538.406686] [] notify_change+0x1d7/0x340 [ 6538.406686] [] ? generic_getxattr+0x79/0x80 [ 6538.406686] [] do_truncate+0x66/0x90 [ 6538.406686] [] ? __audit_syscall_entry+0xb0/0x110 [ 6538.406686] [] do_sys_ftruncate.clone.0+0xf3/0x120 [ 6538.406686] [] SyS_ftruncate+0xe/0x10 [ 6538.406686] [] entry_SYSCALL_64_fastpath+0x12/0x71 [ 6538.406686] Code: 28 48 81 ee b0 04 00 00 48 8b 92 50 fb ff ff 48 8b 80 b0 03 00 00 48 39 90 88 00 00 00 0f 84 30 fe ff ff 0f 0b eb fe 0f 0b eb fe <0f> 0b 0f 1f 00 eb fb 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 [ 6538.406686] RIP [] ocfs2_block_group_clear_bits+0x23b/0x250 [ocfs2] [ 6538.406686] RSP [ 6538.691128] ---[ end trace 31cd7011d6770d7e ]--- [ 6538.694492] Kernel panic - not syncing: Fatal exception [ 6538.695484] Kernel Offset: disabled Fixes: de92c8caf16c("jbd2: speedup jbd2_journal_get_[write|undo]_access()") Cc: Signed-off-by: Junxiao Bi Signed-off-by: Theodore Ts'o diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index b996212..1498ad9 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1009,7 +1009,8 @@ out: } /* Fast check whether buffer is already attached to the required transaction */ -static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh) +static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh, + bool undo) { struct journal_head *jh; bool ret = false; @@ -1036,6 +1037,9 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh) jh = READ_ONCE(bh->b_private); if (!jh) goto out; + /* For undo access buffer must have data copied */ + if (undo && !jh->b_committed_data) + goto out; if (jh->b_transaction != handle->h_transaction && jh->b_next_transaction != handle->h_transaction) goto out; @@ -1073,7 +1077,7 @@ int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh) struct journal_head *jh; int rc; - if (jbd2_write_access_granted(handle, bh)) + if (jbd2_write_access_granted(handle, bh, false)) return 0; jh = jbd2_journal_add_journal_head(bh); @@ -1210,7 +1214,7 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh) char *committed_data = NULL; JBUFFER_TRACE(jh, "entry"); - if (jbd2_write_access_granted(handle, bh)) + if (jbd2_write_access_granted(handle, bh, true)) return 0; jh = jbd2_journal_add_journal_head(bh); -- cgit v0.10.2 From 6d99905a8c887f6c878f14af1475c3eefdcb0b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 4 Dec 2015 13:32:55 +0100 Subject: drm/amdgpu: set snooped flags only on system addresses v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not necessary for VRAM. v2: no need to check if ttm is NULL. Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8051cb9..8a1752f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -801,11 +801,12 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, if (mem && mem->mem_type != TTM_PL_SYSTEM) flags |= AMDGPU_PTE_VALID; - if (mem && mem->mem_type == TTM_PL_TT) + if (mem && mem->mem_type == TTM_PL_TT) { flags |= AMDGPU_PTE_SYSTEM; - if (!ttm || ttm->caching_state == tt_cached) - flags |= AMDGPU_PTE_SNOOPED; + if (ttm->caching_state == tt_cached) + flags |= AMDGPU_PTE_SNOOPED; + } if (adev->asic_type >= CHIP_TOPAZ) flags |= AMDGPU_PTE_EXECUTABLE; -- cgit v0.10.2 From e9d951a832d9a5db33f9d981a810a37f851f8b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 3 Dec 2015 19:55:51 +0100 Subject: drm/amdgpu: take a BO reference in the display code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for the GEM reference here. Reviewed-by: Michel Dänzer Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index e173a5a..ddd7233 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -109,7 +109,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work) } else DRM_ERROR("failed to reserve buffer after flip\n"); - drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); + amdgpu_bo_unref(&work->old_rbo); kfree(work->shared); kfree(work); } @@ -148,8 +148,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, obj = old_amdgpu_fb->obj; /* take a reference to the old object */ - drm_gem_object_reference(obj); work->old_rbo = gem_to_amdgpu_bo(obj); + amdgpu_bo_ref(work->old_rbo); new_amdgpu_fb = to_amdgpu_framebuffer(fb); obj = new_amdgpu_fb->obj; @@ -222,7 +222,7 @@ pflip_cleanup: amdgpu_bo_unreserve(new_rbo); cleanup: - drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); + amdgpu_bo_unref(&work->old_rbo); fence_put(work->excl); for (i = 0; i < work->shared_count; ++i) fence_put(work->shared[i]); -- cgit v0.10.2 From 8423536fe453b3623f4ed7c2c3cca9b86af1ace5 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 1 Dec 2015 11:44:40 +0100 Subject: ARM: at91: fix pinctrl driver selection Move the selection of the pinctrl driver to SoC family level since we have two pinctrl drivers. It is useless to select one which is not compatible with the SoC. [abelloni: fixed pm.c when only sama2d2 is selected] Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Signed-off-by: Alexandre Belloni diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 9267300..28656c2 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -4,7 +4,6 @@ menuconfig ARCH_AT91 select ARCH_REQUIRE_GPIOLIB select COMMON_CLK_AT91 select PINCTRL - select PINCTRL_AT91 select SOC_BUS if ARCH_AT91 @@ -17,6 +16,7 @@ config SOC_SAMA5D2 select HAVE_AT91_USB_CLK select HAVE_AT91_H32MX select HAVE_AT91_GENERATED_CLK + select PINCTRL_AT91PIO4 help Select this if ou are using one of Atmel's SAMA5D2 family SoC. @@ -27,6 +27,7 @@ config SOC_SAMA5D3 select HAVE_AT91_UTMI select HAVE_AT91_SMD select HAVE_AT91_USB_CLK + select PINCTRL_AT91 help Select this if you are using one of Atmel's SAMA5D3 family SoC. This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35, SAMA5D36. @@ -40,6 +41,7 @@ config SOC_SAMA5D4 select HAVE_AT91_SMD select HAVE_AT91_USB_CLK select HAVE_AT91_H32MX + select PINCTRL_AT91 help Select this if you are using one of Atmel's SAMA5D4 family SoC. @@ -50,6 +52,7 @@ config SOC_AT91RM9200 select CPU_ARM920T select HAVE_AT91_USB_CLK select MIGHT_HAVE_PCI + select PINCTRL_AT91 select SOC_SAM_V4_V5 select SRAM if PM help @@ -65,6 +68,7 @@ config SOC_AT91SAM9 select HAVE_AT91_UTMI select HAVE_FB_ATMEL select MEMORY + select PINCTRL_AT91 select SOC_SAM_V4_V5 select SRAM if PM help diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 80e277c..23726fb 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -41,8 +41,10 @@ * implementation should be moved down into the pinctrl driver and get * called as part of the generic suspend/resume path. */ +#ifdef CONFIG_PINCTRL_AT91 extern void at91_pinctrl_gpio_suspend(void); extern void at91_pinctrl_gpio_resume(void); +#endif static struct { unsigned long uhp_udp_mask; @@ -151,8 +153,9 @@ static void at91_pm_suspend(suspend_state_t state) static int at91_pm_enter(suspend_state_t state) { +#ifdef CONFIG_PINCTRL_AT91 at91_pinctrl_gpio_suspend(); - +#endif switch (state) { /* * Suspend-to-RAM is like STANDBY plus slow clock mode, so @@ -192,7 +195,9 @@ static int at91_pm_enter(suspend_state_t state) error: target_state = PM_SUSPEND_ON; +#ifdef CONFIG_PINCTRL_AT91 at91_pinctrl_gpio_resume(); +#endif return 0; } -- cgit v0.10.2 From 43d1c0eb7e11919f85200d2fce211173526f7304 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 20 Nov 2015 22:22:34 +0100 Subject: block: detach bdev inode from its wb in __blkdev_put() Since 52ebea749aae ("writeback: make backing_dev_info host cgroup-specific bdi_writebacks") inode, at some point in its lifetime, gets attached to a wb (struct bdi_writeback). Detaching happens on evict, in inode_detach_wb() called from __destroy_inode(), and involves updating wb. However, detaching an internal bdev inode from its wb in __destroy_inode() is too late. Its bdi and by extension root wb are embedded into struct request_queue, which has different lifetime rules and can be freed long before the final bdput() is called (can be from __fput() of a corresponding /dev inode, through dput() - evict() - bd_forget(). bdevs hold onto the underlying disk/queue pair only while opened; as soon as bdev is closed all bets are off. In fact, disk/queue can be gone before __blkdev_put() even returns: 1499 static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) 1500 { ... 1518 if (bdev->bd_contains == bdev) { 1519 if (disk->fops->release) 1520 disk->fops->release(disk, mode); [ Driver puts its references to disk/queue ] 1521 } 1522 if (!bdev->bd_openers) { 1523 struct module *owner = disk->fops->owner; 1524 1525 disk_put_part(bdev->bd_part); 1526 bdev->bd_part = NULL; 1527 bdev->bd_disk = NULL; 1528 if (bdev != bdev->bd_contains) 1529 victim = bdev->bd_contains; 1530 bdev->bd_contains = NULL; 1531 1532 put_disk(disk); [ We put ours, the queue is gone The last bdput() would result in a write to invalid memory ] 1533 module_put(owner); ... 1539 } Since bdev inodes are special anyway, detach them in __blkdev_put() after clearing inode's dirty bits, turning the problematic inode_detach_wb() in __destroy_inode() into a noop. add_disk() grabs its disk->queue since 523e1d399ce0 ("block: make gendisk hold a reference to its queue"), so the old ->release comment is removed in favor of the new inode_detach_wb() comment. Cc: stable@vger.kernel.org # 4.2+, needs backporting Signed-off-by: Ilya Dryomov Acked-by: Tejun Heo Tested-by: Raghavendra K T Signed-off-by: Jens Axboe diff --git a/fs/block_dev.c b/fs/block_dev.c index c25639e..44d4a1e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1523,11 +1523,14 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) WARN_ON_ONCE(bdev->bd_holders); sync_blockdev(bdev); kill_bdev(bdev); + + bdev_write_inode(bdev); /* - * ->release can cause the queue to disappear, so flush all - * dirty data before. + * Detaching bdev inode from its wb in __destroy_inode() + * is too late: the queue which embeds its bdi (along with + * root wb) can be gone as soon as we put_disk() below. */ - bdev_write_inode(bdev); + inode_detach_wb(bdev->bd_inode); } if (bdev->bd_contains == bdev) { if (disk->fops->release) -- cgit v0.10.2 From f3f1769283b8dbf047c678da95b72194ac2477a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 3 Dec 2015 19:55:52 +0100 Subject: drm/amdgpu: take a BO reference for the user fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for a GEM reference here. Reviewed-by: Michel Dänzer Signed-off-by: Christian König Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 1d44d50..4f352ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -222,6 +222,8 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) } p->uf.bo = gem_to_amdgpu_bo(gobj); + amdgpu_bo_ref(p->uf.bo); + drm_gem_object_unreference_unlocked(gobj); p->uf.offset = fence_data->offset; } else { ret = -EINVAL; @@ -487,7 +489,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo amdgpu_ib_free(parser->adev, &parser->ibs[i]); kfree(parser->ibs); if (parser->uf.bo) - drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); + amdgpu_bo_unref(&parser->uf.bo); } static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p, @@ -776,7 +778,7 @@ static int amdgpu_cs_free_job(struct amdgpu_job *job) amdgpu_ib_free(job->adev, &job->ibs[i]); kfree(job->ibs); if (job->uf.bo) - drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base); + amdgpu_bo_unref(&job->uf.bo); return 0; } -- cgit v0.10.2 From 9c97b5ab4a91c18c2e7654f044cbff446cfd979b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 3 Dec 2015 20:54:35 +0100 Subject: drm/amdgpu: partially revert "drm/amdgpu: fix VM_CONTEXT*_PAGE_TABLE_END_ADDR" v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gtt_end is already inclusive, we don't need to subtract one here. v2 (chk): keep the fix for the VM code, cause here it really applies. Signed-off-by: Christian König Signed-off-by: Anatoli Antonovitch Reviewed-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 7427d8c..ed8abb5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -513,7 +513,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_L2_CNTL3, tmp); /* setup context0 */ WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12); - WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(adev->dummy_page.addr >> 12)); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index cb0e50e..d390284 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -657,7 +657,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_L2_CNTL4, tmp); /* setup context0 */ WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12); - WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(adev->dummy_page.addr >> 12)); -- cgit v0.10.2 From 81d75a30c6ed006a314f5c760196d04758660ca6 Mon Sep 17 00:00:00 2001 From: jimqu Date: Fri, 4 Dec 2015 17:17:00 +0800 Subject: drm/amdgpu: add spin lock to protect freed list in vm (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit there is a protection fault about freed list when OCL test. add a spin lock to protect it. v2: drop changes in vm_fini Signed-off-by: JimQu Reviewed-by: Christian König diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 670fefb..5a5f04d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -956,6 +956,8 @@ struct amdgpu_vm { struct amdgpu_vm_id ids[AMDGPU_MAX_RINGS]; /* for interval tree */ spinlock_t it_lock; + /* protecting freed */ + spinlock_t freed_lock; }; struct amdgpu_vm_manager { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index a582ef5..b53d273 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -885,17 +885,21 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, struct amdgpu_bo_va_mapping *mapping; int r; + spin_lock(&vm->freed_lock); while (!list_empty(&vm->freed)) { mapping = list_first_entry(&vm->freed, struct amdgpu_bo_va_mapping, list); list_del(&mapping->list); - + spin_unlock(&vm->freed_lock); r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL); kfree(mapping); if (r) return r; + spin_lock(&vm->freed_lock); } + spin_unlock(&vm->freed_lock); + return 0; } @@ -1155,10 +1159,13 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_unmap(bo_va, mapping); - if (valid) + if (valid) { + spin_lock(&vm->freed_lock); list_add(&mapping->list, &vm->freed); - else + spin_unlock(&vm->freed_lock); + } else { kfree(mapping); + } return 0; } @@ -1191,7 +1198,9 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, interval_tree_remove(&mapping->it, &vm->va); spin_unlock(&vm->it_lock); trace_amdgpu_vm_bo_unmap(bo_va, mapping); + spin_lock(&vm->freed_lock); list_add(&mapping->list, &vm->freed); + spin_unlock(&vm->freed_lock); } list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) { list_del(&mapping->list); @@ -1252,6 +1261,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) INIT_LIST_HEAD(&vm->cleared); INIT_LIST_HEAD(&vm->freed); spin_lock_init(&vm->it_lock); + spin_lock_init(&vm->freed_lock); pd_size = amdgpu_vm_directory_size(adev); pd_entries = amdgpu_vm_num_pdes(adev); -- cgit v0.10.2 From cb5d41664375ad4fbe47bdae745bb6fe8d837e68 Mon Sep 17 00:00:00 2001 From: Lyude Date: Thu, 3 Dec 2015 18:26:07 -0500 Subject: drm/radeon: Retry DDC probing on DVI on failure if we got an HPD interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HPD signals on DVI ports can be fired off before the pins required for DDC probing actually make contact, due to the pins for HPD making contact first. This results in a HPD signal being asserted but DDC probing failing, resulting in hotplugging occasionally failing. This is somewhat rare on most cards (depending on what angle you plug the DVI connector in), but on some cards it happens constantly. The Radeon R5 on the machine used for testing this patch for instance, runs into this issue just about every time I try to hotplug a DVI monitor and as a result hotplugging almost never works. Rescheduling the hotplug work for a second when we run into an HPD signal with a failing DDC probe usually gives enough time for the rest of the connector's pins to make contact, and fixes this issue. Reviewed-by: Christian König Signed-off-by: Lyude Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 248953d..6801a0c 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -8472,7 +8472,7 @@ restart_ih: if (queue_dp) schedule_work(&rdev->dp_work); if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_reset) { rdev->needs_reset = true; wake_up_all(&rdev->fence_queue); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7f33767..f61d664 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -5344,7 +5344,7 @@ restart_ih: if (queue_dp) schedule_work(&rdev->dp_work); if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_hdmi) schedule_work(&rdev->audio_work); if (queue_thermal && rdev->pm.dpm_enabled) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 238b13f..2df3c86 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev) status = r100_irq_ack(rdev); } if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (rdev->msi_enabled) { switch (rdev->family) { case CHIP_RS400: diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4ea5b10..cc2fdf0 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -4276,7 +4276,7 @@ restart_ih: WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_hdmi) schedule_work(&rdev->audio_work); if (queue_thermal && rdev->pm.dpm_enabled) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b6cbd81..87db649 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2414,7 +2414,7 @@ struct radeon_device { struct r600_ih ih; /* r6/700 interrupt ring */ struct radeon_rlc rlc; struct radeon_mec mec; - struct work_struct hotplug_work; + struct delayed_work hotplug_work; struct work_struct dp_work; struct work_struct audio_work; int num_crtc; /* number of crtcs */ diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5a2cafb..340f3f5 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (r < 0) return connector_status_disconnected; + if (radeon_connector->detected_hpd_without_ddc) { + force = true; + radeon_connector->detected_hpd_without_ddc = false; + } + if (!force && radeon_check_hpd_status_unchanged(connector)) { ret = connector->status; goto exit; } - if (radeon_connector->ddc_bus) + if (radeon_connector->ddc_bus) { dret = radeon_ddc_probe(radeon_connector, false); + + /* Sometimes the pins required for the DDC probe on DVI + * connectors don't make contact at the same time that the ones + * for HPD do. If the DDC probe fails even though we had an HPD + * signal, try again later */ + if (!dret && !force && + connector->status != connector_status_connected) { + DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n"); + radeon_connector->detected_hpd_without_ddc = true; + schedule_delayed_work(&rdev->hotplug_work, + msecs_to_jiffies(1000)); + goto exit; + } + } if (dret) { radeon_connector->detected_by_load = false; radeon_connector_free_edid(connector); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 171d3e4..979f3bf 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg) static void radeon_hotplug_work_func(struct work_struct *work) { struct radeon_device *rdev = container_of(work, struct radeon_device, - hotplug_work); + hotplug_work.work); struct drm_device *dev = rdev->ddev; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; @@ -302,7 +302,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } } - INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); + INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); INIT_WORK(&rdev->dp_work, radeon_dp_work_func); INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); @@ -310,7 +310,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); if (r) { rdev->irq.installed = false; - flush_work(&rdev->hotplug_work); + flush_delayed_work(&rdev->hotplug_work); return r; } @@ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) rdev->irq.installed = false; if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); - flush_work(&rdev->hotplug_work); + flush_delayed_work(&rdev->hotplug_work); } } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 830e171..0fa3e25 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -553,6 +553,7 @@ struct radeon_connector { void *con_priv; bool dac_load_detect; bool detected_by_load; /* if the connection status was determined by load */ + bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */ uint16_t connector_object_id; struct radeon_hpd hpd; struct radeon_router router; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 97a9048..6244f4e 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev) status = rs600_irq_ack(rdev); } if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_hdmi) schedule_work(&rdev->audio_work); if (rdev->msi_enabled) { diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 07037e3..fb1a7ec 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6848,7 +6848,7 @@ restart_ih: if (queue_dp) schedule_work(&rdev->dp_work); if (queue_hotplug) - schedule_work(&rdev->hotplug_work); + schedule_delayed_work(&rdev->hotplug_work, 0); if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; -- cgit v0.10.2 From 5b5561b3660db734652fbd02b4b6cbe00434d96b Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Wed, 25 Nov 2015 20:14:31 +0100 Subject: drm/radeon: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many vblanks were missed" introduced in Linux 4.4-rc1 makes the drm core more fragile to drivers which don't update hw vblank counters and vblank timestamps in sync with firing of the vblank irq and essentially at leading edge of vblank. This exposed a problem with radeon-kms/amdgpu-kms which do not satisfy above requirements: The vblank irq fires a few scanlines before start of vblank, but programmed pageflips complete at start of vblank and vblank timestamps update at start of vblank, whereas the hw vblank counter increments only later, at start of vsync. This leads to problems like off by one errors for vblank counter updates, vblank counters apparently going backwards or vblank timestamps apparently having time going backwards. The net result is stuttering of graphics in games, or little hangs, as well as total failure of timing sensitive applications. See bug #93147 for an example of the regression on Linux 4.4-rc: https://bugs.freedesktop.org/show_bug.cgi?id=93147 This patch tries to align all above events better from the viewpoint of the drm core / of external callers to fix the problem: 1. The apparent start of vblank is shifted a few scanlines earlier, so the vblank irq now always happens after start of this extended vblank interval and thereby drm_update_vblank_count() always samples the updated vblank count and timestamp of the new vblank interval. To achieve this, the reporting of scanout positions by radeon_get_crtc_scanoutpos() now operates as if the vblank starts radeon_crtc->lb_vblank_lead_lines before the real start of the hw vblank interval. This means that the vblank timestamps which are based on these scanout positions will now update at this earlier start of vblank. 2. The driver->get_vblank_counter() function will bump the returned vblank count as read from the hw by +1 if the query happens after the shifted earlier start of the vblank, but before the real hw increment at start of vsync, so the counter appears to increment at start of vblank in sync with the timestamp update. 3. Calls from vblank irq-context and regular non-irq calls are now treated identical, always simulating the shifted vblank start, to avoid inconsistent results for queries happening from vblank irq vs. happening from drm_vblank_enable() or vblank_disable_fn(). 4. The radeon_flip_work_func will delay mmio programming a pageflip until the start of the real vblank iff it happens to execute inside the shifted earlier start of the vblank, so pageflips now also appear to execute at start of the shifted vblank, in sync with vblank counter and timestamp updates. This to avoid some races between updates of vblank count and timestamps that are used for swap scheduling and pageflip execution which could cause pageflips to execute before the scheduled target vblank. The lb_vblank_lead_lines "fudge" value is calculated as the size of the display controllers line buffer in scanlines for the given video mode: Vblank irq's are triggered by the line buffer logic when the line buffer refill for a video frame ends, ie. when the line buffer source read position enters the hw vblank. This means that a vblank irq could fire at most as many scanlines before the current reported scanout position of the crtc timing generator as the number of scanlines the line buffer can maximally hold for a given video mode. This patch has been successfully tested on a RV730 card with DCE-3 display engine and on a evergreen card with DCE-4 display engine, in single-display and dual-display configuration, with different video modes. A similar patch is needed for amdgpu-kms to fix the same problem. Limitations: - Line buffer sizes in pixels are hard-coded on < DCE-4 to a value i just guessed to be high enough to work ok, lacking info on the true sizes atm. Fixes: fdo#93147 Signed-off-by: Mario Kleiner Cc: Alex Deucher Cc: Michel Dänzer Cc: Harry Wentland Cc: Ville Syrjälä (v1) Tested-by: Dave Witbrodt (v2) Refine radeon_flip_work_func() for better efficiency: In radeon_flip_work_func, replace the busy waiting udelay(5) with event lock held by a more performance and energy efficient usleep_range() until at least predicted true start of hw vblank, with some slack for scheduler happiness. Release the event lock during waits to not delay other outputs in doing their stuff, as the waiting can last up to 200 usecs in some cases. Retested on DCE-3 and DCE-4 to verify it still works nicely. (v2) Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 6801a0c..0154db4 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -9630,6 +9630,9 @@ static void dce8_program_watermarks(struct radeon_device *rdev, (rdev->disp_priority == 2)) { DRM_DEBUG_KMS("force priority to high\n"); } + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f61d664..2ad4628 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2372,6 +2372,9 @@ static void evergreen_program_watermarks(struct radeon_device *rdev, c.full = dfixed_div(c, a); priority_b_mark = dfixed_trunc(c); priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2df3c86..9e7e2bf 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3217,6 +3217,9 @@ void r100_bandwidth_update(struct radeon_device *rdev) uint32_t pixel_bytes1 = 0; uint32_t pixel_bytes2 = 0; + /* Guess line buffer size to be 8192 pixels */ + u32 lb_size = 8192; + if (!rdev->mode_info.mode_config_initialized) return; @@ -3631,6 +3634,13 @@ void r100_bandwidth_update(struct radeon_device *rdev) DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); } + + /* Save number of lines the linebuffer leads before the scanout */ + if (mode1) + rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); + + if (mode2) + rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); } int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index a8d9927..1eca0ac 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -322,7 +322,9 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) * to complete in this vblank? */ if (update_pending && - (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, + (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, + crtc_id, + USE_REAL_VBLANKSTART, &vpos, &hpos, NULL, NULL, &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) && ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || @@ -401,6 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work) struct drm_crtc *crtc = &radeon_crtc->base; unsigned long flags; int r; + int vpos, hpos, stat, min_udelay; + struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; down_read(&rdev->exclusive_lock); if (work->fence) { @@ -437,6 +441,41 @@ static void radeon_flip_work_func(struct work_struct *__work) /* set the proper interrupt */ radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); + /* If this happens to execute within the "virtually extended" vblank + * interval before the start of the real vblank interval then it needs + * to delay programming the mmio flip until the real vblank is entered. + * This prevents completing a flip too early due to the way we fudge + * our vblank counter and vblank timestamps in order to work around the + * problem that the hw fires vblank interrupts before actual start of + * vblank (when line buffer refilling is done for a frame). It + * complements the fudging logic in radeon_get_crtc_scanoutpos() for + * timestamping and radeon_get_vblank_counter_kms() for vblank counts. + * + * In practice this won't execute very often unless on very fast + * machines because the time window for this to happen is very small. + */ + for (;;) { + /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank + * start in hpos, and to the "fudged earlier" vblank start in + * vpos. + */ + stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id, + GET_DISTANCE_TO_VBLANKSTART, + &vpos, &hpos, NULL, NULL, + &crtc->hwmode); + + if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || + !(vpos >= 0 && hpos <= 0)) + break; + + /* Sleep at least until estimated real start of hw vblank */ + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); + usleep_range(min_udelay, 2 * min_udelay); + spin_lock_irqsave(&crtc->dev->event_lock, flags); + }; + /* do the flip (mmio) */ radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); @@ -1768,6 +1807,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * \param dev Device to query. * \param crtc Crtc to query. * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). + * For driver internal use only also supports these flags: + * + * USE_REAL_VBLANKSTART to use the real start of vblank instead + * of a fudged earlier start of vblank. + * + * GET_DISTANCE_TO_VBLANKSTART to return distance to the + * fudged earlier start of vblank in *vpos and the distance + * to true start of vblank in *hpos. + * * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. * \param *stime Target location for timestamp taken immediately before @@ -1911,10 +1959,40 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, vbl_end = 0; } + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from real vbl_start in *hpos */ + *hpos = *vpos - vbl_start; + } + + /* Fudge vblank to start a few scanlines earlier to handle the + * problem that vblank irqs fire a few scanlines before start + * of vblank. Some driver internal callers need the true vblank + * start to be used and signal this via the USE_REAL_VBLANKSTART flag. + * + * The cause of the "early" vblank irq is that the irq is triggered + * by the line buffer logic when the line buffer read position enters + * the vblank, whereas our crtc scanout position naturally lags the + * line buffer read position. + */ + if (!(flags & USE_REAL_VBLANKSTART)) + vbl_start -= rdev->mode_info.crtcs[pipe]->lb_vblank_lead_lines; + /* Test scanout position against vblank region. */ if ((*vpos < vbl_start) && (*vpos >= vbl_end)) in_vbl = false; + /* In vblank? */ + if (in_vbl) + ret |= DRM_SCANOUTPOS_IN_VBLANK; + + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from fudged earlier vbl_start */ + *vpos -= vbl_start; + return ret; + } + /* Check if inside vblank area and apply corrective offsets: * vpos will then be >=0 in video scanout area, but negative * within vblank area, counting down the number of lines until @@ -1930,31 +2008,5 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, /* Correct for shifted end of vbl at vbl_end. */ *vpos = *vpos - vbl_end; - /* In vblank? */ - if (in_vbl) - ret |= DRM_SCANOUTPOS_IN_VBLANK; - - /* Is vpos outside nominal vblank area, but less than - * 1/100 of a frame height away from start of vblank? - * If so, assume this isn't a massively delayed vblank - * interrupt, but a vblank interrupt that fired a few - * microseconds before true start of vblank. Compensate - * by adding a full frame duration to the final timestamp. - * Happens, e.g., on ATI R500, R600. - * - * We only do this if DRM_CALLED_FROM_VBLIRQ. - */ - if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { - vbl_start = mode->crtc_vdisplay; - vtotal = mode->crtc_vtotal; - - if (vbl_start - *vpos < vtotal / 100) { - *vpos -= vtotal; - - /* Signal this correction as "applied". */ - ret |= 0x8; - } - } - return ret; } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 0ec6fcc..d290a8a 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -755,6 +755,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev, */ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) { + int vpos, hpos, stat; + u32 count; struct radeon_device *rdev = dev->dev_private; if (crtc < 0 || crtc >= rdev->num_crtc) { @@ -762,7 +764,53 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) return -EINVAL; } - return radeon_get_vblank_counter(rdev, crtc); + /* The hw increments its frame counter at start of vsync, not at start + * of vblank, as is required by DRM core vblank counter handling. + * Cook the hw count here to make it appear to the caller as if it + * incremented at start of vblank. We measure distance to start of + * vblank in vpos. vpos therefore will be >= 0 between start of vblank + * and start of vsync, so vpos >= 0 means to bump the hw frame counter + * result by 1 to give the proper appearance to caller. + */ + if (rdev->mode_info.crtcs[crtc]) { + /* Repeat readout if needed to provide stable result if + * we cross start of vsync during the queries. + */ + do { + count = radeon_get_vblank_counter(rdev, crtc); + /* Ask radeon_get_crtc_scanoutpos to return vpos as + * distance to start of vblank, instead of regular + * vertical scanout pos. + */ + stat = radeon_get_crtc_scanoutpos( + dev, crtc, GET_DISTANCE_TO_VBLANKSTART, + &vpos, &hpos, NULL, NULL, + &rdev->mode_info.crtcs[crtc]->base.hwmode); + } while (count != radeon_get_vblank_counter(rdev, crtc)); + + if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { + DRM_DEBUG_VBL("Query failed! stat %d\n", stat); + } + else { + DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", + crtc, vpos); + + /* Bump counter if we are at >= leading edge of vblank, + * but before vsync where vpos would turn negative and + * the hw counter really increments. + */ + if (vpos >= 0) + count++; + } + } + else { + /* Fallback to use value as is. */ + count = radeon_get_vblank_counter(rdev, crtc); + DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); + } + + return count; } /** diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 0fa3e25..bba1126 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -367,6 +367,7 @@ struct radeon_crtc { u32 line_time; u32 wm_low; u32 wm_high; + u32 lb_vblank_lead_lines; struct drm_display_mode hw_mode; enum radeon_output_csc output_csc; }; @@ -687,6 +688,9 @@ struct atom_voltage_table struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES]; }; +/* Driver internal use only flags of radeon_get_crtc_scanoutpos() */ +#define USE_REAL_VBLANKSTART (1 << 30) +#define GET_DISTANCE_TO_VBLANKSTART (1 << 31) extern void radeon_add_atom_connector(struct drm_device *dev, diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index f4f03dc..59abebd 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1756,7 +1756,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) */ for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { if (rdev->pm.active_crtcs & (1 << crtc)) { - vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, + vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, + crtc, + USE_REAL_VBLANKSTART, &vpos, &hpos, NULL, NULL, &rdev->mode_info.crtcs[crtc]->base.hwmode); if ((vbl_status & DRM_SCANOUTPOS_VALID) && diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 516ca27..6bc44c2 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -207,6 +207,9 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, { u32 tmp; + /* Guess line buffer size to be 8192 pixels */ + u32 lb_size = 8192; + /* * Line Buffer Setup * There is a single line buffer shared by both display controllers. @@ -243,6 +246,13 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; } WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp); + + /* Save number of lines the linebuffer leads before the scanout */ + if (mode1) + rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); + + if (mode2) + rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); } struct rs690_watermark { diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index fb1a7ec..f878d69 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2376,6 +2376,9 @@ static void dce6_program_watermarks(struct radeon_device *rdev, c.full = dfixed_div(c, a); priority_b_mark = dfixed_trunc(c); priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ -- cgit v0.10.2 From a74a821624c0c75388a193337babd17a8c02c740 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 4 Dec 2015 16:44:24 +0100 Subject: ALSA: rme96: Fix unexpected volume reset after rate changes rme96 driver needs to reset DAC depending on the sample rate, and this results in resetting to the max volume suddenly. It's because of the missing call of snd_rme96_apply_dac_volume(). However, calling this function right after the DAC reset still may not work, and we need some delay before this call. Since the DAC reset and the procedure after that are performed in the spinlock, we delay the DAC volume restore at the end after the spinlock. Reported-and-tested-by: Sylvain LABOISNE Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 714df90..41c31db 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -741,10 +741,11 @@ snd_rme96_playback_setrate(struct rme96 *rme96, { /* change to/from double-speed: reset the DAC (if available) */ snd_rme96_reset_dac(rme96); + return 1; /* need to restore volume */ } else { writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); + return 0; } - return 0; } static int @@ -980,6 +981,7 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err, rate, dummy; + bool apply_dac_volume = false; runtime->dma_area = (void __force *)(rme96->iobase + RME96_IO_PLAY_BUFFER); @@ -993,24 +995,26 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, { /* slave clock */ if ((int)params_rate(params) != rate) { - spin_unlock_irq(&rme96->lock); - return -EIO; - } - } else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) { - spin_unlock_irq(&rme96->lock); - return err; - } - if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) { - spin_unlock_irq(&rme96->lock); - return err; + err = -EIO; + goto error; + } + } else { + err = snd_rme96_playback_setrate(rme96, params_rate(params)); + if (err < 0) + goto error; + apply_dac_volume = err > 0; /* need to restore volume later? */ } + + err = snd_rme96_playback_setformat(rme96, params_format(params)); + if (err < 0) + goto error; snd_rme96_setframelog(rme96, params_channels(params), 1); if (rme96->capture_periodsize != 0) { if (params_period_size(params) << rme96->playback_frlog != rme96->capture_periodsize) { - spin_unlock_irq(&rme96->lock); - return -EBUSY; + err = -EBUSY; + goto error; } } rme96->playback_periodsize = @@ -1021,9 +1025,16 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream, rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER); } + + err = 0; + error: spin_unlock_irq(&rme96->lock); - - return 0; + if (apply_dac_volume) { + usleep_range(3000, 10000); + snd_rme96_apply_dac_volume(rme96); + } + + return err; } static int -- cgit v0.10.2 From 8e36f9d33c134d5c6448ad65b423a9fd94e045cf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Dec 2015 12:31:56 -0500 Subject: drm/amdgpu: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v3) commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many vblanks were missed" introduced in Linux 4.4-rc1 makes the drm core more fragile to drivers which don't update hw vblank counters and vblank timestamps in sync with firing of the vblank irq and essentially at leading edge of vblank. This exposed a problem with radeon-kms/amdgpu-kms which do not satisfy above requirements: The vblank irq fires a few scanlines before start of vblank, but programmed pageflips complete at start of vblank and vblank timestamps update at start of vblank, whereas the hw vblank counter increments only later, at start of vsync. This leads to problems like off by one errors for vblank counter updates, vblank counters apparently going backwards or vblank timestamps apparently having time going backwards. The net result is stuttering of graphics in games, or little hangs, as well as total failure of timing sensitive applications. See bug #93147 for an example of the regression on Linux 4.4-rc: https://bugs.freedesktop.org/show_bug.cgi?id=93147 This patch tries to align all above events better from the viewpoint of the drm core / of external callers to fix the problem: 1. The apparent start of vblank is shifted a few scanlines earlier, so the vblank irq now always happens after start of this extended vblank interval and thereby drm_update_vblank_count() always samples the updated vblank count and timestamp of the new vblank interval. To achieve this, the reporting of scanout positions by radeon_get_crtc_scanoutpos() now operates as if the vblank starts radeon_crtc->lb_vblank_lead_lines before the real start of the hw vblank interval. This means that the vblank timestamps which are based on these scanout positions will now update at this earlier start of vblank. 2. The driver->get_vblank_counter() function will bump the returned vblank count as read from the hw by +1 if the query happens after the shifted earlier start of the vblank, but before the real hw increment at start of vsync, so the counter appears to increment at start of vblank in sync with the timestamp update. 3. Calls from vblank irq-context and regular non-irq calls are now treated identical, always simulating the shifted vblank start, to avoid inconsistent results for queries happening from vblank irq vs. happening from drm_vblank_enable() or vblank_disable_fn(). 4. The radeon_flip_work_func will delay mmio programming a pageflip until the start of the real vblank iff it happens to execute inside the shifted earlier start of the vblank, so pageflips now also appear to execute at start of the shifted vblank, in sync with vblank counter and timestamp updates. This to avoid some races between updates of vblank count and timestamps that are used for swap scheduling and pageflip execution which could cause pageflips to execute before the scheduled target vblank. The lb_vblank_lead_lines "fudge" value is calculated as the size of the display controllers line buffer in scanlines for the given video mode: Vblank irq's are triggered by the line buffer logic when the line buffer refill for a video frame ends, ie. when the line buffer source read position enters the hw vblank. This means that a vblank irq could fire at most as many scanlines before the current reported scanout position of the crtc timing generator as the number of scanlines the line buffer can maximally hold for a given video mode. This patch has been successfully tested on a RV730 card with DCE-3 display engine and on a evergreen card with DCE-4 display engine, in single-display and dual-display configuration, with different video modes. A similar patch is needed for amdgpu-kms to fix the same problem. Limitations: - Maybe replace the udelay() in the flip_work_func() by a suitable usleep_range() for a bit better efficiency? Will try that. - Line buffer sizes in pixels are hard-coded on < DCE-4 to a value i just guessed to be high enough to work ok, lacking info on the true sizes atm. Probably fixes: fdo#93147 Port of Mario's radeon fix to amdgpu. Signed-off-by: Alex Deucher (v1) Reviewed-by: Mario Kleiner (v2) Refine amdgpu_flip_work_func() for better efficiency. In amdgpu_flip_work_func, replace the busy waiting udelay(5) with event lock held by a more performance and energy efficient usleep_range() until at least predicted true start of hw vblank, with some slack for scheduler happiness. Release the event lock during waits to not delay other outputs in doing their stuff, as the waiting can last up to 200 usecs in some cases. Also small fix to code comment and formatting in that function. (v2) Signed-off-by: Mario Kleiner (v3) Fix crash in crtc disabled case diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index ddd7233..5580d34 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work) struct drm_crtc *crtc = &amdgpuCrtc->base; unsigned long flags; unsigned i; + int vpos, hpos, stat, min_udelay; + struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; amdgpu_flip_wait_fence(adev, &work->excl); for (i = 0; i < work->shared_count; ++i) @@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work) /* We borrow the event spin lock for protecting flip_status */ spin_lock_irqsave(&crtc->dev->event_lock, flags); + /* If this happens to execute within the "virtually extended" vblank + * interval before the start of the real vblank interval then it needs + * to delay programming the mmio flip until the real vblank is entered. + * This prevents completing a flip too early due to the way we fudge + * our vblank counter and vblank timestamps in order to work around the + * problem that the hw fires vblank interrupts before actual start of + * vblank (when line buffer refilling is done for a frame). It + * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for + * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts. + * + * In practice this won't execute very often unless on very fast + * machines because the time window for this to happen is very small. + */ + for (;;) { + /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank + * start in hpos, and to the "fudged earlier" vblank start in + * vpos. + */ + stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, + GET_DISTANCE_TO_VBLANKSTART, + &vpos, &hpos, NULL, NULL, + &crtc->hwmode); + + if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || + !(vpos >= 0 && hpos <= 0)) + break; + + /* Sleep at least until estimated real start of hw vblank */ + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); + usleep_range(min_udelay, 2 * min_udelay); + spin_lock_irqsave(&crtc->dev->event_lock, flags); + }; + /* do the flip (mmio) */ adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); /* set the flip status */ @@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * \param dev Device to query. * \param pipe Crtc to query. * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). + * For driver internal use only also supports these flags: + * + * USE_REAL_VBLANKSTART to use the real start of vblank instead + * of a fudged earlier start of vblank. + * + * GET_DISTANCE_TO_VBLANKSTART to return distance to the + * fudged earlier start of vblank in *vpos and the distance + * to true start of vblank in *hpos. + * * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. * \param *stime Target location for timestamp taken immediately before @@ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, vbl_end = 0; } + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from real vbl_start in *hpos */ + *hpos = *vpos - vbl_start; + } + + /* Fudge vblank to start a few scanlines earlier to handle the + * problem that vblank irqs fire a few scanlines before start + * of vblank. Some driver internal callers need the true vblank + * start to be used and signal this via the USE_REAL_VBLANKSTART flag. + * + * The cause of the "early" vblank irq is that the irq is triggered + * by the line buffer logic when the line buffer read position enters + * the vblank, whereas our crtc scanout position naturally lags the + * line buffer read position. + */ + if (!(flags & USE_REAL_VBLANKSTART)) + vbl_start -= adev->mode_info.crtcs[pipe]->lb_vblank_lead_lines; + /* Test scanout position against vblank region. */ if ((*vpos < vbl_start) && (*vpos >= vbl_end)) in_vbl = false; + /* In vblank? */ + if (in_vbl) + ret |= DRM_SCANOUTPOS_IN_VBLANK; + + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from fudged earlier vbl_start */ + *vpos -= vbl_start; + return ret; + } + /* Check if inside vblank area and apply corrective offsets: * vpos will then be >=0 in video scanout area, but negative * within vblank area, counting down the number of lines until @@ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, /* Correct for shifted end of vbl at vbl_end. */ *vpos = *vpos - vbl_end; - /* In vblank? */ - if (in_vbl) - ret |= DRM_SCANOUTPOS_IN_VBLANK; - - /* Is vpos outside nominal vblank area, but less than - * 1/100 of a frame height away from start of vblank? - * If so, assume this isn't a massively delayed vblank - * interrupt, but a vblank interrupt that fired a few - * microseconds before true start of vblank. Compensate - * by adding a full frame duration to the final timestamp. - * Happens, e.g., on ATI R500, R600. - * - * We only do this if DRM_CALLED_FROM_VBLIRQ. - */ - if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { - vbl_start = mode->crtc_vdisplay; - vtotal = mode->crtc_vtotal; - - if (vbl_start - *vpos < vtotal / 100) { - *vpos -= vtotal; - - /* Signal this correction as "applied". */ - ret |= 0x8; - } - } - return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 1618e22..e23843f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -611,13 +611,59 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev, u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; + int vpos, hpos, stat; + u32 count; if (pipe >= adev->mode_info.num_crtc) { DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } - return amdgpu_display_vblank_get_counter(adev, pipe); + /* The hw increments its frame counter at start of vsync, not at start + * of vblank, as is required by DRM core vblank counter handling. + * Cook the hw count here to make it appear to the caller as if it + * incremented at start of vblank. We measure distance to start of + * vblank in vpos. vpos therefore will be >= 0 between start of vblank + * and start of vsync, so vpos >= 0 means to bump the hw frame counter + * result by 1 to give the proper appearance to caller. + */ + if (adev->mode_info.crtcs[pipe]) { + /* Repeat readout if needed to provide stable result if + * we cross start of vsync during the queries. + */ + do { + count = amdgpu_display_vblank_get_counter(adev, pipe); + /* Ask amdgpu_get_crtc_scanoutpos to return vpos as + * distance to start of vblank, instead of regular + * vertical scanout pos. + */ + stat = amdgpu_get_crtc_scanoutpos( + dev, pipe, GET_DISTANCE_TO_VBLANKSTART, + &vpos, &hpos, NULL, NULL, + &adev->mode_info.crtcs[pipe]->base.hwmode); + } while (count != amdgpu_display_vblank_get_counter(adev, pipe)); + + if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { + DRM_DEBUG_VBL("Query failed! stat %d\n", stat); + } else { + DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", + pipe, vpos); + + /* Bump counter if we are at >= leading edge of vblank, + * but before vsync where vpos would turn negative and + * the hw counter really increments. + */ + if (vpos >= 0) + count++; + } + } else { + /* Fallback to use value as is. */ + count = amdgpu_display_vblank_get_counter(adev, pipe); + DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); + } + + return count; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index b62c171..064ebb3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -407,6 +407,7 @@ struct amdgpu_crtc { u32 line_time; u32 wm_low; u32 wm_high; + u32 lb_vblank_lead_lines; struct drm_display_mode hw_mode; }; @@ -528,6 +529,10 @@ struct amdgpu_framebuffer { #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \ ((em) == ATOM_ENCODER_MODE_DP_MST)) +/* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ +#define USE_REAL_VBLANKSTART (1 << 30) +#define GET_DISTANCE_TO_VBLANKSTART (1 << 31) + void amdgpu_link_encoder_connector(struct drm_device *dev); struct drm_connector * diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index cb0f774..4dcc8fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1250,7 +1250,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, u32 pixel_period; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; - u32 tmp, wm_mask; + u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { pixel_period = 1000000 / (u32)mode->clock; @@ -1333,6 +1333,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, (adev->mode_info.disp_priority == 2)) { DRM_DEBUG_KMS("force priority to high\n"); } + lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -1357,6 +1358,8 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, amdgpu_crtc->line_time = line_time; amdgpu_crtc->wm_high = latency_watermark_a; amdgpu_crtc->wm_low = latency_watermark_b; + /* Save number of lines the linebuffer leads before the scanout */ + amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 5af3721..8f1e511 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1238,7 +1238,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, u32 pixel_period; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; - u32 tmp, wm_mask; + u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { pixel_period = 1000000 / (u32)mode->clock; @@ -1321,6 +1321,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, (adev->mode_info.disp_priority == 2)) { DRM_DEBUG_KMS("force priority to high\n"); } + lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -1345,6 +1346,8 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, amdgpu_crtc->line_time = line_time; amdgpu_crtc->wm_high = latency_watermark_a; amdgpu_crtc->wm_low = latency_watermark_b; + /* Save number of lines the linebuffer leads before the scanout */ + amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 4f7b49a..42d954d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1193,7 +1193,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, u32 pixel_period; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; - u32 tmp, wm_mask; + u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { pixel_period = 1000000 / (u32)mode->clock; @@ -1276,6 +1276,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, (adev->mode_info.disp_priority == 2)) { DRM_DEBUG_KMS("force priority to high\n"); } + lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -1302,6 +1303,8 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, amdgpu_crtc->line_time = line_time; amdgpu_crtc->wm_high = latency_watermark_a; amdgpu_crtc->wm_low = latency_watermark_b; + /* Save number of lines the linebuffer leads before the scanout */ + amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; } /** -- cgit v0.10.2 From 7f52f31443ae9b2e6a71ec54cfc5a2c89006ea27 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Dec 2015 16:21:08 -0600 Subject: PCI: altera: Fix loop in tlp_read_packet() TLP_LOOP is 500 and the "loop" variable was a u8 so "loop < TLP_LOOP" is always true. We only need this condition to work if there is a problem so it would have been easy to miss this in testing. Make it a normal for loop with "int i" instead of over thinking things and making it complicated. Fixes: 6bb4dd154ae8 ("PCI: altera: Add Altera PCIe host controller driver") Signed-off-by: Dan Carpenter Signed-off-by: Bjorn Helgaas Acked-by: Ley Foon Tan diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index e5dda38..f0820d3 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -166,7 +166,7 @@ static bool altera_pcie_valid_config(struct altera_pcie *pcie, static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) { - u8 loop; + int i; bool sop = 0; u32 ctrl; u32 reg0, reg1; @@ -175,7 +175,7 @@ static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) * Minimum 2 loops to read TLP headers and 1 loop to read data * payload. */ - for (loop = 0; loop < TLP_LOOP; loop++) { + for (i = 0; i < TLP_LOOP; i++) { ctrl = cra_readl(pcie, RP_RXCPL_STATUS); if ((ctrl & RP_RXCPL_SOP) || (ctrl & RP_RXCPL_EOP) || sop) { reg0 = cra_readl(pcie, RP_RXCPL_REG0); -- cgit v0.10.2 From 23ec56708af7155414a979675dc8132a5d6e16ef Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Fri, 4 Dec 2015 16:21:12 -0600 Subject: PCI: altera: Fix Requester ID for config accesses The Requester ID should use the Root Port devfn and it should be always 0. Previously we constructed the Requester ID using the *Completer* devfn, i.e., the devfn of the Function we expect to respond to the config access. This causes issues when accessing configuration space for devices other than the Root Port. Build the Requester ID using the Root Port devfn. Tested on Ethernet adapter card with multi-functions. Signed-off-by: Ley Foon Tan Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index f0820d3..ed736a9 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -57,6 +57,7 @@ #define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) #define TLP_HDR_SIZE 3 #define TLP_LOOP 500 +#define RP_DEVFN 0 #define INTX_NUM 4 @@ -233,7 +234,7 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, else headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1); - headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn), + headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN), TLP_READ_TAG, byte_en); headers[2] = TLP_CFG_DW2(bus, devfn, where); @@ -253,7 +254,7 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, else headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1); - headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn), + headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN), TLP_WRITE_TAG, byte_en); headers[2] = TLP_CFG_DW2(bus, devfn, where); -- cgit v0.10.2 From ea1d3795f65e14619642b5f67382800f58e43f3d Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Fri, 4 Dec 2015 16:21:16 -0600 Subject: PCI: altera: Check TLP completion status Check TLP packet successful completion status. This fix the issue when accessing multi-function devices in enumeration process, TLP will return error when accessing non-exist function number. Returns PCI error code instead of generic errno. Tested on Ethernet adapter card with multi-functions. [bhelgaas: simplify completion status checking code] Signed-off-by: Ley Foon Tan Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index ed736a9..072255d 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -55,6 +55,7 @@ #define TLP_CFG_DW2(bus, devfn, offset) \ (((bus) << 24) | ((devfn) << 16) | (offset)) #define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) +#define TLP_COMP_STATUS(s) (((s) >> 12) & 7) #define TLP_HDR_SIZE 3 #define TLP_LOOP 500 #define RP_DEVFN 0 @@ -171,6 +172,7 @@ static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) bool sop = 0; u32 ctrl; u32 reg0, reg1; + u32 comp_status = 1; /* * Minimum 2 loops to read TLP headers and 1 loop to read data @@ -182,19 +184,25 @@ static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) reg0 = cra_readl(pcie, RP_RXCPL_REG0); reg1 = cra_readl(pcie, RP_RXCPL_REG1); - if (ctrl & RP_RXCPL_SOP) + if (ctrl & RP_RXCPL_SOP) { sop = true; + comp_status = TLP_COMP_STATUS(reg1); + } if (ctrl & RP_RXCPL_EOP) { + if (comp_status) + return PCIBIOS_DEVICE_NOT_FOUND; + if (value) *value = reg0; + return PCIBIOS_SUCCESSFUL; } } udelay(5); } - return -ENOENT; + return PCIBIOS_DEVICE_NOT_FOUND; } static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers, -- cgit v0.10.2 From 99496bd2971fc378226ad4413e5b72c4545714bd Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Fri, 4 Dec 2015 16:21:21 -0600 Subject: PCI: altera: Fix error when INTx is 4 PCI interrupt lines start at 1, not at 0. So, creates additional one interrupt when register for irq domain. Error when PCIe devices have 4 INTx: WARNING: CPU: 1 PID: 1 at kernel/irq/irqdomain.c:280 irq_domain_associate+0x17c/0x1cc() error: hwirq 0x4 is too large for dummy Tested on Ethernet adapter card with multi-functions. Signed-off-by: Ley Foon Tan Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index 072255d..99da549 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -467,7 +467,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie) struct device_node *node = dev->of_node; /* Setup INTx */ - pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM, + pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM + 1, &intx_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); -- cgit v0.10.2 From 8e8efe0379bd93e8219ca0fc6fa80b5dd85b09cb Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Mon, 30 Nov 2015 16:31:13 -0800 Subject: x86/mpx: Fix instruction decoder condition MPX decodes instructions in order to tell which bounds register was violated. Part of this decoding involves looking at the "REX prefix" which is a special instrucion prefix used to retrofit support for new registers in to old instructions. The X86_REX_*() macros are defined to return actual bit values: #define X86_REX_R(rex) ((rex) & 4) *not* boolean values. However, the MPX code was checking for them like they were booleans. This might have led to us mis-decoding the "REX prefix" and giving false information out to userspace about bounds violations. X86_REX_B() actually is bit 1, so this is really only broken for the X86_REX_X() case. Fix the conditionals up to tolerate the non-boolean values. Fixes: fcc7ffd67991 "x86, mpx: Decode MPX instruction to get bound violation information" Reported-by: Dan Carpenter Signed-off-by: Dave Hansen Cc: x86@kernel.org Cc: Dave Hansen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20151201003113.D800C1E0@viggo.jf.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 1202d5c..b2fd67d 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -101,19 +101,19 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, switch (type) { case REG_TYPE_RM: regno = X86_MODRM_RM(insn->modrm.value); - if (X86_REX_B(insn->rex_prefix.value) == 1) + if (X86_REX_B(insn->rex_prefix.value)) regno += 8; break; case REG_TYPE_INDEX: regno = X86_SIB_INDEX(insn->sib.value); - if (X86_REX_X(insn->rex_prefix.value) == 1) + if (X86_REX_X(insn->rex_prefix.value)) regno += 8; break; case REG_TYPE_BASE: regno = X86_SIB_BASE(insn->sib.value); - if (X86_REX_B(insn->rex_prefix.value) == 1) + if (X86_REX_B(insn->rex_prefix.value)) regno += 8; break; -- cgit v0.10.2 From 22eab1108781eff09961ae7001704f7bd8fb1dce Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Tue, 1 Dec 2015 00:54:36 +0300 Subject: x86/signal: Fix restart_syscall number for x32 tasks When restarting a syscall with regs->ax == -ERESTART_RESTARTBLOCK, regs->ax is assigned to a restart_syscall number. For x32 tasks, this syscall number must have __X32_SYSCALL_BIT set, otherwise it will be an x86_64 syscall number instead of a valid x32 syscall number. This issue has been there since the introduction of x32. Reported-by: strace/tests/restart_syscall.test Reported-and-tested-by: Elvira Khabirova Signed-off-by: Dmitry V. Levin Cc: Elvira Khabirova Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20151130215436.GA25996@altlinux.org Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index b7ffb7c..cb6282c 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -690,12 +690,15 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) signal_setup_done(failed, ksig, stepping); } -#ifdef CONFIG_X86_32 -#define NR_restart_syscall __NR_restart_syscall -#else /* !CONFIG_X86_32 */ -#define NR_restart_syscall \ - test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall -#endif /* CONFIG_X86_32 */ +static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs) +{ +#if defined(CONFIG_X86_32) || !defined(CONFIG_X86_64) + return __NR_restart_syscall; +#else /* !CONFIG_X86_32 && CONFIG_X86_64 */ + return test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : + __NR_restart_syscall | (regs->orig_ax & __X32_SYSCALL_BIT); +#endif /* CONFIG_X86_32 || !CONFIG_X86_64 */ +} /* * Note that 'init' is a special process: it doesn't get signals it doesn't @@ -724,7 +727,7 @@ void do_signal(struct pt_regs *regs) break; case -ERESTART_RESTARTBLOCK: - regs->ax = NR_restart_syscall; + regs->ax = get_nr_restart_syscall(regs); regs->ip -= 2; break; } -- cgit v0.10.2 From e0fbac1cd49c5ca6cb6a0aa918d0943ce95d906c Mon Sep 17 00:00:00 2001 From: Yuanfang Chen Date: Tue, 24 Nov 2015 12:05:01 -0500 Subject: perf/x86/intel: Make L1D_PEND_MISS.FB_FULL not constrained on Haswell There was a mistake in the Haswell constraints table. Signed-off-by: Yuanfang Chen Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andi Kleen Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1448384701-9110-1-git-send-email-cheny@udel.edu 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 f63360b..e2a4300 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -232,7 +232,7 @@ static struct event_constraint intel_hsw_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ - INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.* */ + INTEL_UEVENT_CONSTRAINT(0x148, 0x4), /* L1D_PEND_MISS.PENDING */ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ -- cgit v0.10.2 From 169b932a15318e8e9f2f0f12eeb55dda09c8737f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 9 Nov 2015 10:24:31 +0100 Subject: perf/x86/intel: Fix INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA macro We need to add rest of the flags to the constraint mask instead of another INTEL_ARCH_EVENT_MASK, fixing a typo. Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1447061071-28085-1-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index ab18b8a..d0e35eb 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -387,7 +387,7 @@ struct cpu_hw_events { /* Check flags and event code/umask, and set the HSW N/A flag */ #define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \ __EVENT_CONSTRAINT(code, n, \ - INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW) -- cgit v0.10.2 From 4e93ad601a4308d4a67673c81556580817d56940 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 4 Nov 2015 16:00:05 +0100 Subject: perf: Do not send exit event twice In case we monitor events system wide, we get EXIT event (when configured) twice for each task that exited. Note doubled lines with same pid/tid in following example: $ sudo ./perf record -a ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.480 MB perf.data (2518 samples) ] $ sudo ./perf report -D | grep EXIT 0 60290687567581 0x59910 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687568354 0x59948 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687988744 0x59ad8 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 0 60290687989198 0x59b10 [0x38]: PERF_RECORD_EXIT(1250:1250):(1250:1250) 1 60290692567895 0x62af0 [0x38]: PERF_RECORD_EXIT(1253:1253):(1253:1253) 1 60290692568322 0x62b28 [0x38]: PERF_RECORD_EXIT(1253:1253):(1253:1253) 2 60290692739276 0x69a18 [0x38]: PERF_RECORD_EXIT(1252:1252):(1252:1252) 2 60290692739910 0x69a50 [0x38]: PERF_RECORD_EXIT(1252:1252):(1252:1252) The reason is that the cpu contexts are processes each time we call perf_event_task. I'm changing the perf_event_aux logic to serve task_ctx and cpu contexts separately, which ensure we don't get EXIT event generated twice on same cpu context. This does not affect other auxiliary events, as they don't use task_ctx at all. Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1446649205-5822-1-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 49a5118..39cf4a4 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5683,6 +5683,17 @@ perf_event_aux_ctx(struct perf_event_context *ctx, } static void +perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, + struct perf_event_context *task_ctx) +{ + rcu_read_lock(); + preempt_disable(); + perf_event_aux_ctx(task_ctx, output, data); + preempt_enable(); + rcu_read_unlock(); +} + +static void perf_event_aux(perf_event_aux_output_cb output, void *data, struct perf_event_context *task_ctx) { @@ -5691,14 +5702,23 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, struct pmu *pmu; int ctxn; + /* + * If we have task_ctx != NULL we only notify + * the task context itself. The task_ctx is set + * only for EXIT events before releasing task + * context. + */ + if (task_ctx) { + perf_event_aux_task_ctx(output, data, task_ctx); + return; + } + rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); if (cpuctx->unique_pmu != pmu) goto next; perf_event_aux_ctx(&cpuctx->ctx, output, data); - if (task_ctx) - goto next; ctxn = pmu->task_ctx_nr; if (ctxn < 0) goto next; @@ -5708,12 +5728,6 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, next: put_cpu_ptr(pmu->pmu_cpu_context); } - - if (task_ctx) { - preempt_disable(); - perf_event_aux_ctx(task_ctx, output, data); - preempt_enable(); - } rcu_read_unlock(); } @@ -8803,10 +8817,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) struct perf_event_context *child_ctx, *clone_ctx = NULL; unsigned long flags; - if (likely(!child->perf_event_ctxp[ctxn])) { - perf_event_task(child, NULL, 0); + if (likely(!child->perf_event_ctxp[ctxn])) return; - } local_irq_save(flags); /* @@ -8890,6 +8902,14 @@ void perf_event_exit_task(struct task_struct *child) for_each_task_context_nr(ctxn) perf_event_exit_task_context(child, ctxn); + + /* + * The perf_event_exit_task_context calls perf_event_task + * with child's task_ctx, which generates EXIT events for + * child contexts and sets child->perf_event_ctxp[] to NULL. + * At this point we need to send EXIT events to cpu contexts. + */ + perf_event_task(child, NULL, 0); } static void perf_free_event(struct perf_event *event, -- cgit v0.10.2 From acff81ec2c79492b180fade3c2894425cd35a545 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 4 Dec 2015 19:18:48 +0100 Subject: ovl: fix permission checking for setattr [Al Viro] The bug is in being too enthusiastic about optimizing ->setattr() away - instead of "copy verbatim with metadata" + "chmod/chown/utimes" (with the former being always safe and the latter failing in case of insufficient permissions) it tries to combine these two. Note that copyup itself will have to do ->setattr() anyway; _that_ is where the elevated capabilities are right. Having these two ->setattr() (one to set verbatim copy of metadata, another to do what overlayfs ->setattr() had been asked to do in the first place) combined is where it breaks. Signed-off-by: Miklos Szeredi Cc: Signed-off-by: Al Viro diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index ec0c2a050..9612849 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -49,13 +49,13 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) if (err) goto out; - upperdentry = ovl_dentry_upper(dentry); - if (upperdentry) { + err = ovl_copy_up(dentry); + if (!err) { + upperdentry = ovl_dentry_upper(dentry); + mutex_lock(&upperdentry->d_inode->i_mutex); err = notify_change(upperdentry, attr, NULL); mutex_unlock(&upperdentry->d_inode->i_mutex); - } else { - err = ovl_copy_up_last(dentry, attr, false); } ovl_drop_write(dentry); out: -- cgit v0.10.2 From 0f7ff2dabbc95ed7a8019d142274f0c7e083577d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 6 Dec 2015 12:31:07 -0500 Subject: ovl: get rid of the dead code left from broken (and disabled) optimizations Signed-off-by: Al Viro diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 871fcb6..0a89834 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -195,8 +195,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, struct dentry *dentry, struct path *lowerpath, - struct kstat *stat, struct iattr *attr, - const char *link) + struct kstat *stat, const char *link) { struct inode *wdir = workdir->d_inode; struct inode *udir = upperdir->d_inode; @@ -240,8 +239,6 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, mutex_lock(&newdentry->d_inode->i_mutex); err = ovl_set_attr(newdentry, stat); - if (!err && attr) - err = notify_change(newdentry, attr, NULL); mutex_unlock(&newdentry->d_inode->i_mutex); if (err) goto out_cleanup; @@ -286,8 +283,7 @@ out_cleanup: * that point the file will have already been copied up anyway. */ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, - struct path *lowerpath, struct kstat *stat, - struct iattr *attr) + struct path *lowerpath, struct kstat *stat) { struct dentry *workdir = ovl_workdir(dentry); int err; @@ -345,26 +341,19 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, } upperdentry = ovl_dentry_upper(dentry); if (upperdentry) { - unlock_rename(workdir, upperdir); + /* Raced with another copy-up? Nothing to do, then... */ err = 0; - /* Raced with another copy-up? Do the setattr here */ - if (attr) { - mutex_lock(&upperdentry->d_inode->i_mutex); - err = notify_change(upperdentry, attr, NULL); - mutex_unlock(&upperdentry->d_inode->i_mutex); - } - goto out_put_cred; + goto out_unlock; } err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, - stat, attr, link); + stat, link); if (!err) { /* Restore timestamps on parent (best effort) */ ovl_set_timestamps(upperdir, &pstat); } out_unlock: unlock_rename(workdir, upperdir); -out_put_cred: revert_creds(old_cred); put_cred(override_cred); @@ -406,7 +395,7 @@ int ovl_copy_up(struct dentry *dentry) ovl_path_lower(next, &lowerpath); err = vfs_getattr(&lowerpath, &stat); if (!err) - err = ovl_copy_up_one(parent, next, &lowerpath, &stat, NULL); + err = ovl_copy_up_one(parent, next, &lowerpath, &stat); dput(parent); dput(next); diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 9612849..4060ffd 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -12,8 +12,7 @@ #include #include "overlayfs.h" -static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr, - bool no_data) +static int ovl_copy_up_truncate(struct dentry *dentry) { int err; struct dentry *parent; @@ -30,10 +29,8 @@ static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr, if (err) goto out_dput_parent; - if (no_data) - stat.size = 0; - - err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat, attr); + stat.size = 0; + err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); out_dput_parent: dput(parent); @@ -353,7 +350,7 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) return ERR_PTR(err); if (file_flags & O_TRUNC) - err = ovl_copy_up_last(dentry, NULL, true); + err = ovl_copy_up_truncate(dentry); else err = ovl_copy_up(dentry); ovl_drop_write(dentry); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index ea5a40b..e17154a 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -194,7 +194,6 @@ void ovl_cleanup(struct inode *dir, struct dentry *dentry); /* copy_up.c */ int ovl_copy_up(struct dentry *dentry); int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, - struct path *lowerpath, struct kstat *stat, - struct iattr *attr); + struct path *lowerpath, struct kstat *stat); int ovl_copy_xattr(struct dentry *old, struct dentry *new); int ovl_set_attr(struct dentry *upper, struct kstat *stat); -- cgit v0.10.2 From 2788cc47f4593cca2c3c73c7bb82cd32b88c8ef7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 6 Dec 2015 12:33:02 -0500 Subject: Don't reset ->total_link_count on nested calls of vfs_path_lookup() we already zero it on outermost set_nameidata(), so initialization in path_init() is pointless and wrong. The same DoS exists on pre-4.2 kernels, but there a slightly different fix will be needed. Cc: stable@vger.kernel.org # v4.2 Signed-off-by: Al Viro diff --git a/fs/namei.c b/fs/namei.c index d84d7c7..0c3974c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1996,7 +1996,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; nd->depth = 0; - nd->total_link_count = 0; if (flags & LOOKUP_ROOT) { struct dentry *root = nd->root.dentry; struct inode *inode = root->d_inode; -- cgit v0.10.2 From d035e336287b5ea7e88dd9714e31dad5907c6aaf Mon Sep 17 00:00:00 2001 From: James Simmons Date: Fri, 4 Dec 2015 18:23:08 -0500 Subject: staging/lustre: remove IOC_LIBCFS_PING_TEST ioctl The ioctl IOC_LIBCFS_PING_TEST has not been used in ages. The recent nidstring changes which moved all the nidstring operations from libcfs to the LNet layer but this ioctl code was still using an nidstring operation that was causing a circular dependency loop between libcfs and LNet. Signed-off-by: James Simmons Signed-off-by: Oleg Drokin Signed-off-by: Linus Torvalds diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h index f5d741f..485ab26 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h @@ -110,7 +110,6 @@ struct libcfs_ioctl_handler { #define IOC_LIBCFS_CLEAR_DEBUG _IOWR('e', 31, long) #define IOC_LIBCFS_MARK_DEBUG _IOWR('e', 32, long) #define IOC_LIBCFS_MEMHOG _IOWR('e', 36, long) -#define IOC_LIBCFS_PING_TEST _IOWR('e', 37, long) /* lnet ioctls */ #define IOC_LIBCFS_GET_NI _IOWR('e', 50, long) #define IOC_LIBCFS_FAIL_NID _IOWR('e', 51, long) diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 07a6859..e7c2b26 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -274,23 +274,6 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd, } break; - case IOC_LIBCFS_PING_TEST: { - extern void (kping_client)(struct libcfs_ioctl_data *); - void (*ping)(struct libcfs_ioctl_data *); - - CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n", - data->ioc_count, libcfs_nid2str(data->ioc_nid), - libcfs_nid2str(data->ioc_nid)); - ping = symbol_get(kping_client); - if (!ping) - CERROR("symbol_get failed\n"); - else { - ping(data); - symbol_put(kping_client); - } - return 0; - } - default: { struct libcfs_ioctl_handler *hand; -- cgit v0.10.2 From 527e9316f8ec44bd53d90fb9f611fa7ffff52bb9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Dec 2015 15:43:12 -0800 Subject: Linux 4.4-rc4 diff --git a/Makefile b/Makefile index 904a1d6..d644f6e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Blurry Fish Butt # *DOCUMENTATION* -- cgit v0.10.2 From 7c23b7c1996597dd9d60bb282fb5fa1be6ebd18b Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Mon, 7 Dec 2015 15:59:13 +0800 Subject: ALSA: hda - Fix playback noise with 24/32 bit sample size on BXT In BXT-P A0, HD-Audio DMA requests is later than expected, and makes an audio stream sensitive to system latencies when 24/32 bits are playing. Adjusting threshold of DMA fifo to force the DMA request sooner to improve latency tolerance at the expense of power. v2: move Intel specific code to hda_intel.c Signed-off-by: Lu, Han Signed-off-by: Takashi Iwai diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 2ae8812..94dc6a9 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -93,6 +93,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_HSW_EM4 0x100c #define AZX_REG_HSW_EM5 0x1010 +/* Skylake/Broxton display HD-A controller Extended Mode registers */ +#define AZX_REG_SKL_EM4L 0x1040 + /* PCI space */ #define AZX_PCIREG_TCSEL 0x44 diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 963f824..bff5c8b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -355,6 +355,8 @@ enum { ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) +#define IS_BROXTON(pci) ((pci)->device == 0x5a98) + static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -506,15 +508,36 @@ static void azx_init_pci(struct azx *chip) } } +/* + * In BXT-P A0, HD-Audio DMA requests is later than expected, + * and makes an audio stream sensitive to system latencies when + * 24/32 bits are playing. + * Adjusting threshold of DMA fifo to force the DMA request + * sooner to improve latency tolerance at the expense of power. + */ +static void bxt_reduce_dma_latency(struct azx *chip) +{ + u32 val; + + val = azx_readl(chip, SKL_EM4L); + val &= (0x3 << 20); + azx_writel(chip, SKL_EM4L, val); +} + static void hda_intel_init_chip(struct azx *chip, bool full_reset) { struct hdac_bus *bus = azx_bus(chip); + struct pci_dev *pci = chip->pci; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, true); azx_init_chip(chip, full_reset); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, false); + + /* reduce dma latency to avoid noise */ + if (IS_BROXTON(pci)) + bxt_reduce_dma_latency(chip); } /* calculate runtime delay from LPIB */ -- cgit v0.10.2 From 02f6ff90400d055f08b0ba0b5f0707630b6faed7 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 7 Dec 2015 11:29:31 +0100 Subject: ALSA: hda - Add inverted dmic for Packard Bell DOTS On the internal mic of the Packard Bell DOTS, one channel has an inverted signal. Add a quirk to fix this up. Cc: stable@vger.kernel.org BugLink: https://bugs.launchpad.net/bugs/1523232 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9bedf7c..ebc5362 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6409,6 +6409,7 @@ static const struct hda_fixup alc662_fixups[] = { static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), -- cgit v0.10.2 From 2ac46030331e2952a56c05bd15d99082fc410088 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 15 Nov 2015 15:11:00 +0200 Subject: virtio-net: Stop doing DMA from the stack Once virtio starts using the DMA API, we won't be able to safely DMA from the stack. virtio-net does a couple of config DMA requests from small stack buffers -- switch to using dynamically-allocated memory. This should have no effect on any performance-critical code paths. Reported-by: Andy Lutomirski Signed-off-by: Michael S. Tsirkin Tested-by: Andy Lutomirski diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d8838ded..f94ab78 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -140,6 +140,12 @@ struct virtnet_info { /* CPU hot plug notifier */ struct notifier_block nb; + + /* Control VQ buffers: protected by the rtnl lock */ + struct virtio_net_ctrl_hdr ctrl_hdr; + virtio_net_ctrl_ack ctrl_status; + u8 ctrl_promisc; + u8 ctrl_allmulti; }; struct padded_vnet_hdr { @@ -976,31 +982,30 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, struct scatterlist *out) { struct scatterlist *sgs[4], hdr, stat; - struct virtio_net_ctrl_hdr ctrl; - virtio_net_ctrl_ack status = ~0; unsigned out_num = 0, tmp; /* Caller should know better */ BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); - ctrl.class = class; - ctrl.cmd = cmd; + vi->ctrl_status = ~0; + vi->ctrl_hdr.class = class; + vi->ctrl_hdr.cmd = cmd; /* Add header */ - sg_init_one(&hdr, &ctrl, sizeof(ctrl)); + sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr)); sgs[out_num++] = &hdr; if (out) sgs[out_num++] = out; /* Add return status. */ - sg_init_one(&stat, &status, sizeof(status)); + sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status)); sgs[out_num] = &stat; BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC); if (unlikely(!virtqueue_kick(vi->cvq))) - return status == VIRTIO_NET_OK; + return vi->ctrl_status == VIRTIO_NET_OK; /* Spin for a response, the kick causes an ioport write, trapping * into the hypervisor, so the request should be handled immediately. @@ -1009,7 +1014,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, !virtqueue_is_broken(vi->cvq)) cpu_relax(); - return status == VIRTIO_NET_OK; + return vi->ctrl_status == VIRTIO_NET_OK; } static int virtnet_set_mac_address(struct net_device *dev, void *p) @@ -1151,7 +1156,6 @@ static void virtnet_set_rx_mode(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); struct scatterlist sg[2]; - u8 promisc, allmulti; struct virtio_net_ctrl_mac *mac_data; struct netdev_hw_addr *ha; int uc_count; @@ -1163,22 +1167,22 @@ static void virtnet_set_rx_mode(struct net_device *dev) if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) return; - promisc = ((dev->flags & IFF_PROMISC) != 0); - allmulti = ((dev->flags & IFF_ALLMULTI) != 0); + vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0); + vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0); - sg_init_one(sg, &promisc, sizeof(promisc)); + sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, VIRTIO_NET_CTRL_RX_PROMISC, sg)) dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", - promisc ? "en" : "dis"); + vi->ctrl_promisc ? "en" : "dis"); - sg_init_one(sg, &allmulti, sizeof(allmulti)); + sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, VIRTIO_NET_CTRL_RX_ALLMULTI, sg)) dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", - allmulti ? "en" : "dis"); + vi->ctrl_allmulti ? "en" : "dis"); uc_count = netdev_uc_count(dev); mc_count = netdev_mc_count(dev); -- cgit v0.10.2 From ea013a9b205b47b1fcbc72522146fad560af0712 Mon Sep 17 00:00:00 2001 From: Andreas Werner Date: Fri, 4 Dec 2015 18:12:49 +0100 Subject: libata-eh.c: Introduce new ata port flag for controller which lockup on read log page Some controller lockup on a ata_read_log_page. Add new ata port flag ATA_FLAG_NO_LOG_PAGE which can used to blacklist a controller. If this flag is set, any attempt to read a log page returns an error without actually issuing the command. Signed-off-by: Andreas Werner Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index cb0508a..961acc7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1505,12 +1505,20 @@ static const char *ata_err_string(unsigned int err_mask) unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors) { + unsigned long ap_flags = dev->link->ap->flags; struct ata_taskfile tf; unsigned int err_mask; bool dma = false; DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page); + /* + * Return error without actually issuing the command on controllers + * which e.g. lockup on a read log page. + */ + if (ap_flags & ATA_FLAG_NO_LOG_PAGE) + return AC_ERR_DEV; + retry: ata_tf_init(dev, &tf); if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) && diff --git a/include/linux/libata.h b/include/linux/libata.h index 83577f8..600c1e0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -210,6 +210,7 @@ enum { ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ /* (doesn't imply presence) */ ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LOG_PAGE = (1 << 5), /* do not issue log page read */ ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ -- cgit v0.10.2 From 4f2568f5cb475529aa2894adc7c7912517c83cb0 Mon Sep 17 00:00:00 2001 From: Andreas Werner Date: Fri, 4 Dec 2015 18:14:14 +0100 Subject: ata/sata_fsl.c: add ATA_FLAG_NO_LOG_PAGE to blacklist the controller for log page reads Every attempt to issue a read log page command lockup the controller. The command is currently sent if the sata device includes the devlsp feature to read out the timing data. This attempt to read the data, locks up the controller and the device is not recognzied correctly (failed to set xfermode) and cannot be accessed. This was found on Freescale P1013/P1022 and T4240 CPUs using a ATP IG mSATA 4GB with the devslp feature. fsl-sata ff718000.sata: Sata FSL Platform/CSB Driver init [ 1.254195] scsi0 : sata_fsl [ 1.256004] ata1: SATA max UDMA/133 irq 74 [ 1.370666] fsl-gianfar ethernet.3: enabled errata workarounds, flags: 0x4 [ 1.470671] fsl-gianfar ethernet.4: enabled errata workarounds, flags: 0x4 [ 1.775584] ata1: Signature Update detected @ 504 msecs [ 1.947594] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) [ 1.948366] ata1.00: ATA-8: ATP IG mSATA, 20150311, max UDMA/133 [ 1.948371] ata1.00: 7732368 sectors, multi 0: LBA [ 1.948843] ata1.00: failed to get Identify Device Data, Emask 0x1 [ 1.948857] ata1.00: failed to set xfermode (err_mask=0x40) [ 7.467557] ata1: Signature Update detected @ 504 msecs [ 7.639560] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) [ 7.651320] ata1.00: failed to get Identify Device Data, Emask 0x1 [ 7.651360] ata1.00: failed to set xfermode (err_mask=0x40) [ 7.655628] ata1: limiting SATA link speed to 1.5 Gbps [ 7.659458] ata1.00: limiting speed to UDMA/133:PIO3 [ 13.163554] ata1: Signature Update detected @ 504 msecs [ 13.335558] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300) [ 13.347298] ata1.00: failed to get Identify Device Data, Emask 0x1 [ 13.347334] ata1.00: failed to set xfermode (err_mask=0x40) [ 13.351601] ata1.00: disabled [ 13.353278] ata1: exception Emask 0x50 SAct 0x0 SErr 0x800 action 0x6 frozen t4 [ 13.359281] ata1: SError: { HostInt } [ 13.361644] ata1: hard resetting link Signed-off-by: Andreas Werner Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 5389579..a723ae9 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -45,7 +45,8 @@ enum { SATA_FSL_MAX_PRD_DIRECT = 16, /* Direct PRDT entries */ SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | - ATA_FLAG_PMP | ATA_FLAG_NCQ | ATA_FLAG_AN), + ATA_FLAG_PMP | ATA_FLAG_NCQ | + ATA_FLAG_AN | ATA_FLAG_NO_LOG_PAGE), SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH, SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */ -- cgit v0.10.2 From d542483876f6ed720f573de3fbb1d8e60ccd0d6e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 16 Nov 2015 16:57:08 +0200 Subject: vhost: relax log address alignment commit 5d9a07b0de512b77bf28d2401e5fe3351f00a240 ("vhost: relax used address alignment") fixed the alignment for the used virtual address, but not for the physical address used for logging. That's a mistake: alignment should clearly be the same for virtual and physical addresses, Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index eec2f11..080422f 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -819,7 +819,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE); if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) || (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) || - (a.log_guest_addr & (sizeof(u64) - 1))) { + (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) { r = -EINVAL; break; } -- cgit v0.10.2 From c13f99b7e945dad5273a8b7ee230f4d1f22d3354 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 16 Sep 2015 19:29:17 -0500 Subject: virtio: fix memory leak of virtio ida cache layers The virtio core uses a static ida named virtio_index_ida for assigning index numbers to virtio devices during registration. The ida core may allocate some internal idr cache layers and an ida bitmap upon any ida allocation, and all these layers are truely freed only upon the ida destruction. The virtio_index_ida is not destroyed at present, leading to a memory leak when using the virtio core as a module and atleast one virtio device is registered and unregistered. Fix this by invoking ida_destroy() in the virtio core module exit. Cc: stable@vger.kernel.org Signed-off-by: Suman Anna Signed-off-by: Michael S. Tsirkin diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index b1877d7..7062bb0 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -412,6 +412,7 @@ static int virtio_init(void) static void __exit virtio_exit(void) { bus_unregister(&virtio_bus); + ida_destroy(&virtio_index_ida); } core_initcall(virtio_init); module_exit(virtio_exit); -- cgit v0.10.2 From 40c172e5d99220c8a99dbc4468e792c74494a596 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 29 Nov 2015 12:43:48 +0200 Subject: tools/virtio: move list macro stubs Makes them more generally available. Signed-off-by: Michael S. Tsirkin diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h index 0a3da64..4db7d56 100644 --- a/tools/virtio/linux/kernel.h +++ b/tools/virtio/linux/kernel.h @@ -110,4 +110,10 @@ static inline void free_page(unsigned long addr) (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) +/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */ +#define list_add_tail(a, b) do {} while (0) +#define list_del(a) do {} while (0) +#define list_for_each_entry(a, b, c) while (0) +/* end of stubs */ + #endif /* KERNEL_H */ diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index a3e0701..ee125e7 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -3,12 +3,6 @@ #include #include -/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */ -#define list_add_tail(a, b) do {} while (0) -#define list_del(a) do {} while (0) -#define list_for_each_entry(a, b, c) while (0) -/* end of stubs */ - struct virtio_device { void *dev; u64 features; -- cgit v0.10.2 From 55564a02b2ad4dab0c29fd9391d5118592c7fdc8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 29 Nov 2015 13:03:23 +0200 Subject: tools/virtio: fix byteswap logic commit cf561f0d2eb74574ad9985a2feab134267a9d298 ("virtio: introduce virtio_is_little_endian() helper") changed byteswap logic to skip feature bit checks for LE platforms, but didn't update tools/virtio, so vring_bench started failing. Update the copy under tools/virtio/ (TODO: find a way to avoid this code duplication). Cc: Greg Kurz Signed-off-by: Michael S. Tsirkin diff --git a/tools/virtio/linux/virtio_config.h b/tools/virtio/linux/virtio_config.h index 806d683..57a6964 100644 --- a/tools/virtio/linux/virtio_config.h +++ b/tools/virtio/linux/virtio_config.h @@ -40,33 +40,39 @@ static inline void __virtio_clear_bit(struct virtio_device *vdev, #define virtio_has_feature(dev, feature) \ (__virtio_test_bit((dev), feature)) +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); +} + +/* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } - -- cgit v0.10.2 From 5fba13b5cf5856e725de35665c37b647323d3b9a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 29 Nov 2015 13:34:44 +0200 Subject: vhost: replace % with & on data path We know vring num is a power of 2, so use & to mask the high bits. Signed-off-by: Michael S. Tsirkin diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 080422f..ad2146a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1369,7 +1369,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ if (unlikely(__get_user(ring_head, - &vq->avail->ring[last_avail_idx % vq->num]))) { + &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); @@ -1489,7 +1489,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, u16 old, new; int start; - start = vq->last_used_idx % vq->num; + start = vq->last_used_idx & (vq->num - 1); used = vq->used->ring + start; if (count == 1) { if (__put_user(heads[0].id, &used->id)) { @@ -1531,7 +1531,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, { int start, n, r; - start = vq->last_used_idx % vq->num; + start = vq->last_used_idx & (vq->num - 1); n = vq->num - start; if (n < count) { r = __vhost_add_used_n(vq, heads, n); -- cgit v0.10.2 From 82107539bbb9db303fb6676c78c836add5680bb0 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 1 Dec 2015 15:32:49 +0100 Subject: virtio: Do not drop __GFP_HIGH in alloc_indirect b92b1b89a33c ("virtio: force vring descriptors to be allocated from lowmem") tried to exclude highmem pages for descriptors so it cleared __GFP_HIGHMEM from a given gfp mask. The patch also cleared __GFP_HIGH which doesn't make much sense for this fix because __GFP_HIGH only controls access to memory reserves and it doesn't have any influence on the zone selection. Some of the call paths use GFP_ATOMIC and dropping __GFP_HIGH will reduce their changes for success because the lack of access to memory reserves. Signed-off-by: Michal Hocko Signed-off-by: Michael S. Tsirkin Acked-by: Will Deacon Reviewed-by: Mel Gorman diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 096b857..abdb341 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -109,7 +109,7 @@ static struct vring_desc *alloc_indirect(struct virtqueue *_vq, * otherwise virt_to_phys will give us bogus addresses in the * virtqueue. */ - gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH); + gfp &= ~__GFP_HIGHMEM; desc = kmalloc(total_sg * sizeof(struct vring_desc), gfp); if (!desc) -- cgit v0.10.2 From f277ec42f38f406ed073569b24b04f1c291fec0f Mon Sep 17 00:00:00 2001 From: Venkatesh Srinivas Date: Tue, 10 Nov 2015 16:21:07 -0800 Subject: virtio_ring: shadow available ring flags & index Improves cacheline transfer flow of available ring header. Virtqueues are implemented as a pair of rings, one producer->consumer avail ring and one consumer->producer used ring; preceding the avail ring in memory are two contiguous u16 fields -- avail->flags and avail->idx. A producer posts work by writing to avail->idx and a consumer reads avail->idx. The flags and idx fields only need to be written by a producer CPU and only read by a consumer CPU; when the producer and consumer are running on different CPUs and the virtio_ring code is structured to only have source writes/sink reads, we can continuously transfer the avail header cacheline between 'M' states between cores. This flow optimizes core -> core bandwidth on certain CPUs. (see: "Software Optimization Guide for AMD Family 15h Processors", Section 11.6; similar language appears in the 10h guide and should apply to CPUs w/ exclusive caches, using LLC as a transfer cache) Unfortunately the existing virtio_ring code issued reads to the avail->idx and read-modify-writes to avail->flags on the producer. This change shadows the flags and index fields in producer memory; the vring code now reads from the shadows and only ever writes to avail->flags and avail->idx, allowing the cacheline to transfer core -> core optimally. In a concurrent version of vring_bench, the time required for 10,000,000 buffer checkout/returns was reduced by ~2% (average across many runs) on an AMD Piledriver (15h) CPU: (w/o shadowing): Performance counter stats for './vring_bench': 5,451,082,016 L1-dcache-loads ... 2.221477739 seconds time elapsed (w/ shadowing): Performance counter stats for './vring_bench': 5,405,701,361 L1-dcache-loads ... 2.168405376 seconds time elapsed The further away (in a NUMA sense) virtio producers and consumers are from each other, the more we expect to benefit. Physical implementations of virtio devices and implementations of virtio where the consumer polls vring avail indexes (vhost) should also benefit. Signed-off-by: Venkatesh Srinivas Signed-off-by: Michael S. Tsirkin diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index abdb341..ee663c4 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -80,6 +80,12 @@ struct vring_virtqueue { /* Last used index we've seen. */ u16 last_used_idx; + /* Last written value to avail->flags */ + u16 avail_flags_shadow; + + /* Last written value to avail->idx in guest byte order */ + u16 avail_idx_shadow; + /* How to notify other side. FIXME: commonalize hcalls! */ bool (*notify)(struct virtqueue *vq); @@ -235,13 +241,14 @@ static inline int virtqueue_add(struct virtqueue *_vq, /* Put entry in available array (but don't update avail->idx until they * do sync). */ - avail = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) & (vq->vring.num - 1); + avail = vq->avail_idx_shadow & (vq->vring.num - 1); vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head); /* Descriptors and available array need to be set before we expose the * new available array entries. */ virtio_wmb(vq->weak_barriers); - vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) + 1); + vq->avail_idx_shadow++; + vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); vq->num_added++; pr_debug("Added buffer head %i to %p\n", head, vq); @@ -354,8 +361,8 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq) * event. */ virtio_mb(vq->weak_barriers); - old = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->num_added; - new = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx); + old = vq->avail_idx_shadow - vq->num_added; + new = vq->avail_idx_shadow; vq->num_added = 0; #ifdef DEBUG @@ -510,7 +517,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) /* If we expect an interrupt for the next entry, tell host * by writing event index and flush out the write before * the read in the next get_buf call. */ - if (!(vq->vring.avail->flags & cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT))) { + if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx); virtio_mb(vq->weak_barriers); } @@ -537,7 +544,11 @@ void virtqueue_disable_cb(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); - vq->vring.avail->flags |= cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT); + if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { + vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); + } + } EXPORT_SYMBOL_GPL(virtqueue_disable_cb); @@ -565,7 +576,10 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq) /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to * either clear the flags bit or point the event index at the next * entry. Always do both to keep code simple. */ - vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT); + if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { + vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); + } vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx); END_USE(vq); return last_used_idx; @@ -633,9 +647,12 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to * either clear the flags bit or point the event index at the next * entry. Always do both to keep code simple. */ - vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT); + if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { + vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); + } /* TODO: tune this threshold */ - bufs = (u16)(virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->last_used_idx) * 3 / 4; + bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4; vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs); virtio_mb(vq->weak_barriers); if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) { @@ -670,7 +687,8 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq) /* detach_buf clears data, so grab it now. */ buf = vq->data[i]; detach_buf(vq, i); - vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - 1); + vq->avail_idx_shadow--; + vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); END_USE(vq); return buf; } @@ -735,6 +753,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, vq->weak_barriers = weak_barriers; vq->broken = false; vq->last_used_idx = 0; + vq->avail_flags_shadow = 0; + vq->avail_idx_shadow = 0; vq->num_added = 0; list_add_tail(&vq->vq.list, &vdev->vqs); #ifdef DEBUG @@ -746,8 +766,10 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); /* No callback? Tell other side not to bother us. */ - if (!callback) - vq->vring.avail->flags |= cpu_to_virtio16(vdev, VRING_AVAIL_F_NO_INTERRUPT); + if (!callback) { + vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; + vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); + } /* Put everything in free lists. */ vq->free_head = 0; -- cgit v0.10.2 From f27a62995330fdc5f804acf2ebf1444f9025c879 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sun, 6 Dec 2015 11:25:43 +0100 Subject: lightnvm: use flags in rrpc_get_blk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rrpc_get_blk use constant 0 as the input parameter of nvm_get_blk, this may result in getting gc block failed unexpectedly. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 75e59c3..d606c7a 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -182,7 +182,7 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun, struct nvm_block *blk; struct rrpc_block *rblk; - blk = nvm_get_blk(rrpc->dev, rlun->parent, 0); + blk = nvm_get_blk(rrpc->dev, rlun->parent, flags); if (!blk) return NULL; -- cgit v0.10.2 From d3d1a43842077c53e22dedaebfe7cb52022b18e1 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sun, 6 Dec 2015 11:25:44 +0100 Subject: lightnvm: put blks when luns configure failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put the allocated blocks back to the free list when the luns configure failed, to make these blocks useable to others. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index d606c7a..cf1a4a5 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -202,6 +202,20 @@ static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk) nvm_put_blk(rrpc->dev, rblk->parent); } +static void rrpc_put_blks(struct rrpc *rrpc) +{ + struct rrpc_lun *rlun; + int i; + + for (i = 0; i < rrpc->nr_luns; i++) { + rlun = &rrpc->luns[i]; + if (rlun->cur) + rrpc_put_blk(rrpc, rlun->cur); + if (rlun->gc_cur) + rrpc_put_blk(rrpc, rlun->gc_cur); + } +} + static struct rrpc_lun *get_next_lun(struct rrpc *rrpc) { int next = atomic_inc_return(&rrpc->next_lun); @@ -1224,18 +1238,21 @@ static int rrpc_luns_configure(struct rrpc *rrpc) rblk = rrpc_get_blk(rrpc, rlun, 0); if (!rblk) - return -EINVAL; + goto err; rrpc_set_lun_cur(rlun, rblk); /* Emergency gc block */ rblk = rrpc_get_blk(rrpc, rlun, 1); if (!rblk) - return -EINVAL; + goto err; rlun->gc_cur = rblk; } return 0; +err: + rrpc_put_blks(rrpc); + return -EINVAL; } static struct nvm_tgt_type tt_rrpc; -- cgit v0.10.2 From e9b76a80f1f165cb031f62128dc07d219e29f5a3 Mon Sep 17 00:00:00 2001 From: Wenwei Tao Date: Sun, 6 Dec 2015 11:25:45 +0100 Subject: lightnvm: refactor spin_unlock in gennvm_get_blk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spin_unlock is duplicated multiple times. Jump to a single unlock to improve the code flow. Signed-off-by: Wenwei Tao Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 35dde84..ce60254 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -262,14 +262,11 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, if (list_empty(&lun->free_list)) { pr_err_ratelimited("gennvm: lun %u have no free pages available", lun->vlun.id); - spin_unlock(&vlun->lock); goto out; } - while (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) { - spin_unlock(&vlun->lock); + if (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) goto out; - } blk = list_first_entry(&lun->free_list, struct nvm_block, list); list_move_tail(&blk->list, &lun->used_list); @@ -278,8 +275,8 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, lun->vlun.nr_free_blocks--; lun->vlun.nr_inuse_blocks++; - spin_unlock(&vlun->lock); out: + spin_unlock(&vlun->lock); return blk; } -- cgit v0.10.2 From 437f8f9a1e923deab6c61822c36f29f4a2198cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:46 +0100 Subject: lightnvm: check mm before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The core can may issue I/Os before a media manager is registered with the lightnvm subsystem. Make sure that we don't call the media manager ->end_io prematurely with a null pointer. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 06c3364..762c9a7 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -455,7 +455,7 @@ static void nvme_nvm_end_io(struct request *rq, int error) struct nvm_rq *rqd = rq->end_io_data; struct nvm_dev *dev = rqd->dev; - if (dev->mt->end_io(rqd, error)) + if (dev->mt && dev->mt->end_io(rqd, error)) pr_err("nvme: err status: %x result: %lx\n", rq->errors, (unsigned long)rq->special); -- cgit v0.10.2 From 57b4bd06ff0372fe1e3617889c4b37fbd500364a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:47 +0100 Subject: lightnvm: comments on constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not obvious what NVM_IO_* and NVM_BLK_T_* are used for. Make sure to comment them appropriately as the other constants. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index c6916ae..935ef38 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -50,9 +50,16 @@ enum { NVM_IO_DUAL_ACCESS = 0x1, NVM_IO_QUAD_ACCESS = 0x2, + /* NAND Access Modes */ NVM_IO_SUSPEND = 0x80, NVM_IO_SLC_MODE = 0x100, NVM_IO_SCRAMBLE_DISABLE = 0x200, + + /* Block Types */ + NVM_BLK_T_FREE = 0x0, + NVM_BLK_T_BAD = 0x1, + NVM_BLK_T_DEV = 0x2, + NVM_BLK_T_HOST = 0x4, }; struct nvm_id_group { -- cgit v0.10.2 From 16f26c3aa9b9c36a9d1092ae3258461d1008481e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:48 +0100 Subject: lightnvm: replace req queue with nvmdev for lld MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the case where a request queue is passed to the low lever lightnvm device drive integration, the device driver might pass its admin commands through another queue. Instead pass nvm_dev, and let the low level drive the appropriate queue. Reported-by: Christoph Hellwig Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 0c3940e..7981b74 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -444,8 +444,9 @@ static void null_lnvm_end_io(struct request *rq, int error) blk_put_request(rq); } -static int null_lnvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) +static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) { + struct request_queue *q = dev->q; struct request *rq; struct bio *bio = rqd->bio; @@ -470,7 +471,7 @@ static int null_lnvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) return 0; } -static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) +static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id) { sector_t size = gb * 1024 * 1024 * 1024ULL; sector_t blksize; @@ -523,7 +524,7 @@ static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) return 0; } -static void *null_lnvm_create_dma_pool(struct request_queue *q, char *name) +static void *null_lnvm_create_dma_pool(struct nvm_dev *dev, char *name) { mempool_t *virtmem_pool; @@ -541,7 +542,7 @@ static void null_lnvm_destroy_dma_pool(void *pool) mempool_destroy(pool); } -static void *null_lnvm_dev_dma_alloc(struct request_queue *q, void *pool, +static void *null_lnvm_dev_dma_alloc(struct nvm_dev *dev, void *pool, gfp_t mem_flags, dma_addr_t *dma_handler) { return mempool_alloc(pool, mem_flags); diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 86ce887..4a8d1fe 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -74,7 +74,7 @@ EXPORT_SYMBOL(nvm_unregister_target); void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags, dma_addr_t *dma_handler) { - return dev->ops->dev_dma_alloc(dev->q, dev->ppalist_pool, mem_flags, + return dev->ops->dev_dma_alloc(dev, dev->ppalist_pool, mem_flags, dma_handler); } EXPORT_SYMBOL(nvm_dev_dma_alloc); @@ -246,7 +246,7 @@ static int nvm_init(struct nvm_dev *dev) if (!dev->q || !dev->ops) return ret; - if (dev->ops->identity(dev->q, &dev->identity)) { + if (dev->ops->identity(dev, &dev->identity)) { pr_err("nvm: device could not be identified\n"); goto err; } @@ -326,8 +326,7 @@ int nvm_register(struct request_queue *q, char *disk_name, } if (dev->ops->max_phys_sect > 1) { - dev->ppalist_pool = dev->ops->create_dma_pool(dev->q, - "ppalist"); + dev->ppalist_pool = dev->ops->create_dma_pool(dev, "ppalist"); if (!dev->ppalist_pool) { pr_err("nvm: could not create ppa pool\n"); ret = -ENOMEM; diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index ce60254..52b513a 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -195,7 +195,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) } if (dev->ops->get_l2p_tbl) { - ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages, + ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages, gennvm_block_map, dev); if (ret) { pr_err("gennvm: could not read L2P table.\n"); @@ -346,7 +346,7 @@ static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) gennvm_generic_to_addr_mode(dev, rqd); rqd->dev = dev; - return dev->ops->submit_io(dev->q, rqd); + return dev->ops->submit_io(dev, rqd); } static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa, @@ -382,7 +382,7 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd) if (!dev->ops->set_bb_tbl) return; - if (dev->ops->set_bb_tbl(dev->q, rqd, 1)) + if (dev->ops->set_bb_tbl(dev, rqd, 1)) return; gennvm_addr_to_generic_mode(dev, rqd); @@ -450,7 +450,7 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk, gennvm_generic_to_addr_mode(dev, &rqd); - ret = dev->ops->erase_block(dev->q, &rqd); + ret = dev->ops->erase_block(dev, &rqd); if (plane_cnt) nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list); diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index cf1a4a5..134e4fa 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -1016,7 +1016,7 @@ static int rrpc_map_init(struct rrpc *rrpc) return 0; /* Bring up the mapping table from device */ - ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages, + ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages, rrpc_l2p_update, rrpc); if (ret) { pr_err("nvm: rrpc: could not read L2P table.\n"); diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 762c9a7..15f2acb 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -271,9 +271,9 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id) return 0; } -static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id) +static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id) { - struct nvme_ns *ns = q->queuedata; + struct nvme_ns *ns = nvmdev->q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_id *nvme_nvm_id; struct nvme_nvm_command c = {}; @@ -308,10 +308,10 @@ out: return ret; } -static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb, +static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb, nvm_l2p_update_fn *update_l2p, void *priv) { - struct nvme_ns *ns = q->queuedata; + struct nvme_ns *ns = nvmdev->q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_command c = {}; u32 len = queue_max_hw_sectors(dev->admin_q) << 9; @@ -415,10 +415,10 @@ out: return ret; } -static int nvme_nvm_set_bb_tbl(struct request_queue *q, struct nvm_rq *rqd, +static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct nvm_rq *rqd, int type) { - struct nvme_ns *ns = q->queuedata; + struct nvme_ns *ns = nvmdev->q->queuedata; struct nvme_dev *dev = ns->dev; struct nvme_nvm_command c = {}; int ret = 0; @@ -463,8 +463,9 @@ static void nvme_nvm_end_io(struct request *rq, int error) blk_mq_free_request(rq); } -static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) +static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) { + struct request_queue *q = dev->q; struct nvme_ns *ns = q->queuedata; struct request *rq; struct bio *bio = rqd->bio; @@ -502,8 +503,9 @@ static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) return 0; } -static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd) +static int nvme_nvm_erase_block(struct nvm_dev *dev, struct nvm_rq *rqd) { + struct request_queue *q = dev->q; struct nvme_ns *ns = q->queuedata; struct nvme_nvm_command c = {}; @@ -515,9 +517,9 @@ static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd) return nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0); } -static void *nvme_nvm_create_dma_pool(struct request_queue *q, char *name) +static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name) { - struct nvme_ns *ns = q->queuedata; + struct nvme_ns *ns = nvmdev->q->queuedata; struct nvme_dev *dev = ns->dev; return dma_pool_create(name, dev->dev, PAGE_SIZE, PAGE_SIZE, 0); @@ -530,7 +532,7 @@ static void nvme_nvm_destroy_dma_pool(void *pool) dma_pool_destroy(dma_pool); } -static void *nvme_nvm_dev_dma_alloc(struct request_queue *q, void *pool, +static void *nvme_nvm_dev_dma_alloc(struct nvm_dev *dev, void *pool, gfp_t mem_flags, dma_addr_t *dma_handler) { return dma_pool_alloc(pool, mem_flags, dma_handler); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 935ef38..034117b 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -183,17 +183,17 @@ struct nvm_block; typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *); typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *); -typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *); -typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32, +typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *); +typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32, nvm_l2p_update_fn *, void *); typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int, nvm_bb_update_fn *, void *); -typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int); -typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *); -typedef int (nvm_erase_blk_fn)(struct request_queue *, struct nvm_rq *); -typedef void *(nvm_create_dma_pool_fn)(struct request_queue *, char *); +typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int); +typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); +typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *); +typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *); typedef void (nvm_destroy_dma_pool_fn)(void *); -typedef void *(nvm_dev_dma_alloc_fn)(struct request_queue *, void *, gfp_t, +typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t, dma_addr_t *); typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t); -- cgit v0.10.2 From 762796bc9e5758df6c72253e4ec19657055cea1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:49 +0100 Subject: lightnvm: fix media mgr registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes two issues during media manager registration. 1. The ppa pool can be used at media manager registration. Allocate the ppa pool before that. 2. If a media manager can't be found, this should not lead to the device being unallocated. A media manager can be registered later, that can manage the device. Only warn if a media manager fails initialization. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 4a8d1fe..8f41b24 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -97,15 +97,47 @@ static struct nvmm_type *nvm_find_mgr_type(const char *name) return NULL; } +struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev) +{ + struct nvmm_type *mt; + int ret; + + lockdep_assert_held(&nvm_lock); + + list_for_each_entry(mt, &nvm_mgrs, list) { + ret = mt->register_mgr(dev); + if (ret < 0) { + pr_err("nvm: media mgr failed to init (%d) on dev %s\n", + ret, dev->name); + return NULL; /* initialization failed */ + } else if (ret > 0) + return mt; + } + + return NULL; +} + int nvm_register_mgr(struct nvmm_type *mt) { + struct nvm_dev *dev; int ret = 0; down_write(&nvm_lock); - if (nvm_find_mgr_type(mt->name)) + if (nvm_find_mgr_type(mt->name)) { ret = -EEXIST; - else + goto finish; + } else { list_add(&mt->list, &nvm_mgrs); + } + + /* try to register media mgr if any device have none configured */ + list_for_each_entry(dev, &nvm_devices, devices) { + if (dev->mt) + continue; + + dev->mt = nvm_init_mgr(dev); + } +finish: up_write(&nvm_lock); return ret; @@ -123,26 +155,6 @@ void nvm_unregister_mgr(struct nvmm_type *mt) } EXPORT_SYMBOL(nvm_unregister_mgr); -/* register with device with a supported manager */ -static int register_mgr(struct nvm_dev *dev) -{ - struct nvmm_type *mt; - int ret = 0; - - list_for_each_entry(mt, &nvm_mgrs, list) { - ret = mt->register_mgr(dev); - if (ret > 0) { - dev->mt = mt; - break; /* successfully initialized */ - } - } - - if (!ret) - pr_info("nvm: no compatible nvm manager found.\n"); - - return ret; -} - static struct nvm_dev *nvm_find_nvm_dev(const char *name) { struct nvm_dev *dev; @@ -271,14 +283,6 @@ static int nvm_init(struct nvm_dev *dev) goto err; } - down_write(&nvm_lock); - ret = register_mgr(dev); - up_write(&nvm_lock); - if (ret < 0) - goto err; - if (!ret) - return 0; - pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n", dev->name, dev->sec_per_pg, dev->nr_planes, dev->pgs_per_blk, dev->blks_per_lun, dev->nr_luns, @@ -334,7 +338,9 @@ int nvm_register(struct request_queue *q, char *disk_name, } } + /* register device with a supported media manager */ down_write(&nvm_lock); + dev->mt = nvm_init_mgr(dev); list_add(&dev->devices, &nvm_devices); up_write(&nvm_lock); @@ -379,19 +385,13 @@ static int nvm_create_target(struct nvm_dev *dev, struct nvm_tgt_type *tt; struct nvm_target *t; void *targetdata; - int ret = 0; - down_write(&nvm_lock); if (!dev->mt) { - ret = register_mgr(dev); - if (!ret) - ret = -ENODEV; - if (ret < 0) { - up_write(&nvm_lock); - return ret; - } + pr_info("nvm: device has no media manager registered.\n"); + return -ENODEV; } + down_write(&nvm_lock); tt = nvm_find_target_type(create->tgttype); if (!tt) { pr_err("nvm: target type %s not found\n", create->tgttype); -- cgit v0.10.2 From 008b74438269b368d57a14452afbc194f7f9ff2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:50 +0100 Subject: lightnvm: prevent gennvm module unload on use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the gennvm module has been initialized. It might be attached to one or several devices. In that case, the module is in use. Make sure that it can not be unloaded. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 52b513a..f434e89 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -219,6 +219,9 @@ static int gennvm_register(struct nvm_dev *dev) struct gen_nvm *gn; int ret; + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + gn = kzalloc(sizeof(struct gen_nvm), GFP_KERNEL); if (!gn) return -ENOMEM; @@ -242,12 +245,14 @@ static int gennvm_register(struct nvm_dev *dev) return 1; err: gennvm_free(dev); + module_put(THIS_MODULE); return ret; } static void gennvm_unregister(struct nvm_dev *dev) { gennvm_free(dev); + module_put(THIS_MODULE); } static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, -- cgit v0.10.2 From 4158624454db3756c1f1b3641f1ab4215e697936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Bj=C3=B8rling?= Date: Sun, 6 Dec 2015 11:25:51 +0100 Subject: lightnvm: do not compile in debugging by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LightNVM module exposes a debug interface when CONFIG_NVM_DEBUG is set. This interfaces takes a string to configure media managers and targets. Make sure this interface is only exposed when chosen deliberately. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig index a16bf56..85a3390 100644 --- a/drivers/lightnvm/Kconfig +++ b/drivers/lightnvm/Kconfig @@ -18,6 +18,7 @@ if NVM config NVM_DEBUG bool "Open-Channel SSD debugging support" + default n ---help--- Exposes a debug management interface to create/remove targets at: -- cgit v0.10.2 From 98fb754831e1d139f1151e968bdebb6eefb9b581 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 1 Dec 2015 13:20:40 +0100 Subject: arm64: update linker script to increased L1_CACHE_BYTES value Bring the linker script in line with the recent increase of L1_CACHE_BYTES to 128. Replace the hardcoded value of 64 with the symbolic constant. Signed-off-by: Ard Biesheuvel Acked-by: Mark Rutland [catalin.marinas@arm.com: fix up RW_DATA_SECTION as well] Signed-off-by: Catalin Marinas diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 1ee2c39..71426a7 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -140,7 +141,7 @@ SECTIONS ARM_EXIT_KEEP(EXIT_DATA) } - PERCPU_SECTION(64) + PERCPU_SECTION(L1_CACHE_BYTES) . = ALIGN(PAGE_SIZE); __init_end = .; @@ -158,7 +159,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); _data = .; _sdata = .; - RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) + RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) PECOFF_EDATA_PADDING _edata = .; -- cgit v0.10.2 From 756b9b37cfb2e3dc76b2e43a8c097402ac736e07 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 7 Dec 2015 12:52:23 -0800 Subject: SUNRPC: Fix callback channel The NFSv4.1 callback channel is currently broken because the receive message will keep shrinking because the backchannel receive buffer size never gets reset. The easiest solution to this problem is instead of changing the receive buffer, to rather adjust the copied request. Fixes: 38b7631fbe42 ("nfs4: limit callback decoding to received bytes") Cc: Benjamin Coddington Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index beac58b..646cdac 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -78,8 +78,7 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes) p = xdr_inline_decode(xdr, nbytes); if (unlikely(p == NULL)) - printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed " - "or truncated request.\n"); + printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n"); return p; } @@ -890,7 +889,6 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r struct cb_compound_hdr_arg hdr_arg = { 0 }; struct cb_compound_hdr_res hdr_res = { NULL }; struct xdr_stream xdr_in, xdr_out; - struct xdr_buf *rq_arg = &rqstp->rq_arg; __be32 *p, status; struct cb_process_state cps = { .drc_status = 0, @@ -902,8 +900,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r dprintk("%s: start\n", __func__); - rq_arg->len = rq_arg->head[0].iov_len + rq_arg->page_len; - xdr_init_decode(&xdr_in, rq_arg, rq_arg->head[0].iov_base); + xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); xdr_init_encode(&xdr_out, &rqstp->rq_res, p); diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 95f82d8..229956b 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -353,20 +353,12 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) { struct rpc_xprt *xprt = req->rq_xprt; struct svc_serv *bc_serv = xprt->bc_serv; - struct xdr_buf *rq_rcv_buf = &req->rq_rcv_buf; spin_lock(&xprt->bc_pa_lock); list_del(&req->rq_bc_pa_list); xprt_dec_alloc_count(xprt, 1); spin_unlock(&xprt->bc_pa_lock); - if (copied <= rq_rcv_buf->head[0].iov_len) { - rq_rcv_buf->head[0].iov_len = copied; - rq_rcv_buf->page_len = 0; - } else { - rq_rcv_buf->page_len = copied - rq_rcv_buf->head[0].iov_len; - } - req->rq_private_buf.len = copied; set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 7fccf96..cc98528 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1363,7 +1363,19 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); + + /* Adjust the argument buffer length */ rqstp->rq_arg.len = req->rq_private_buf.len; + if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { + rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; + rqstp->rq_arg.page_len = 0; + } else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len + + rqstp->rq_arg.page_len) + rqstp->rq_arg.page_len = rqstp->rq_arg.len - + rqstp->rq_arg.head[0].iov_len; + else + rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len + + rqstp->rq_arg.page_len; /* reset result send buffer "put" position */ resv->iov_len = 0; -- cgit v0.10.2 From 785f742223c03ec70f9dcf36b87f59e9df2067e0 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Mon, 30 Nov 2015 09:34:26 -0500 Subject: IB/qib: Fix qib_mr structure struct qib_mr requires the mr member be the last because struct qib_mregion contains a dynamic array at the end. The additions of members should have been placed before this structure as the comment noted. Failure to do so was causing random memory corruption. Reproducing this bug was easy to do by running the client and server of ib_write_bw -s 8 -n 5 on the same node. This BUG() was tripped in a slab debug kernel: kernel BUG at mm/slab.c:2572! Fixes: 38071a461f0a ("IB/qib: Support the new memory registration API") Reviewed-by: Mike Marciniszyn Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 2baf5ad..bc803f3 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -329,9 +329,9 @@ struct qib_sge { struct qib_mr { struct ib_mr ibmr; struct ib_umem *umem; - struct qib_mregion mr; /* must be last */ u64 *pages; u32 npages; + struct qib_mregion mr; /* must be last */ }; /* -- cgit v0.10.2 From 1d784b890c0101db2556b981e864c2282a3c1b02 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Tue, 1 Dec 2015 10:13:51 -0500 Subject: IB/core: Fix user mode post wr corruption Commit e622f2f4ad21 ("IB: split struct ib_send_wr") introduced a regression for HCAs whose user mode post sends go through ib_uverbs_post_send(). The code didn't account for the fact that the first sge is offset by an operation dependent length. The allocation did, but the pointer to the destination sge list is computed without that knowledge. The sge list copy_from_user() then corrupts fields in the work request Store the operation dependent length in a local variable and compute the sge list copy_from_user() destination using that length. Reviewed-by: Ira Weiny Signed-off-by: Mike Marciniszyn Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 94816ae..4cb8e9d 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2446,6 +2446,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, int i, sg_ind; int is_ud; ssize_t ret = -EINVAL; + size_t next_size; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; @@ -2490,7 +2491,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, goto out_put; } - ud = alloc_wr(sizeof(*ud), user_wr->num_sge); + next_size = sizeof(*ud); + ud = alloc_wr(next_size, user_wr->num_sge); if (!ud) { ret = -ENOMEM; goto out_put; @@ -2511,7 +2513,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, user_wr->opcode == IB_WR_RDMA_READ) { struct ib_rdma_wr *rdma; - rdma = alloc_wr(sizeof(*rdma), user_wr->num_sge); + next_size = sizeof(*rdma); + rdma = alloc_wr(next_size, user_wr->num_sge); if (!rdma) { ret = -ENOMEM; goto out_put; @@ -2525,7 +2528,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) { struct ib_atomic_wr *atomic; - atomic = alloc_wr(sizeof(*atomic), user_wr->num_sge); + next_size = sizeof(*atomic); + atomic = alloc_wr(next_size, user_wr->num_sge); if (!atomic) { ret = -ENOMEM; goto out_put; @@ -2540,7 +2544,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, } else if (user_wr->opcode == IB_WR_SEND || user_wr->opcode == IB_WR_SEND_WITH_IMM || user_wr->opcode == IB_WR_SEND_WITH_INV) { - next = alloc_wr(sizeof(*next), user_wr->num_sge); + next_size = sizeof(*next); + next = alloc_wr(next_size, user_wr->num_sge); if (!next) { ret = -ENOMEM; goto out_put; @@ -2572,7 +2577,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, if (next->num_sge) { next->sg_list = (void *) next + - ALIGN(sizeof *next, sizeof (struct ib_sge)); + ALIGN(next_size, sizeof(struct ib_sge)); if (copy_from_user(next->sg_list, buf + sizeof cmd + cmd.wr_count * cmd.wqe_size + -- cgit v0.10.2 From 57ab2512138205fe7836332fb4742441e53907ff Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Mon, 2 Nov 2015 12:13:14 -0500 Subject: IB/qib: Minor fixes to qib per SFF 8636 Minor errors found via code inspection during future development. SFF 8636 defines bit position 2 to hold the status indication of QSFP memory paging. The mask used to test for the value was incorrect and is fixed in this patch. Additionally, the dump function had a mismatch between the field being printed out and the field used to source the data which was fixed. Reviewed-by: Mitko Haralanov Reviewed-by: Mike Marciniszyn Reported-by: Easwar Hariharan Signed-off-by: Easwar Hariharan Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c index 5e27f76..4c7c3c8 100644 --- a/drivers/infiniband/hw/qib/qib_qsfp.c +++ b/drivers/infiniband/hw/qib/qib_qsfp.c @@ -292,7 +292,7 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp) qib_dev_porterr(ppd->dd, ppd->port, "QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]); - if ((peek[2] & 2) == 0) { + if ((peek[2] & 4) == 0) { /* * If cable is paged, rather than "flat memory", we need to * set the page to zero, Even if it already appears to be zero. @@ -538,7 +538,7 @@ int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len) sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", QSFP_DATE_LEN, cd.date); sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", - QSFP_LOT_LEN, cd.date); + QSFP_LOT_LEN, cd.lot); while (bidx < QSFP_DEFAULT_HDR_CNT) { int iidx; -- cgit v0.10.2 From d144da8c6f51f48ec39d891ea9dff80169c45f3b Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 2 Nov 2015 12:13:25 -0500 Subject: IB/core: use RCU for uverbs id lookup The current implementation gets a spin_lock, and at any scale with qib and hfi1 post send, the lock contention grows exponentially with the number of QPs. idr_find() is RCU compatibile, so read doesn't need the lock. Change to use rcu_read_lock() and rcu_read_unlock() in __idr_get_uobj(). kfree_rcu() is used to insure a grace period between the idr removal and actual free. Reviewed-by: Ira Weiny Signed-off-by: Mike Marciniszyn Reviewed-By: Jason Gunthorpe Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 4cb8e9d..1c02dea 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -62,9 +62,11 @@ static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" }; * The ib_uobject locking scheme is as follows: * * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it - * needs to be held during all idr operations. When an object is + * needs to be held during all idr write operations. When an object is * looked up, a reference must be taken on the object's kref before - * dropping this lock. + * dropping this lock. For read operations, the rcu_read_lock() + * and rcu_write_lock() but similarly the kref reference is grabbed + * before the rcu_read_unlock(). * * - Each object also has an rwsem. This rwsem must be held for * reading while an operation that uses the object is performed. @@ -96,7 +98,7 @@ static void init_uobj(struct ib_uobject *uobj, u64 user_handle, static void release_uobj(struct kref *kref) { - kfree(container_of(kref, struct ib_uobject, ref)); + kfree_rcu(container_of(kref, struct ib_uobject, ref), rcu); } static void put_uobj(struct ib_uobject *uobj) @@ -145,7 +147,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, { struct ib_uobject *uobj; - spin_lock(&ib_uverbs_idr_lock); + rcu_read_lock(); uobj = idr_find(idr, id); if (uobj) { if (uobj->context == context) @@ -153,7 +155,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, else uobj = NULL; } - spin_unlock(&ib_uverbs_idr_lock); + rcu_read_unlock(); return uobj; } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 9a68a19..120da1d 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1271,6 +1271,7 @@ struct ib_uobject { int id; /* index into kernel idr */ struct kref ref; struct rw_semaphore mutex; /* protects .live */ + struct rcu_head rcu; /* kfree_rcu() overhead */ int live; }; -- cgit v0.10.2 From 2c63d1072ad7cf1059333ef5cfa06075bead4a39 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Nov 2015 17:41:36 +0100 Subject: IB/iser: use sector_div instead of do_div do_div is the wrong way to divide a sector_t, as it is less efficient when sector_t is 32-bit wide. With the upcoming do_div optimizations, the kernel starts warning about this: drivers/infiniband/ulp/iser/iser_verbs.c:1296:4: note: in expansion of macro 'do_div' include/asm-generic/div64.h:224:22: warning: passing argument 1 of '__div64_32' from incompatible pointer type This changes the code to use sector_div instead, which always produces optimal code. Signed-off-by: Arnd Bergmann Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index a930702..42f4da6 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -1293,7 +1293,7 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) { sector_t sector_off = mr_status.sig_err.sig_err_offset; - do_div(sector_off, sector_size + 8); + sector_div(sector_off, sector_size + 8); *sector = scsi_get_lba(iser_task->sc) + sector_off; pr_err("PI error found type %d at sector %llx " -- cgit v0.10.2 From 3ebd2fd0d0119a5ac7906bf17be637b527f63d31 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Fri, 30 Oct 2015 08:23:45 -0400 Subject: IB/sa: Put netlink request into the request list before sending It was found by Saurabh Sengar that the netlink code tried to allocate memory with GFP_KERNEL while holding a spinlock. While it is possible to fix the issue by replacing GFP_KERNEL with GFP_ATOMIC, it is better to get rid of the spinlock while sending the packet. However, in order to protect against a race condition that a quick response may be received before the request is put on the request list, we need to put the request on the list first. Signed-off-by: Kaike Wan Reviewed-by: Jason Gunthorpe Reviewed-by: Ira Weiny Reported-by: Saurabh Sengar Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 2aba774..a95a32b 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -512,7 +512,7 @@ static int ib_nl_get_path_rec_attrs_len(ib_sa_comp_mask comp_mask) return len; } -static int ib_nl_send_msg(struct ib_sa_query *query) +static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask) { struct sk_buff *skb = NULL; struct nlmsghdr *nlh; @@ -526,7 +526,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query) if (len <= 0) return -EMSGSIZE; - skb = nlmsg_new(len, GFP_KERNEL); + skb = nlmsg_new(len, gfp_mask); if (!skb) return -ENOMEM; @@ -544,7 +544,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query) /* Repair the nlmsg header length */ nlmsg_end(skb, nlh); - ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL); + ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, gfp_mask); if (!ret) ret = len; else @@ -553,7 +553,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query) return ret; } -static int ib_nl_make_request(struct ib_sa_query *query) +static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask) { unsigned long flags; unsigned long delay; @@ -562,25 +562,27 @@ static int ib_nl_make_request(struct ib_sa_query *query) INIT_LIST_HEAD(&query->list); query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq); + /* Put the request on the list first.*/ spin_lock_irqsave(&ib_nl_request_lock, flags); - ret = ib_nl_send_msg(query); - if (ret <= 0) { - ret = -EIO; - goto request_out; - } else { - ret = 0; - } - delay = msecs_to_jiffies(sa_local_svc_timeout_ms); query->timeout = delay + jiffies; list_add_tail(&query->list, &ib_nl_request_list); /* Start the timeout if this is the only request */ if (ib_nl_request_list.next == &query->list) queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay); - -request_out: spin_unlock_irqrestore(&ib_nl_request_lock, flags); + ret = ib_nl_send_msg(query, gfp_mask); + if (ret <= 0) { + ret = -EIO; + /* Remove the request */ + spin_lock_irqsave(&ib_nl_request_lock, flags); + list_del(&query->list); + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + } else { + ret = 0; + } + return ret; } @@ -1108,7 +1110,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) if (query->flags & IB_SA_ENABLE_LOCAL_SERVICE) { if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) { - if (!ib_nl_make_request(query)) + if (!ib_nl_make_request(query, gfp_mask)) return id; } ib_sa_disable_local_svc(query); -- cgit v0.10.2 From 4d59ad2995e4128c06d889f9e223099b1f19548e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 1 Dec 2015 10:17:32 -0800 Subject: IB/srp: Fix a memory leak If srp_connect_ch() returns a positive value then that is considered by its caller as a connection failure but this does not result in a scsi_host_put() call and additionally causes the srp_create_target() function to return a positive value while it should return a negative value. Avoid all this confusion and additionally fix a memory leak by ensuring that srp_connect_ch() always returns a value that is <= 0. This patch avoids that a rejected login triggers the following memory leak: unreferenced object 0xffff88021b24a220 (size 8): comm "srp_daemon", pid 56421, jiffies 4295006762 (age 4240.750s) hex dump (first 8 bytes): 68 6f 73 74 35 38 00 a5 host58.. backtrace: [] kmemleak_alloc+0x7a/0xc0 [] __kmalloc_track_caller+0xfe/0x160 [] kvasprintf+0x5b/0x90 [] kvasprintf_const+0x8d/0xb0 [] kobject_set_name_vargs+0x3c/0xa0 [] dev_set_name+0x3c/0x40 [] scsi_host_alloc+0x327/0x4b0 [] srp_create_target+0x4e/0x8a0 [ib_srp] [] dev_attr_store+0x1b/0x20 [] sysfs_kf_write+0x4a/0x60 [] kernfs_fop_write+0x14e/0x180 [] __vfs_write+0x2f/0xf0 [] vfs_write+0xa4/0x100 [] SyS_write+0x54/0xc0 [] entry_SYSCALL_64_fastpath+0x12/0x6f Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Cc: Sebastian Parschauer Cc: stable Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 9909022..a074dad 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -994,16 +994,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich) ret = srp_lookup_path(ch); if (ret) - return ret; + goto out; while (1) { init_completion(&ch->done); ret = srp_send_req(ch, multich); if (ret) - return ret; + goto out; ret = wait_for_completion_interruptible(&ch->done); if (ret < 0) - return ret; + goto out; /* * The CM event handling code will set status to @@ -1011,15 +1011,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich) * back, or SRP_DLID_REDIRECT if we get a lid/qp * redirect REJ back. */ - switch (ch->status) { + ret = ch->status; + switch (ret) { case 0: ch->connected = true; - return 0; + goto out; case SRP_PORT_REDIRECT: ret = srp_lookup_path(ch); if (ret) - return ret; + goto out; break; case SRP_DLID_REDIRECT: @@ -1028,13 +1029,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich) case SRP_STALE_CONN: shost_printk(KERN_ERR, target->scsi_host, PFX "giving up on stale connection\n"); - ch->status = -ECONNRESET; - return ch->status; + ret = -ECONNRESET; + goto out; default: - return ch->status; + goto out; } } + +out: + return ret <= 0 ? ret : -ENODEV; } static int srp_inv_rkey(struct srp_rdma_ch *ch, u32 rkey) -- cgit v0.10.2 From 09c0c0bea500a9ad362589990ee316c9b2482f44 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Tue, 1 Dec 2015 10:18:03 -0800 Subject: IB/srp: Fix possible send queue overflow When using work request based memory registration (fast_reg) we must reserve SQ entries for registration and invalidation in addition to send operations. Each IO consumes 3 SQ entries (registration, send, invalidation) so we need to allocate 3x larger send-queue instead of 2x. Signed-off-by: Sagi Grimberg CC: Stable Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index a074dad..c7a95d2 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -488,7 +488,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) struct ib_qp *qp; struct ib_fmr_pool *fmr_pool = NULL; struct srp_fr_pool *fr_pool = NULL; - const int m = 1 + dev->use_fast_reg; + const int m = dev->use_fast_reg ? 3 : 1; struct ib_cq_init_attr cq_attr = {}; int ret; -- cgit v0.10.2 From fc925518aa04ee9f03c4e0cadd9c59f1ef48bcfa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 1 Dec 2015 10:18:30 -0800 Subject: IB/srp: Initialize dma_length in srp_map_idb Without this sg_dma_len will return 0 on architectures tha have the dma_length field. Fixes: commit f7f7aab1a5c0 ("IB/srp: Convert to new registration API") Signed-off-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index c7a95d2..72fac20 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1524,6 +1524,9 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, state.sg_nents = 1; sg_set_buf(idb_sg, req->indirect_desc, idb_len); idb_sg->dma_address = req->indirect_dma_addr; /* hack! */ +#ifdef CONFIG_NEED_SG_DMA_LENGTH + idb_sg->dma_length = idb_sg->length; /* hack^2 */ +#endif ret = srp_map_finish_fr(&state, ch); if (ret < 0) return ret; -- cgit v0.10.2 From a745f4f410082fedc17be75e10e4098f300943db Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 1 Dec 2015 10:18:47 -0800 Subject: IB/srp: Fix indirect data buffer rkey endianness Detected by sparse. Fixes: commit 330179f2fa93 ("IB/srp: Register the indirect data buffer descriptor") Signed-off-by: Bart Van Assche Cc: stable # v4.3+ Cc: Sagi Grimberg Cc: Christoph Hellwig Cc: Sebastian Parschauer Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 72fac20..fac1423 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1662,7 +1662,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, return ret; req->nmdesc++; } else { - idb_rkey = target->global_mr->rkey; + idb_rkey = cpu_to_be32(target->global_mr->rkey); } indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); -- cgit v0.10.2 From 57b0be9c0fb0ba3a35683c6ce21db7162d6758c5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 1 Dec 2015 10:19:38 -0800 Subject: IB/srp: Fix srp_map_sg_fr() After dma_map_sg() has been called the return value of that function must be used as the number of elements in the scatterlist instead of scsi_sg_count(). Fixes: commit f7f7aab1a5c0 ("IB/srp: Convert to new registration API") Reported-by: Christoph Hellwig Signed-off-by: Bart Van Assche Cc: stable # v4.4+ Cc: Sagi Grimberg Cc: Sebastian Parschauer Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index fac1423..3db9a65 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1313,7 +1313,7 @@ reset_state: } static int srp_map_finish_fr(struct srp_map_state *state, - struct srp_rdma_ch *ch) + struct srp_rdma_ch *ch, int sg_nents) { struct srp_target_port *target = ch->target; struct srp_device *dev = target->srp_host->srp_dev; @@ -1328,10 +1328,10 @@ static int srp_map_finish_fr(struct srp_map_state *state, WARN_ON_ONCE(!dev->use_fast_reg); - if (state->sg_nents == 0) + if (sg_nents == 0) return 0; - if (state->sg_nents == 1 && target->global_mr) { + if (sg_nents == 1 && target->global_mr) { srp_map_desc(state, sg_dma_address(state->sg), sg_dma_len(state->sg), target->global_mr->rkey); @@ -1345,8 +1345,7 @@ static int srp_map_finish_fr(struct srp_map_state *state, rkey = ib_inc_rkey(desc->mr->rkey); ib_update_fast_reg_key(desc->mr, rkey); - n = ib_map_mr_sg(desc->mr, state->sg, state->sg_nents, - dev->mr_page_size); + n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, dev->mr_page_size); if (unlikely(n < 0)) return n; @@ -1452,16 +1451,15 @@ static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch, state->fr.next = req->fr_list; state->fr.end = req->fr_list + ch->target->cmd_sg_cnt; state->sg = scat; - state->sg_nents = scsi_sg_count(req->scmnd); - while (state->sg_nents) { + while (count) { int i, n; - n = srp_map_finish_fr(state, ch); + n = srp_map_finish_fr(state, ch, count); if (unlikely(n < 0)) return n; - state->sg_nents -= n; + count -= n; for (i = 0; i < n; i++) state->sg = sg_next(state->sg); } @@ -1521,13 +1519,12 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, if (dev->use_fast_reg) { state.sg = idb_sg; - state.sg_nents = 1; sg_set_buf(idb_sg, req->indirect_desc, idb_len); idb_sg->dma_address = req->indirect_dma_addr; /* hack! */ #ifdef CONFIG_NEED_SG_DMA_LENGTH idb_sg->dma_length = idb_sg->length; /* hack^2 */ #endif - ret = srp_map_finish_fr(&state, ch); + ret = srp_map_finish_fr(&state, ch, 1); if (ret < 0) return ret; } else if (dev->use_fmr) { diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 87a2a91..f6af531 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -300,10 +300,7 @@ struct srp_map_state { dma_addr_t base_dma_addr; u32 dma_len; u32 total_len; - union { - unsigned int npages; - int sg_nents; - }; + unsigned int npages; unsigned int nmdesc; unsigned int ndesc; }; -- cgit v0.10.2 From 8f5ba10ed40a9d3ffe84854984227d011a7428bd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 3 Dec 2015 16:04:17 -0800 Subject: IB core: Fix ib_sg_to_pages() On 12/03/2015 01:18 AM, Christoph Hellwig wrote: > The patch looks good to me, but while we touch this area, how about > throwing in a few cosmetic fixes as well? How about the patch below ? In that version of the ib_sg_to_pages() fix these concerns have been addressed and additionally to more bugs have been fixed. ------------ [PATCH] IB core: Fix ib_sg_to_pages() Fix the code for detecting gaps. A gap occurs not only if the second or later scatterlist element is not aligned but also if any scatterlist element other than the last does not end at a page boundary. In the code for coalescing contiguous elements, ensure that mr->length is correct and that last_page_addr is up-to-date. Ensure that this function returns a negative error code instead of zero if the first set_page() call fails. Fixes: commit 4c67e2bfc8b7 ("IB/core: Introduce new fast registration API") Reported-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 043a60e..545906d 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1516,7 +1516,7 @@ EXPORT_SYMBOL(ib_map_mr_sg); * @sg_nents: number of entries in sg * @set_page: driver page assignment function pointer * - * Core service helper for drivers to covert the largest + * Core service helper for drivers to convert the largest * prefix of given sg list to a page vector. The sg list * prefix converted is the prefix that meet the requirements * of ib_map_mr_sg. @@ -1533,7 +1533,7 @@ int ib_sg_to_pages(struct ib_mr *mr, u64 last_end_dma_addr = 0, last_page_addr = 0; unsigned int last_page_off = 0; u64 page_mask = ~((u64)mr->page_size - 1); - int i; + int i, ret; mr->iova = sg_dma_address(&sgl[0]); mr->length = 0; @@ -1544,27 +1544,29 @@ int ib_sg_to_pages(struct ib_mr *mr, u64 end_dma_addr = dma_addr + dma_len; u64 page_addr = dma_addr & page_mask; - if (i && page_addr != dma_addr) { - if (last_end_dma_addr != dma_addr) { - /* gap */ - goto done; - - } else if (last_page_off + dma_len <= mr->page_size) { - /* chunk this fragment with the last */ - mr->length += dma_len; - last_end_dma_addr += dma_len; - last_page_off += dma_len; - continue; - } else { - /* map starting from the next page */ - page_addr = last_page_addr + mr->page_size; - dma_len -= mr->page_size - last_page_off; - } + /* + * For the second and later elements, check whether either the + * end of element i-1 or the start of element i is not aligned + * on a page boundary. + */ + if (i && (last_page_off != 0 || page_addr != dma_addr)) { + /* Stop mapping if there is a gap. */ + if (last_end_dma_addr != dma_addr) + break; + + /* + * Coalesce this element with the last. If it is small + * enough just update mr->length. Otherwise start + * mapping from the next page. + */ + goto next_page; } do { - if (unlikely(set_page(mr, page_addr))) - goto done; + ret = set_page(mr, page_addr); + if (unlikely(ret < 0)) + return i ? : ret; +next_page: page_addr += mr->page_size; } while (page_addr < end_dma_addr); @@ -1574,7 +1576,6 @@ int ib_sg_to_pages(struct ib_mr *mr, last_page_off = end_dma_addr & ~page_mask; } -done: return i; } EXPORT_SYMBOL(ib_sg_to_pages); -- cgit v0.10.2 From 25642e1459ace29f6ce5a171efc8b7b59a52a2d4 Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Mon, 7 Dec 2015 11:28:28 +1100 Subject: powerpc/opal-irqchip: Fix double endian conversion The OPAL event calls return a mask of events that are active in big endian format. This is checked when unmasking the events in the irqchip by comparison with a cached value. The cached value was stored in big endian format but should've been converted to CPU endian first. This bug leads to OPAL event delivery being delayed or dropped on some systems. Symptoms may include a non-functional console. The bug is fixed by calling opal_handle_events(...) instead of duplicating code in opal_event_unmask(...). Fixes: 9f0fd0499d30 ("powerpc/powernv: Add a virtual irqchip for opal events") Cc: stable@vger.kernel.org # v4.2+ Reported-by: Douglas L Lehr Signed-off-by: Alistair Popple Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index 6ccfb6c..0a00e2a 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -43,11 +43,34 @@ static unsigned int opal_irq_count; static unsigned int *opal_irqs; static void opal_handle_irq_work(struct irq_work *work); -static __be64 last_outstanding_events; +static u64 last_outstanding_events; static struct irq_work opal_event_irq_work = { .func = opal_handle_irq_work, }; +void opal_handle_events(uint64_t events) +{ + int virq, hwirq = 0; + u64 mask = opal_event_irqchip.mask; + + if (!in_irq() && (events & mask)) { + last_outstanding_events = events; + irq_work_queue(&opal_event_irq_work); + return; + } + + while (events & mask) { + hwirq = fls64(events) - 1; + if (BIT_ULL(hwirq) & mask) { + virq = irq_find_mapping(opal_event_irqchip.domain, + hwirq); + if (virq) + generic_handle_irq(virq); + } + events &= ~BIT_ULL(hwirq); + } +} + static void opal_event_mask(struct irq_data *d) { clear_bit(d->hwirq, &opal_event_irqchip.mask); @@ -55,12 +78,12 @@ static void opal_event_mask(struct irq_data *d) static void opal_event_unmask(struct irq_data *d) { + __be64 events; + set_bit(d->hwirq, &opal_event_irqchip.mask); - opal_poll_events(&last_outstanding_events); - if (last_outstanding_events & opal_event_irqchip.mask) - /* Need to retrigger the interrupt */ - irq_work_queue(&opal_event_irq_work); + opal_poll_events(&events); + opal_handle_events(be64_to_cpu(events)); } static int opal_event_set_type(struct irq_data *d, unsigned int flow_type) @@ -96,29 +119,6 @@ static int opal_event_map(struct irq_domain *d, unsigned int irq, return 0; } -void opal_handle_events(uint64_t events) -{ - int virq, hwirq = 0; - u64 mask = opal_event_irqchip.mask; - - if (!in_irq() && (events & mask)) { - last_outstanding_events = events; - irq_work_queue(&opal_event_irq_work); - return; - } - - while (events & mask) { - hwirq = fls64(events) - 1; - if (BIT_ULL(hwirq) & mask) { - virq = irq_find_mapping(opal_event_irqchip.domain, - hwirq); - if (virq) - generic_handle_irq(virq); - } - events &= ~BIT_ULL(hwirq); - } -} - static irqreturn_t opal_interrupt(int irq, void *data) { __be64 events; @@ -131,7 +131,7 @@ static irqreturn_t opal_interrupt(int irq, void *data) static void opal_handle_irq_work(struct irq_work *work) { - opal_handle_events(be64_to_cpu(last_outstanding_events)); + opal_handle_events(last_outstanding_events); } static int opal_event_match(struct irq_domain *h, struct device_node *node, -- cgit v0.10.2 From e606e035cc7293a3824527d97359711fdda00663 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Mon, 7 Dec 2015 14:34:40 +0100 Subject: cxl: Set endianess of kernel contexts A process element (defined in CAIA) keeps track of the endianess of contexts through the Little Endian (LE) bit of the State Register. It is currently set for user contexts, but was somehow forgotten for kernel contexts, so this patch fixes it. It could lead to erratic behavior from an AFU when the context is attached through the kernel API. Fixes: 2f663527bd6a ("cxl: Configure PSL for kernel contexts and merge code") Cc: stable@vger.kernel.org # 4.2+ Signed-off-by: Frederic Barrat Suggested-by: Michael Neuling Signed-off-by: Michael Ellerman diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index d2e75c8..f409097 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -497,6 +497,7 @@ static u64 calculate_sr(struct cxl_context *ctx) { u64 sr = 0; + set_endian(sr); if (ctx->master) sr |= CXL_PSL_SR_An_MP; if (mfspr(SPRN_LPCR) & LPCR_TC) @@ -506,7 +507,6 @@ static u64 calculate_sr(struct cxl_context *ctx) sr |= CXL_PSL_SR_An_HV; } else { sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R; - set_endian(sr); sr &= ~(CXL_PSL_SR_An_HV); if (!test_tsk_thread_flag(current, TIF_32BIT)) sr |= CXL_PSL_SR_An_SF; -- cgit v0.10.2 From 23adc192b862b69ad80a40bd5206e337f41264ac Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 8 Dec 2015 12:27:18 +0800 Subject: ALSA: hda - Fixing speaker noise on the two latest thinkpad models We have two latest thinkpad laptop models which are all based on the Intel skylake platforms, and all of them have the codec alc293 on them. When the machines boot to the desktop, an greeting dialogue shows up with the notification sound. But on these two models, there is noise with the notification sound. We have 3 SKUs for each of the models, all of them have this problem. So far, this problem is only specific to these two thinkpad models, we did not find this problem on the old thinkpad models with the codec alc293 or alc292. A workaround for this problem is disabling the aamix. Cc: stable@vger.kernel.org BugLink: https://bugs.launchpad.net/bugs/1523517 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ebc5362..49b1d36 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4596,6 +4596,7 @@ enum { ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC275_FIXUP_DELL_XPS, ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, + ALC293_FIXUP_LENOVO_SPK_NOISE, }; static const struct hda_fixup alc269_fixups[] = { @@ -5187,6 +5188,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE }, + [ALC293_FIXUP_LENOVO_SPK_NOISE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5334,6 +5341,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -5343,6 +5351,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), -- cgit v0.10.2 From 8fbf9d92a7bc4cadd3a0139698cf17031dfcdfca Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Nov 2015 19:45:16 +0100 Subject: drm/vmwgfx: Implement the cursor_set2 callback v2 Fixes native drm clients like Fedora 23 Wayland which now appears to be able to use cursor hotspots without strange cursor offsets. Also fixes a couple of ignored error paths. Since the core drm cursor hotspot is incompatible with the legacy vmwgfx hotspot (the core drm hotspot is reset when the drm_mode_cursor ioctl is used), we need to keep track of both and add them when the device hotspot is set. We assume that either is always zero. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index a09cf85..c49812b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1233,6 +1233,7 @@ static void vmw_master_drop(struct drm_device *dev, vmw_fp->locked_master = drm_master_get(file_priv->master); ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile); + vmw_kms_legacy_hotspot_clear(dev_priv); if (unlikely((ret != 0))) { DRM_ERROR("Unable to lock TTM at VT switch.\n"); drm_master_put(&vmw_fp->locked_master); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a8ae9df..469cdd5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -925,6 +925,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, uint32_t num_clips); int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv); int vmw_dumb_create(struct drm_file *file_priv, struct drm_device *dev, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9fcd7f8..9b4bb9e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -133,13 +133,19 @@ void vmw_cursor_update_position(struct vmw_private *dev_priv, vmw_mmio_write(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT); } -int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, - uint32_t handle, uint32_t width, uint32_t height) + +/* + * vmw_du_crtc_cursor_set2 - Driver cursor_set2 callback. + */ +int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height, + int32_t hot_x, int32_t hot_y) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_surface *surface = NULL; struct vmw_dma_buffer *dmabuf = NULL; + s32 hotspot_x, hotspot_y; int ret; /* @@ -151,6 +157,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, */ drm_modeset_unlock_crtc(crtc); drm_modeset_lock_all(dev_priv->dev); + hotspot_x = hot_x + du->hotspot_x; + hotspot_y = hot_y + du->hotspot_y; /* A lot of the code assumes this */ if (handle && (width != 64 || height != 64)) { @@ -187,31 +195,34 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, vmw_dmabuf_unreference(&du->cursor_dmabuf); /* setup new image */ + ret = 0; if (surface) { /* vmw_user_surface_lookup takes one reference */ du->cursor_surface = surface; du->cursor_surface->snooper.crtc = crtc; du->cursor_age = du->cursor_surface->snooper.age; - vmw_cursor_update_image(dev_priv, surface->snooper.image, - 64, 64, du->hotspot_x, du->hotspot_y); + ret = vmw_cursor_update_image(dev_priv, surface->snooper.image, + 64, 64, hotspot_x, hotspot_y); } else if (dmabuf) { /* vmw_user_surface_lookup takes one reference */ du->cursor_dmabuf = dmabuf; ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height, - du->hotspot_x, du->hotspot_y); + hotspot_x, hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); - ret = 0; goto out; } - vmw_cursor_update_position(dev_priv, true, - du->cursor_x + du->hotspot_x, - du->cursor_y + du->hotspot_y); + if (!ret) { + vmw_cursor_update_position(dev_priv, true, + du->cursor_x + hotspot_x, + du->cursor_y + hotspot_y); + du->core_hotspot_x = hot_x; + du->core_hotspot_y = hot_y; + } - ret = 0; out: drm_modeset_unlock_all(dev_priv->dev); drm_modeset_lock_crtc(crtc, crtc->cursor); @@ -239,8 +250,10 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) drm_modeset_lock_all(dev_priv->dev); vmw_cursor_update_position(dev_priv, shown, - du->cursor_x + du->hotspot_x, - du->cursor_y + du->hotspot_y); + du->cursor_x + du->hotspot_x + + du->core_hotspot_x, + du->cursor_y + du->hotspot_y + + du->core_hotspot_y); drm_modeset_unlock_all(dev_priv->dev); drm_modeset_lock_crtc(crtc, crtc->cursor); @@ -334,6 +347,29 @@ err_unreserve: ttm_bo_unreserve(bo); } +/** + * vmw_kms_legacy_hotspot_clear - Clear legacy hotspots + * + * @dev_priv: Pointer to the device private struct. + * + * Clears all legacy hotspots. + */ +void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct vmw_display_unit *du; + struct drm_crtc *crtc; + + drm_modeset_lock_all(dev); + drm_for_each_crtc(crtc, dev) { + du = vmw_crtc_to_du(crtc); + + du->hotspot_x = 0; + du->hotspot_y = 0; + } + drm_modeset_unlock_all(dev); +} + void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -351,7 +387,9 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) du->cursor_age = du->cursor_surface->snooper.age; vmw_cursor_update_image(dev_priv, du->cursor_surface->snooper.image, - 64, 64, du->hotspot_x, du->hotspot_y); + 64, 64, + du->hotspot_x + du->core_hotspot_x, + du->hotspot_y + du->core_hotspot_y); } mutex_unlock(&dev->mode_config.mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 782df7c..edd8150 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -159,6 +159,8 @@ struct vmw_display_unit { int hotspot_x; int hotspot_y; + s32 core_hotspot_x; + s32 core_hotspot_y; unsigned unit; @@ -193,8 +195,9 @@ void vmw_du_crtc_restore(struct drm_crtc *crtc); void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, uint32_t size); -int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, - uint32_t handle, uint32_t width, uint32_t height); +int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height, + int32_t hot_x, int32_t hot_y); int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); int vmw_du_connector_dpms(struct drm_connector *connector, int mode); void vmw_du_connector_save(struct drm_connector *connector); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index bb63e4d..52caecb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -297,7 +297,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) static struct drm_crtc_funcs vmw_legacy_crtc_funcs = { .save = vmw_du_crtc_save, .restore = vmw_du_crtc_restore, - .cursor_set = vmw_du_crtc_cursor_set, + .cursor_set2 = vmw_du_crtc_cursor_set2, .cursor_move = vmw_du_crtc_cursor_move, .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_ldu_crtc_destroy, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index b96d1ab..13926ff 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -533,7 +533,7 @@ out_no_fence: static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .save = vmw_du_crtc_save, .restore = vmw_du_crtc_restore, - .cursor_set = vmw_du_crtc_cursor_set, + .cursor_set2 = vmw_du_crtc_cursor_set2, .cursor_move = vmw_du_crtc_cursor_move, .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_sou_crtc_destroy, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index b1fc1c0..f823fc3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1043,7 +1043,7 @@ out_finish: static struct drm_crtc_funcs vmw_stdu_crtc_funcs = { .save = vmw_du_crtc_save, .restore = vmw_du_crtc_restore, - .cursor_set = vmw_du_crtc_cursor_set, + .cursor_set2 = vmw_du_crtc_cursor_set2, .cursor_move = vmw_du_crtc_cursor_move, .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_stdu_crtc_destroy, -- cgit v0.10.2 From 928c75fbeb6b62edbdff7c52ee1e9a3591faee4f Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Tue, 24 Nov 2015 15:34:09 +0100 Subject: usb: phy: msm: fix a possible NULL dereference of_match_device could return NULL, and so cause a NULL pointer dereference later. Even if the probability of this case is very low, fixing it made static analyzers happy. Solving this with of_device_get_match_data made also code simplier. Reported-by: coverity (CID 1324133) Signed-off-by: LABBE Corentin Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 80eb991..0d19a6d 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1506,7 +1506,6 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) { struct msm_otg_platform_data *pdata; struct extcon_dev *ext_id, *ext_vbus; - const struct of_device_id *id; struct device_node *node = pdev->dev.of_node; struct property *prop; int len, ret, words; @@ -1518,8 +1517,9 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->pdata = pdata; - id = of_match_device(msm_otg_dt_match, &pdev->dev); - pdata->phy_type = (enum msm_usb_phy_type) id->data; + pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev); + if (!pdata->phy_type) + return 1; motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); if (IS_ERR(motg->link_rst)) -- cgit v0.10.2 From 4d05591094979d24a0e728f246589963c40102e9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 7 Dec 2015 21:23:15 -0800 Subject: usb: musb: core: Fix pm runtime for deferred probe If musb_init_controller fails at musb_platform_init, we have already called pm_runtime_irq_safe for musb and that causes the pm runtime count to be enabled for parent before the parent has completed initialization. This causes pm to stop working as on unload nothing gets idled. This issue can be reproduced at least with: # modprobe omap2430 HS USB OTG: no transceiver configured musb-hdrc musb-hdrc.0.auto: musb_init_controller failed with status -517 # modprobe phy-twl4030-usb # rmmod omap2430 And after the steps above omap2430 will block deeper idle states on omap3. To fix this, let's not enable pm runtime until we need to and the parent has been initialized. Note that this does not fix the issue of PM being broken for musb during runtime. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 18cfc0a..3c07ffd 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2017,7 +2017,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* We need musb_read/write functions initialized for PM */ pm_runtime_use_autosuspend(musb->controller); pm_runtime_set_autosuspend_delay(musb->controller, 200); - pm_runtime_irq_safe(musb->controller); pm_runtime_enable(musb->controller); /* The musb_platform_init() call: @@ -2218,6 +2217,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_put(musb->controller); + /* + * For why this is currently needed, see commit 3e43a0725637 + * ("usb: musb: core: add pm_runtime_irq_safe()") + */ + pm_runtime_irq_safe(musb->controller); + return 0; fail5: -- cgit v0.10.2 From 27681abc429554622a188a3a0b213fb1c20040f7 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Sat, 28 Nov 2015 18:35:44 +0100 Subject: usb: gadget: uvc: fix permissions of configfs attributes 76e0da3 "usb-gadget/uvc: use per-attribute show and store methods" removed write permission for writeable attributes. Correct attribute permissions. Fixes: 76e0da3 "usb-gadget/uvc: use per-attribute show and store methods" Reviewed-by: Christoph Hellwig Reviewed-by: Laurent Pinchart Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 289ebca..ad8c9b0 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -20,7 +20,7 @@ #define UVC_ATTR(prefix, cname, aname) \ static struct configfs_attribute prefix##attr_##cname = { \ .ca_name = __stringify(aname), \ - .ca_mode = S_IRUGO, \ + .ca_mode = S_IRUGO | S_IWUGO, \ .ca_owner = THIS_MODULE, \ .show = prefix##cname##_show, \ .store = prefix##cname##_store, \ -- cgit v0.10.2 From f8062386671a596ca7022c61727a14a25679a0a1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 5 Dec 2015 16:13:53 -0800 Subject: of/fdt: Add mutex protection for calls to __unflatten_device_tree() __unflatten_device_tree() calls unflatten_dt_node(), which declares a static variable. It is therefore not reentrant. One of the callers of __unflatten_device_tree(), unflatten_device_tree(), is only called once during early initialization and does not need to be protected. The other caller, of_fdt_unflatten_tree(), can be called at any time, possibly multiple times in parallel. This can happen, for example, if multiple devicetree overlays have to be loaded and installed. Without this protection, errors such as the following may be seen. kernel: End of tree marker overwritten: e6a3a458 kernel: find_target_node: Failed to find target-indirect node at /fragment@0 kernel: __of_overlay_create: of_build_overlay_info() failed for tree@/ Add a mutex to of_fdt_unflatten_tree() to make the call reentrant. Cc: Pantelis Antoniou Signed-off-by: Guenter Roeck Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Rob Herring diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 1bbe3a9..655f79d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -436,6 +437,8 @@ static void *kernel_tree_alloc(u64 size, u64 align) return kzalloc(size, GFP_KERNEL); } +static DEFINE_MUTEX(of_fdt_unflatten_mutex); + /** * of_fdt_unflatten_tree - create tree of device_nodes from flat blob * @@ -447,7 +450,9 @@ static void *kernel_tree_alloc(u64 size, u64 align) void of_fdt_unflatten_tree(const unsigned long *blob, struct device_node **mynodes) { + mutex_lock(&of_fdt_unflatten_mutex); __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc); + mutex_unlock(&of_fdt_unflatten_mutex); } EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); -- cgit v0.10.2 From d3632493c70b6a866a77264cd8cfdeb89958b906 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 20 Nov 2015 11:04:12 -0800 Subject: IB/cma: Add a missing rcu_read_unlock() Ensure that validate_ipv4_net_dev() calls rcu_read_unlock() if fib_lookup() fails. Detected by sparse. Compile-tested only. Fixes: "IB/cma: Validate routing of incoming requests" (commit f887f2ac87c2). Cc: Haggai Eran Cc: stable Reviewed-by: Sagi Grimberg Reviewed-by: Haggai Eran Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 944cd90..d2d5d00 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1126,10 +1126,7 @@ static bool validate_ipv4_net_dev(struct net_device *net_dev, rcu_read_lock(); err = fib_lookup(dev_net(net_dev), &fl4, &res, 0); - if (err) - return false; - - ret = FIB_RES_DEV(res) == net_dev; + ret = err == 0 && FIB_RES_DEV(res) == net_dev; rcu_read_unlock(); return ret; -- cgit v0.10.2 From 533708867dd6388f643f12c87465b59e732d729d Mon Sep 17 00:00:00 2001 From: Hal Rosenstock Date: Fri, 13 Nov 2015 15:22:22 -0500 Subject: IB/mad: Require CM send method for everything except ClassPortInfo Receipt of CM MAD with other than the Send method for an attribute other than the ClassPortInfo attribute is invalid. CM attributes other than ClassPortInfo only use the send method. The SRP initiator does not maintain a timeout policy for CM connect requests relies on the CM layer to do that. The result was that the SRP initiator hung as the connect request never completed. A new SRP target has been observed to respond to Send CM REQ with GetResp of CM REQ with bad status. This is non conformant with IBA spec but exposes a vulnerability in the current MAD/CM code which will respond to the incoming GetResp of CM REQ as if it was a valid incoming Send of CM REQ rather than tossing this on the floor. It also causes the MAD layer not to retransmit the original REQ even though it has not received a REP. Reviewed-by: Sagi Grimberg Signed-off-by: Hal Rosenstock Reviewed-by: Ira Weiny Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 8d8af7a..2281de1 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1811,6 +1811,11 @@ static int validate_mad(const struct ib_mad_hdr *mad_hdr, if (qp_num == 0) valid = 1; } else { + /* CM attributes other than ClassPortInfo only use Send method */ + if ((mad_hdr->mgmt_class == IB_MGMT_CLASS_CM) && + (mad_hdr->attr_id != IB_MGMT_CLASSPORTINFO_ATTR_ID) && + (mad_hdr->method != IB_MGMT_METHOD_SEND)) + goto out; /* Filter GSI packets sent to QP0 */ if (qp_num != 0) valid = 1; diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 188df91..ec9b44d 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -237,6 +237,8 @@ struct ib_vendor_mad { u8 data[IB_MGMT_VENDOR_DATA]; }; +#define IB_MGMT_CLASSPORTINFO_ATTR_ID cpu_to_be16(0x0001) + struct ib_class_port_info { u8 base_version; u8 class_version; -- cgit v0.10.2 From a5e14ba334e202c58e45ef47414ec94c585c1a8c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 28 Oct 2015 13:28:15 +0200 Subject: mlx4: Expose correct max_sge_rd limit mlx4 devices (ConnectX-2, ConnectX-3) has a limitation where rdma read work queue entries cannot exceed 512 bytes. A rdma_read wqe needs to fit in 512 bytes: - wqe control segment (16 bytes) - rdma segment (16 bytes) - scatter elements (16 bytes each) So max_sge_rd should be: (512 - 16 - 16) / 16 = 30. Signed-off-by: Sagi Grimberg Reviewed-by: Steve Wise Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index f567160..97d6878 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -456,7 +456,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; props->max_sge = min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg); - props->max_sge_rd = props->max_sge; + props->max_sge_rd = MLX4_MAX_SGE_RD; props->max_cq = dev->dev->quotas.cq; props->max_cqe = dev->dev->caps.max_cqes; props->max_mr = dev->dev->quotas.mpt; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 7501626..d3133be 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -427,6 +427,17 @@ enum { }; enum { + /* + * Max wqe size for rdma read is 512 bytes, so this + * limits our max_sge_rd as the wqe needs to fit: + * - ctrl segment (16 bytes) + * - rdma segment (16 bytes) + * - scatter elements (16 bytes each) + */ + MLX4_MAX_SGE_RD = (512 - 16 - 16) / 16 +}; + +enum { MLX4_DEV_PMC_SUBTYPE_GUID_INFO = 0x14, MLX4_DEV_PMC_SUBTYPE_PORT_INFO = 0x15, MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE = 0x16, -- cgit v0.10.2 From f1a47d37fbc65bc49d32f23ab61c3e09fefeab73 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 28 Oct 2015 13:28:16 +0200 Subject: iser-target: Remove explicit mlx4 work-around The driver now exposes sufficient limits so we can avoid having mlx4 specific work-around. Signed-off-by: Sagi Grimberg Reviewed-by: Steve Wise Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index dfbbbb2..8a51c3b 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -157,16 +157,9 @@ isert_create_qp(struct isert_conn *isert_conn, attr.recv_cq = comp->cq; attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS; attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1; - /* - * FIXME: Use devattr.max_sge - 2 for max_send_sge as - * work-around for RDMA_READs with ConnectX-2. - * - * Also, still make sure to have at least two SGEs for - * outgoing control PDU responses. - */ - attr.cap.max_send_sge = max(2, device->dev_attr.max_sge - 2); - isert_conn->max_sge = attr.cap.max_send_sge; - + attr.cap.max_send_sge = device->dev_attr.max_sge; + isert_conn->max_sge = min(device->dev_attr.max_sge, + device->dev_attr.max_sge_rd); attr.cap.max_recv_sge = 1; attr.sq_sig_type = IB_SIGNAL_REQ_WR; attr.qp_type = IB_QPT_RC; -- cgit v0.10.2 From 4ad78628445d26e5e9487b2e8f23274ad7b0f5d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 8 Dec 2015 03:07:22 -0500 Subject: 9p: ->evict_inode() should kick out ->i_data, not ->i_mapping For block devices the pagecache is associated with the inode on bdevfs, not with the aliasing ones on the mountable filesystems. The latter have its own ->i_data empty and ->i_mapping pointing to the (unique per major/minor) bdevfs inode. That guarantees cache coherence between all block device inodes with the same device number. Eviction of an alias inode has no business trying to evict the pages belonging to bdevfs one; moreover, ->i_mapping is only safe to access when the thing is opened. At the time of ->evict_inode() the victim is definitely *not* opened. We are about to kill the address space embedded into struct inode (inode->i_data) and that's what we need to empty of any pages. 9p instance tries to empty inode->i_mapping instead, which is both unsafe and bogus - if we have several device nodes with the same device number in different places, closing one of them should not try to empty the (shared) page cache. Fortunately, other instances in the tree are OK; they are evicting from &inode->i_data instead, as 9p one should. Cc: stable@vger.kernel.org # v2.6.32+, ones prior to 2.6.36 need only half of that Reported-by: "Suzuki K. Poulose" Tested-by: "Suzuki K. Poulose" Signed-off-by: Al Viro diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 699941e..5110785 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -451,9 +451,9 @@ void v9fs_evict_inode(struct inode *inode) { struct v9fs_inode *v9inode = V9FS_I(inode); - truncate_inode_pages_final(inode->i_mapping); + truncate_inode_pages_final(&inode->i_data); clear_inode(inode); - filemap_fdatawrite(inode->i_mapping); + filemap_fdatawrite(&inode->i_data); v9fs_cache_inode_put_cookie(inode); /* clunk the fid stashed in writeback_fid */ -- cgit v0.10.2 From 2d4594acbf6d8f75a27f3578476b6a27d8b13ebb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 8 Dec 2015 12:22:47 -0500 Subject: fix the regression from "direct-io: Fix negative return from dio read beyond eof" Sure, it's better to bail out of past-the-eof read and return 0 than return a bogus negative value on such. Only we'd better make sure we are bailing out with 0 and not -ENOMEM... Cc: stable@vger.kernel.org Signed-off-by: Al Viro diff --git a/fs/direct-io.c b/fs/direct-io.c index 1c75a3a..602e844 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1175,6 +1175,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, if (dio->flags & DIO_LOCKING) mutex_unlock(&inode->i_mutex); kmem_cache_free(dio_cache, dio); + retval = 0; goto out; } -- cgit v0.10.2 From af096e2235c5de76af7e8749f59a90de07f5e943 Mon Sep 17 00:00:00 2001 From: Minfei Huang Date: Tue, 8 Dec 2015 13:47:34 -0700 Subject: null_blk: Fix error path in module initialization Module couldn't release resource properly during the initialization. To fix this issue, we will clean up the proper resource before returning. Signed-off-by: Minfei Huang Signed-off-by: Jens Axboe diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 7981b74..8162475 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -766,7 +766,9 @@ out: static int __init null_init(void) { + int ret = 0; unsigned int i; + struct nullb *nullb; if (bs > PAGE_SIZE) { pr_warn("null_blk: invalid block size\n"); @@ -808,22 +810,29 @@ static int __init null_init(void) 0, 0, NULL); if (!ppa_cache) { pr_err("null_blk: unable to create ppa cache\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_ppa; } } for (i = 0; i < nr_devices; i++) { - if (null_add_dev()) { - unregister_blkdev(null_major, "nullb"); - goto err_ppa; - } + ret = null_add_dev(); + if (ret) + goto err_dev; } pr_info("null: module loaded\n"); return 0; -err_ppa: + +err_dev: + while (!list_empty(&nullb_list)) { + nullb = list_entry(nullb_list.next, struct nullb, list); + null_del_dev(nullb); + } kmem_cache_destroy(ppa_cache); - return -EINVAL; +err_ppa: + unregister_blkdev(null_major, "nullb"); + return ret; } static void __exit null_exit(void) -- cgit v0.10.2 From db2f24dc240856fb1d78005307f1523b7b3c121b Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 18 Nov 2015 09:37:15 +0100 Subject: um: Fix get_signal() usage If get_signal() returns us a signal to post we must not call it again, otherwise the already posted signal will be overridden. Before commit a610d6e672d this was the case as we stopped the while after a successful handle_signal(). Cc: # 3.10- Fixes: a610d6e672d ("pull clearing RESTORE_SIGMASK into block_sigmask()") Signed-off-by: Richard Weinberger diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index 57acbd6..fc8be0e 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -69,7 +69,7 @@ void do_signal(struct pt_regs *regs) struct ksignal ksig; int handled_sig = 0; - while (get_signal(&ksig)) { + if (get_signal(&ksig)) { handled_sig = 1; /* Whee! Actually deliver the signal. */ handle_signal(&ksig, regs); -- cgit v0.10.2 From fb1770aa78a43530940d0c2dd161e77bc705bdac Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 18 Nov 2015 23:12:09 +0900 Subject: arch: um: fix error when linking vmlinux. On gcc Ubuntu 4.8.4-2ubuntu1~14.04, linking vmlinux fails with: arch/um/os-Linux/built-in.o: In function `os_timer_create': /android/kernel/android/arch/um/os-Linux/time.c:51: undefined reference to `timer_create' arch/um/os-Linux/built-in.o: In function `os_timer_set_interval': /android/kernel/android/arch/um/os-Linux/time.c:84: undefined reference to `timer_settime' arch/um/os-Linux/built-in.o: In function `os_timer_remain': /android/kernel/android/arch/um/os-Linux/time.c:109: undefined reference to `timer_gettime' arch/um/os-Linux/built-in.o: In function `os_timer_one_shot': /android/kernel/android/arch/um/os-Linux/time.c:132: undefined reference to `timer_settime' arch/um/os-Linux/built-in.o: In function `os_timer_disable': /android/kernel/android/arch/um/os-Linux/time.c:145: undefined reference to `timer_settime' This is because -lrt appears in the generated link commandline after arch/um/os-Linux/built-in.o. Fix this by removing -lrt from arch/um/Makefile and adding it to the UM-specific section of scripts/link-vmlinux.sh. Signed-off-by: Lorenzo Colitti Signed-off-by: Richard Weinberger diff --git a/arch/um/Makefile b/arch/um/Makefile index 25ed409..e3abe6f 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -131,7 +131,7 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT) # The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc -LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -lrt +LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) # Used by link-vmlinux.sh which has special support for um link export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 1a10d8a..dacf71a 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -62,7 +62,7 @@ vmlinux_link() -Wl,--start-group \ ${KBUILD_VMLINUX_MAIN} \ -Wl,--end-group \ - -lutil ${1} + -lutil -lrt ${1} rm -f linux fi } -- cgit v0.10.2 From 8090bfd2bb9abc6293f5cedef8ec9be84a913d2f Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sun, 29 Nov 2015 21:13:50 +0100 Subject: um: Fix fpstate handling The x86 FPU cleanup changed fpstate to a plain integer. UML on x86 has to deal with that too. Signed-off-by: Richard Weinberger diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 06934a8..e5f854c 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -211,7 +211,7 @@ static int copy_sc_from_user(struct pt_regs *regs, if (err) return 1; - err = convert_fxsr_from_user(&fpx, sc.fpstate); + err = convert_fxsr_from_user(&fpx, (void *)sc.fpstate); if (err) return 1; @@ -227,7 +227,7 @@ static int copy_sc_from_user(struct pt_regs *regs, { struct user_i387_struct fp; - err = copy_from_user(&fp, sc.fpstate, + err = copy_from_user(&fp, (void *)sc.fpstate, sizeof(struct user_i387_struct)); if (err) return 1; @@ -291,7 +291,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, #endif #undef PUTREG sc.oldmask = mask; - sc.fpstate = to_fp; + sc.fpstate = (unsigned long)to_fp; err = copy_to_user(to, &sc, sizeof(struct sigcontext)); if (err) @@ -468,12 +468,10 @@ long sys_sigreturn(void) struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); sigset_t set; struct sigcontext __user *sc = &frame->sc; - unsigned long __user *oldmask = &sc->oldmask; - unsigned long __user *extramask = frame->extramask; int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || - copy_from_user(&set.sig[1], extramask, sig_size)) + if (copy_from_user(&set.sig[0], (void *)sc->oldmask, sizeof(set.sig[0])) || + copy_from_user(&set.sig[1], frame->extramask, sig_size)) goto segfault; set_current_blocked(&set); @@ -505,6 +503,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, { struct rt_sigframe __user *frame; int err = 0, sig = ksig->sig; + unsigned long fp_to; frame = (struct rt_sigframe __user *) round_down(stack_top - sizeof(struct rt_sigframe), 16); @@ -526,7 +525,10 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs)); err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]); - err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate); + + fp_to = (unsigned long)&frame->fpstate; + + err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); -- cgit v0.10.2 From 887a9853092c09e20598f4a7f91ac1cfb762be50 Mon Sep 17 00:00:00 2001 From: "Geyslan G. Bem" Date: Tue, 1 Dec 2015 17:18:55 -0300 Subject: um: fix returns without va_end When using va_list ensure that va_start will be followed by va_end. Signed-off-by: Geyslan G. Bem Signed-off-by: Richard Weinberger diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index e697a41..e9f8445 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -249,21 +249,23 @@ void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) char *split_if_spec(char *str, ...) { - char **arg, *end; + char **arg, *end, *ret = NULL; va_list ap; va_start(ap, str); while ((arg = va_arg(ap, char **)) != NULL) { if (*str == '\0') - return NULL; + goto out; end = strchr(str, ','); if (end != str) *arg = str; if (end == NULL) - return NULL; + goto out; *end++ = '\0'; str = end; } + ret = str; +out: va_end(ap); - return str; + return ret; } -- cgit v0.10.2 From 73d4da7b9fec13cbddcf548888c4d0e46f1d5087 Mon Sep 17 00:00:00 2001 From: Wengang Wang Date: Thu, 8 Oct 2015 13:21:33 +0800 Subject: IB/mlx4: Use correct order of variables in log message There is a mis-order in mlx4 log. Fix it. Signed-off-by: Wengang Wang Acked-by: Or Gerlitz Signed-off-by: Doug Ledford diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 2177e56..d48d579 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1010,7 +1010,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && smp->method == IB_MGMT_METHOD_GET) || network_view) { mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n", - slave, smp->method, smp->mgmt_class, + slave, smp->mgmt_class, smp->method, network_view ? "Network" : "Host", be16_to_cpu(smp->attr_id)); return -EPERM; -- cgit v0.10.2 From 0ef2f05c7e02ff99c0b5b583d7dee2cd12b053f2 Mon Sep 17 00:00:00 2001 From: Wengang Wang Date: Thu, 8 Oct 2015 13:27:04 +0800 Subject: IB/mlx4: Use vmalloc for WR buffers when needed There are several hits that WR buffer allocation(kmalloc) failed. It failed at order 3 and/or 4 contigous pages allocation. At the same time there are actually 100MB+ free memory but well fragmented. So try vmalloc when kmalloc failed. Signed-off-by: Wengang Wang Acked-by: Or Gerlitz Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index a2e4ca5..13eaaf4 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -795,8 +796,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, if (err) goto err_mtt; - qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), gfp); - qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), gfp); + qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(u64), gfp); + if (!qp->sq.wrid) + qp->sq.wrid = __vmalloc(qp->sq.wqe_cnt * sizeof(u64), + gfp, PAGE_KERNEL); + qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(u64), gfp); + if (!qp->rq.wrid) + qp->rq.wrid = __vmalloc(qp->rq.wqe_cnt * sizeof(u64), + gfp, PAGE_KERNEL); if (!qp->sq.wrid || !qp->rq.wrid) { err = -ENOMEM; goto err_wrid; @@ -886,8 +893,8 @@ err_wrid: if (qp_has_rq(init_attr)) mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db); } else { - kfree(qp->sq.wrid); - kfree(qp->rq.wrid); + kvfree(qp->sq.wrid); + kvfree(qp->rq.wrid); } err_mtt: @@ -1062,8 +1069,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, &qp->db); ib_umem_release(qp->umem); } else { - kfree(qp->sq.wrid); - kfree(qp->rq.wrid); + kvfree(qp->sq.wrid); + kvfree(qp->rq.wrid); if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) free_proxy_bufs(&dev->ib_dev, qp); diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index dce5dfe..8d133c4 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "mlx4_ib.h" #include "user.h" @@ -172,8 +173,12 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL); if (!srq->wrid) { - err = -ENOMEM; - goto err_mtt; + srq->wrid = __vmalloc(srq->msrq.max * sizeof(u64), + GFP_KERNEL, PAGE_KERNEL); + if (!srq->wrid) { + err = -ENOMEM; + goto err_mtt; + } } } @@ -204,7 +209,7 @@ err_wrid: if (pd->uobject) mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db); else - kfree(srq->wrid); + kvfree(srq->wrid); err_mtt: mlx4_mtt_cleanup(dev->dev, &srq->mtt); -- cgit v0.10.2 From ab5cdc31630c7596d81ca8fbe7d695f10666f39b Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 21 Oct 2015 09:21:17 +0300 Subject: IB/mlx5: Postpone remove_keys under knowledge of coming preemption The remove_keys() logic is performed as garbage collection task. Such task is intended to be run when no other active processes are running. The need_resched() will return TRUE if there are user tasks to be activated in near future. In such case, we don't execute remove_keys() and postpone the garbage collection work to try to run in next cycle, in order to free CPU resources to other tasks. The possible pseudo-code to trigger such scenario: 1. Allocate a lot of MR to fill the cache above the limit. 2. Wait a small amount of time "to calm" the system. 3. Start CPU extensive operations on multi-node cluster. 4. Expect performance degradation during MR cache shrink operation. Signed-off-by: Leon Romanovsky Signed-off-by: Eli Cohen Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index ec8993a..6000f7a 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -381,7 +381,19 @@ static void __cache_work_func(struct mlx5_cache_ent *ent) } } } else if (ent->cur > 2 * ent->limit) { - if (!someone_adding(cache) && + /* + * The remove_keys() logic is performed as garbage collection + * task. Such task is intended to be run when no other active + * processes are running. + * + * The need_resched() will return TRUE if there are user tasks + * to be activated in near future. + * + * In such case, we don't execute remove_keys() and postpone + * the garbage collection work to try to run in next cycle, + * in order to free CPU resources to other tasks. + */ + if (!need_resched() && !someone_adding(cache) && time_after(jiffies, cache->last_add + 300 * HZ)) { remove_keys(dev, i, 1); if (ent->cur > ent->limit) -- cgit v0.10.2 From 714a98fc3f20934ce8098667b809de954ebab93c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 9 Dec 2015 10:06:05 +1000 Subject: drm/nouveau/pmu: remove whitelist for PGOB-exit WAR, enable by default NVIDIA have indicated that the workaround is required on all GK10[467] boards that have the PGOB fuse set. I've left the commandline option in place for now, as paranoia. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 8f76000..913192c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -159,7 +159,6 @@ struct nvkm_device_func { struct nvkm_device_quirk { u8 tv_pin_mask; u8 tv_gpio; - bool War00C800_0; }; struct nvkm_device_chip { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index caf22b5..62ad030 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -259,12 +259,6 @@ nvkm_device_pci_10de_0df4[] = { }; static const struct nvkm_device_pci_vendor -nvkm_device_pci_10de_0fcd[] = { - { 0x17aa, 0x3801, NULL, { .War00C800_0 = true } }, /* Lenovo Y510P */ - {} -}; - -static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_0fd2[] = { { 0x1028, 0x0595, "GeForce GT 640M LE" }, { 0x1028, 0x05b2, "GeForce GT 640M LE" }, @@ -279,12 +273,6 @@ nvkm_device_pci_10de_0fe3[] = { }; static const struct nvkm_device_pci_vendor -nvkm_device_pci_10de_0fe4[] = { - { 0x144d, 0xc740, NULL, { .War00C800_0 = true } }, - {} -}; - -static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_104b[] = { { 0x1043, 0x844c, "GeForce GT 625" }, { 0x1043, 0x846b, "GeForce GT 625" }, @@ -690,13 +678,6 @@ nvkm_device_pci_10de_1189[] = { static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_1199[] = { { 0x1458, 0xd001, "GeForce GTX 760" }, - { 0x1462, 0x1106, "GeForce GTX 780M", { .War00C800_0 = true } }, /* Medion Erazer X7827 */ - {} -}; - -static const struct nvkm_device_pci_vendor -nvkm_device_pci_10de_11e0[] = { - { 0x1558, 0x5106, NULL, { .War00C800_0 = true } }, {} }; @@ -707,14 +688,6 @@ nvkm_device_pci_10de_11e3[] = { }; static const struct nvkm_device_pci_vendor -nvkm_device_pci_10de_11fc[] = { - { 0x1179, 0x0001, NULL, { .War00C800_0 = true } }, /* Toshiba Tecra W50 */ - { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ - { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ - {} -}; - -static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_1247[] = { { 0x1043, 0x212a, "GeForce GT 635M" }, { 0x1043, 0x212b, "GeForce GT 635M" }, @@ -1368,7 +1341,7 @@ nvkm_device_pci_10de[] = { { 0x0fc6, "GeForce GTX 650" }, { 0x0fc8, "GeForce GT 740" }, { 0x0fc9, "GeForce GT 730" }, - { 0x0fcd, "GeForce GT 755M", nvkm_device_pci_10de_0fcd }, + { 0x0fcd, "GeForce GT 755M" }, { 0x0fce, "GeForce GT 640M LE" }, { 0x0fd1, "GeForce GT 650M" }, { 0x0fd2, "GeForce GT 640M", nvkm_device_pci_10de_0fd2 }, @@ -1382,7 +1355,7 @@ nvkm_device_pci_10de[] = { { 0x0fe1, "GeForce GT 730M" }, { 0x0fe2, "GeForce GT 745M" }, { 0x0fe3, "GeForce GT 745M", nvkm_device_pci_10de_0fe3 }, - { 0x0fe4, "GeForce GT 750M", nvkm_device_pci_10de_0fe4 }, + { 0x0fe4, "GeForce GT 750M" }, { 0x0fe9, "GeForce GT 750M" }, { 0x0fea, "GeForce GT 755M" }, { 0x0fec, "GeForce 710A" }, @@ -1497,12 +1470,12 @@ nvkm_device_pci_10de[] = { { 0x11c6, "GeForce GTX 650 Ti" }, { 0x11c8, "GeForce GTX 650" }, { 0x11cb, "GeForce GT 740" }, - { 0x11e0, "GeForce GTX 770M", nvkm_device_pci_10de_11e0 }, + { 0x11e0, "GeForce GTX 770M" }, { 0x11e1, "GeForce GTX 765M" }, { 0x11e2, "GeForce GTX 765M" }, { 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 }, { 0x11fa, "Quadro K4000" }, - { 0x11fc, "Quadro K2100M", nvkm_device_pci_10de_11fc }, + { 0x11fc, "Quadro K2100M" }, { 0x1200, "GeForce GTX 560 Ti" }, { 0x1201, "GeForce GTX 560" }, { 0x1203, "GeForce GTX 460 SE v2" }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index d942fa7..86f9f3b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -81,9 +81,7 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); nvkm_rd32(device, 0x000200); - if ( nvkm_boolopt(device->cfgopt, "War00C800_0", - device->quirk ? device->quirk->War00C800_0 : false)) { - nvkm_info(&pmu->subdev, "hw bug workaround enabled\n"); + if (nvkm_boolopt(device->cfgopt, "War00C800_0", true)) { switch (device->chipset) { case 0xe4: magic(device, 0x04000000); -- cgit v0.10.2 From 5b01310cfc8d2302dcca1d8da42873edab2ef784 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 8 Dec 2015 17:44:02 -0500 Subject: powerpc/sbc8641: drop bogus PHY IRQ entries from DTS file This file was originally cloned off of the MPC8641D-HPCN reference platform, which actually had a PHY IRQ line connected. However this board does not. The bogus entry was largely inert and went undetected until commit 321beec5047af83db90c88114b7e664b156f49fe ("net: phy: Use interrupts when available in NOLINK state") was added to the tree. With the above commit, the board fails to NFS boot since it sits waiting for a PHY IRQ event that of course never arrives. Removing the bogus entries from the DTS file fixes the issue. Cc: Andrew Lunn Signed-off-by: Paul Gortmaker Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/boot/dts/sbc8641d.dts b/arch/powerpc/boot/dts/sbc8641d.dts index 631ede7..68f0ed7 100644 --- a/arch/powerpc/boot/dts/sbc8641d.dts +++ b/arch/powerpc/boot/dts/sbc8641d.dts @@ -227,23 +227,15 @@ reg = <0x520 0x20>; phy0: ethernet-phy@1f { - interrupt-parent = <&mpic>; - interrupts = <10 1>; reg = <0x1f>; }; phy1: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <10 1>; reg = <0>; }; phy2: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <10 1>; reg = <1>; }; phy3: ethernet-phy@2 { - interrupt-parent = <&mpic>; - interrupts = <10 1>; reg = <2>; }; tbi0: tbi-phy@11 { -- cgit v0.10.2 From dc9c41bd9ece090b54eb8f1bbdfb1930e10d3ae7 Mon Sep 17 00:00:00 2001 From: Andrew Donnellan Date: Tue, 8 Dec 2015 16:59:25 +1100 Subject: Revert "powerpc/eeh: Don't unfreeze PHB PE after reset" This reverts commit 527d10ef3a315d3cb9dc098dacd61889a6c26439. The reverted commit breaks cxlflash devices following an EEH reset (and possibly other cxl devices, however this has not been tested). The reverted commit changed the behaviour of eeh_reset_device() so that PHB PEs are not unfrozen following the completion of the reset. This should not be problematic, as no device resources should have been associated with the PHB PE. However, when attempting to load the cxlflash driver after a reset, the driver attempts to read Vital Product Data through a call to pci_read_vpd() (which is called on the physical cxl device, not on the virtual AFU device). pci_read_vpd() in turn attempts to read from the cxl device's config space. This fails, as the PE it's trying to read from is still frozen. In turn, the driver gets an -ENODEV and fails to initialise. It appears this issue only affects some parts of the VPD area, as "lspci -vvv", which only reads a subset of the VPD bytes, is not broken by the original patch. At this stage, we don't fully understand why we're trying to read a frozen PE, and we don't know how this affects other cxl devices. It is possible that there is an underlying bug in the cxl driver or the powerpc CAPI support code, or alternatively a bug in the PCI resource allocation/mapping code that is incorrectly mapping resources to PE#0. As such, this fix is incomplete, however it is necessary to prevent a serious regression in CAPI support. In the meantime, revert the commit, especially as it was intended to be a non-functional change. Cc: Gavin Shan Cc: Ian Munsie Cc: Daniel Axtens Signed-off-by: Andrew Donnellan Signed-off-by: Michael Ellerman diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 80dfe89..8d14feb 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -590,16 +590,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); - /* - * If it's PHB PE, the frozen state on all available PEs should have - * been cleared by the PHB reset. Otherwise, we unfreeze the PE and its - * child PEs because they might be in frozen state. - */ - if (!(pe->type & EEH_PE_PHB)) { - rc = eeh_clear_pe_frozen_state(pe, false); - if (rc) - return rc; - } + /* Clear frozen state */ + rc = eeh_clear_pe_frozen_state(pe, false); + if (rc) + return rc; /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, -- cgit v0.10.2 From e410b5cbabe70b1f1da08146481f6bd7e904643c Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 7 Dec 2015 15:02:52 +0800 Subject: drm/amdgpu: fix the lost duplicates checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Chunming Zhou Reviewed-by: Christian König Reviewed-by: Jammy Zhou Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index f6ea4b4..9c253c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -477,6 +477,14 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, if (domain == AMDGPU_GEM_DOMAIN_CPU) goto error_unreserve; } + list_for_each_entry(entry, &duplicates, head) { + domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type); + /* if anything is swapped out don't swap it in here, + just abort and wait for the next CS */ + if (domain == AMDGPU_GEM_DOMAIN_CPU) + goto error_unreserve; + } + r = amdgpu_vm_update_page_directory(adev, bo_va->vm); if (r) goto error_unreserve; -- cgit v0.10.2 From 5f3e226f511ec98d70c970f09cdb4ec46511cc5e Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 4 Dec 2015 23:09:03 +0200 Subject: radeon/cik: Fix GFX IB test on Big-Endian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes the IB test on the GFX ring pass for CI-based cards installed in Big-Endian machines. Reviewed-by: Christian König Signed-off-by: Oded Gabbay Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 0154db4..f81fb26 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4173,11 +4173,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) control |= ib->length_dw | (vm_id << 24); radeon_ring_write(ring, header); - radeon_ring_write(ring, -#ifdef __BIG_ENDIAN - (2 << 0) | -#endif - (ib->gpu_addr & 0xFFFFFFFC)); + radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFFC)); radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); radeon_ring_write(ring, control); } -- cgit v0.10.2 From 687f4b98d1f4e27508f7ad4bcce787c1ba58b289 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 4 Dec 2015 23:09:04 +0200 Subject: radeon: Fix VCE ring test for Big-Endian systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the VCE ring test when running on Big-Endian machines. Every write to the ring needs to be translated to little-endian. Reviewed-by: Christian König Signed-off-by: Oded Gabbay Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index 574f62b..86f57e4 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -699,12 +699,12 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev, { uint64_t addr = semaphore->gpu_addr; - radeon_ring_write(ring, VCE_CMD_SEMAPHORE); - radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); - radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); - radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)); + radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)); + radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)); + radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))); if (!emit_wait) - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); return true; } @@ -719,10 +719,10 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev, void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) { struct radeon_ring *ring = &rdev->ring[ib->ring]; - radeon_ring_write(ring, VCE_CMD_IB); - radeon_ring_write(ring, ib->gpu_addr); - radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); - radeon_ring_write(ring, ib->length_dw); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)); + radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)); + radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))); + radeon_ring_write(ring, cpu_to_le32(ib->length_dw)); } /** @@ -738,12 +738,12 @@ void radeon_vce_fence_emit(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[fence->ring]; uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; - radeon_ring_write(ring, VCE_CMD_FENCE); - radeon_ring_write(ring, addr); - radeon_ring_write(ring, upper_32_bits(addr)); - radeon_ring_write(ring, fence->seq); - radeon_ring_write(ring, VCE_CMD_TRAP); - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)); + radeon_ring_write(ring, cpu_to_le32(addr)); + radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))); + radeon_ring_write(ring, cpu_to_le32(fence->seq)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); } /** @@ -765,7 +765,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) ring->idx, r); return r; } - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { -- cgit v0.10.2 From 361c32d39087e7caa99e629c0d7fb00643cb2190 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 4 Dec 2015 23:09:05 +0200 Subject: radeon: Fix VCE IB test on Big-Endian systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes the VCE IB test pass on Big-Endian systems. It converts to little-endian the contents of the VCE message. Reviewed-by: Christian König Signed-off-by: Oded Gabbay Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index 86f57e4..7eb1ae7 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -361,31 +361,31 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, /* stitch together an VCE create msg */ ib.length_dw = 0; - ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ - ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ - ib.ptr[ib.length_dw++] = handle; - - ib.ptr[ib.length_dw++] = 0x00000030; /* len */ - ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ - ib.ptr[ib.length_dw++] = 0x00000000; - ib.ptr[ib.length_dw++] = 0x00000042; - ib.ptr[ib.length_dw++] = 0x0000000a; - ib.ptr[ib.length_dw++] = 0x00000001; - ib.ptr[ib.length_dw++] = 0x00000080; - ib.ptr[ib.length_dw++] = 0x00000060; - ib.ptr[ib.length_dw++] = 0x00000100; - ib.ptr[ib.length_dw++] = 0x00000100; - ib.ptr[ib.length_dw++] = 0x0000000c; - ib.ptr[ib.length_dw++] = 0x00000000; - - ib.ptr[ib.length_dw++] = 0x00000014; /* len */ - ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ - ib.ptr[ib.length_dw++] = upper_32_bits(dummy); - ib.ptr[ib.length_dw++] = dummy; - ib.ptr[ib.length_dw++] = 0x00000001; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(handle); + + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); + + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ + ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); + ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); for (i = ib.length_dw; i < ib_size_dw; ++i) - ib.ptr[i] = 0x0; + ib.ptr[i] = cpu_to_le32(0x0); r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { @@ -428,21 +428,21 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, /* stitch together an VCE destroy msg */ ib.length_dw = 0; - ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ - ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ - ib.ptr[ib.length_dw++] = handle; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(handle); - ib.ptr[ib.length_dw++] = 0x00000014; /* len */ - ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ - ib.ptr[ib.length_dw++] = upper_32_bits(dummy); - ib.ptr[ib.length_dw++] = dummy; - ib.ptr[ib.length_dw++] = 0x00000001; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ + ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); + ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); - ib.ptr[ib.length_dw++] = 0x00000008; /* len */ - ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ for (i = ib.length_dw; i < ib_size_dw; ++i) - ib.ptr[i] = 0x0; + ib.ptr[i] = cpu_to_le32(0x0); r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { -- cgit v0.10.2 From 9a811230481243f384b8036c6a558bfdbd961f78 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2015 15:17:43 +0100 Subject: ALSA: hda - Fix noise problems on Thinkpad T440s Lenovo Thinkpad T440s suffers from constant background noises, and it seems to be a generic hardware issue on this model: https://forums.lenovo.com/t5/ThinkPad-T400-T500-and-newer-T/T440s-speaker-noise/td-p/1339883 As the noise comes from the analog loopback path, disabling the path is the easy workaround. Also, the machine gives significant cracking noises at PM suspend. A workaround found by trial-and-error is to disable the shutup callback currently used for ALC269-variant. This patch addresses these noise issues by introducing a new fixup chain. Although the same workaround might be applicable to other Thinkpad models, it's applied only to T440s (17aa:220c) in this patch, so far, just to be safe (you chicken!). As a compromise, a new model option string "tp440" is provided now, though, so that owners of other Thinkpad models can test it more easily. Bugzilla: https://bugzilla.opensuse.org/show_bug.cgi?id=958504 Reported-and-tested-by: Tim Hardeck Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 49b1d36..8dd2ac1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4204,6 +4204,18 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, } } +/* additional fixup for Thinkpad T440s noise problem */ +static void alc_fixup_tpt440(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->shutup = alc_no_shutup; /* reduce click noise */ + spec->gen.mixer_nid = 0; /* reduce background noise */ + } +} + static void alc_shutup_dell_xps13(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -4578,6 +4590,7 @@ enum { ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, ALC292_FIXUP_TPT440_DOCK, + ALC292_FIXUP_TPT440, ALC283_FIXUP_BXBT2807_MIC, ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, ALC282_FIXUP_ASPIRE_V5_PINS, @@ -5051,6 +5064,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC292_FIXUP_TPT440] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_tpt440, + .chained = true, + .chain_id = ALC292_FIXUP_TPT440_DOCK, + }, [ALC283_FIXUP_BXBT2807_MIC] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -5332,7 +5351,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440), SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK), @@ -5432,6 +5451,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, + {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {} }; -- cgit v0.10.2 From 4c3141e09cfa6460bfcd5e90f73e498db654c917 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 1 Dec 2015 17:24:17 +0100 Subject: of/irq: Export of_irq_find_parent again of_irq_find_parent was made static since it had no users outside of of_irq.c. Export it again since we are going to use it again. Signed-off-by: Carlo Caione [robh: move of_irq_find_parent to correct ifdef section] Signed-off-by: Rob Herring diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 902b89b..4fa916d 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); * Returns a pointer to the interrupt parent node, or NULL if the interrupt * parent could not be determined. */ -static struct device_node *of_irq_find_parent(struct device_node *child) +struct device_node *of_irq_find_parent(struct device_node *child) { struct device_node *p; const __be32 *parp; @@ -77,6 +77,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child) return p; } +EXPORT_SYMBOL_GPL(of_irq_find_parent); /** * of_irq_parse_raw - Low level interrupt tree parsing diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 039f2ee..f648acf 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -46,6 +46,7 @@ extern int of_irq_get(struct device_node *dev, int index); extern int of_irq_get_byname(struct device_node *dev, const char *name); extern int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int nr_irqs); +extern struct device_node *of_irq_find_parent(struct device_node *child); extern struct irq_domain *of_msi_get_domain(struct device *dev, struct device_node *np, enum irq_domain_bus_token token); @@ -70,6 +71,11 @@ static inline int of_irq_to_resource_table(struct device_node *dev, { return 0; } +static inline void *of_irq_find_parent(struct device_node *child) +{ + return NULL; +} + static inline struct irq_domain *of_msi_get_domain(struct device *dev, struct device_node *np, enum irq_domain_bus_token token) -- cgit v0.10.2 From eaddb5725357e9f05ffe5d271630f8197d089da4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 9 Dec 2015 09:11:10 -0600 Subject: of/irq: move of_msi_map_rid declaration to the correct ifdef section In checking fixes for of_irq_find_parent declaration location, I found that of_msi_map_rid is also wrong. of_msi_map_rid is not implemented for Sparc, so it should not be in the Sparc specific section of the header. Move it to just depend on OF_IRQ. Cc: Frank Rowand Signed-off-by: Rob Herring diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index f648acf..1e0deb8 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -53,6 +53,7 @@ extern struct irq_domain *of_msi_get_domain(struct device *dev, extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid); extern void of_msi_configure(struct device *dev, struct device_node *np); +u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in); #else static inline int of_irq_count(struct device_node *dev) { @@ -90,6 +91,11 @@ static inline struct irq_domain *of_msi_map_get_device_domain(struct device *dev static inline void of_msi_configure(struct device *dev, struct device_node *np) { } +static inline u32 of_msi_map_rid(struct device *dev, + struct device_node *msi_np, u32 rid_in) +{ + return rid_in; +} #endif #if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC) @@ -99,7 +105,6 @@ static inline void of_msi_configure(struct device *dev, struct device_node *np) * so declare it here regardless of the CONFIG_OF_IRQ setting. */ extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); -u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in); #else /* !CONFIG_OF && !CONFIG_SPARC */ static inline unsigned int irq_of_parse_and_map(struct device_node *dev, @@ -107,12 +112,6 @@ static inline unsigned int irq_of_parse_and_map(struct device_node *dev, { return 0; } - -static inline u32 of_msi_map_rid(struct device *dev, - struct device_node *msi_np, u32 rid_in) -{ - return rid_in; -} #endif /* !CONFIG_OF */ #endif /* __OF_IRQ_H */ -- cgit v0.10.2 From 7d32cdef535622c0aea39807989f62cdddea207e Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 23 Nov 2015 21:50:11 +0200 Subject: usb: musb: fail with error when no DMA controller set Fail with error when no DMA controller is set. Signed-off-by: Aaro Koskinen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 3c07ffd..ee9ff70 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2094,6 +2094,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) #ifndef CONFIG_MUSB_PIO_ONLY if (!musb->ops->dma_init || !musb->ops->dma_exit) { dev_err(dev, "DMA controller not set\n"); + status = -ENODEV; goto fail2; } musb_dma_controller_create = musb->ops->dma_init; -- cgit v0.10.2 From 5328e1ea87fb2b5cf695115df4325c1913209e97 Mon Sep 17 00:00:00 2001 From: Gabriele Martino Date: Wed, 9 Dec 2015 17:05:58 +0100 Subject: ALSA: hda/ca0132 - quirk for Alienware 17 2015 The Alienware 17 (2015) has the same card and pin configuration of the Alienware 15, so the same quirks must be applied. Signed-off-by: Gabriele Martino Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index f8a12ca4..4ef2259 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -778,7 +778,8 @@ static const struct hda_pintbl alienware_pincfgs[] = { }; static const struct snd_pci_quirk ca0132_quirks[] = { - SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15", QUIRK_ALIENWARE), + SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), + SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), {} }; -- cgit v0.10.2 From 49e99fc717f624aa75ca755d6e7bc029efd3f0e9 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 9 Dec 2015 16:23:24 +0000 Subject: dm thin metadata: fix bug when taking a metadata snapshot When you take a metadata snapshot the btree roots for the mapping and details tree need to have their reference counts incremented so they persist for the lifetime of the metadata snap. The roots being incremented were those currently written in the superblock, which could possibly be out of date if concurrent IO is triggering new mappings, breaking of sharing, etc. Fix this by performing a commit with the metadata lock held while taking a metadata snapshot. 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 67871e7..c219a05 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1207,6 +1207,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) dm_block_t held_root; /* + * We commit to ensure the btree roots which we increment in a + * moment are up to date. + */ + __commit_transaction(pmd); + + /* * Copy the superblock. */ dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION); -- cgit v0.10.2 From 50dd842ad83b43bed71790efb31cfb2f6c05c9c1 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 9 Dec 2015 16:38:12 +0000 Subject: dm space map metadata: fix ref counting bug when bootstrapping a new space map When applying block operations (BOPs) do not remove them from the uncommitted BOP ring-buffer until after they've been applied -- in case we recurse. Also, perform BOP_INC operation, in dm_sm_metadata_create() and sm_metadata_extend(), in terms of the uncommitted BOP ring-buffer rather than using direct calls to sm_ll_inc(). Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 5309129..fca6dbc 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -136,7 +136,7 @@ static int brb_push(struct bop_ring_buffer *brb, return 0; } -static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) +static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result) { struct block_op *bop; @@ -147,6 +147,17 @@ static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) result->type = bop->type; result->block = bop->block; + return 0; +} + +static int brb_pop(struct bop_ring_buffer *brb) +{ + struct block_op *bop; + + if (brb_empty(brb)) + return -ENODATA; + + bop = brb->bops + brb->begin; brb->begin = brb_next(brb, brb->begin); return 0; @@ -211,7 +222,7 @@ static int apply_bops(struct sm_metadata *smm) while (!brb_empty(&smm->uncommitted)) { struct block_op bop; - r = brb_pop(&smm->uncommitted, &bop); + r = brb_peek(&smm->uncommitted, &bop); if (r) { DMERR("bug in bop ring buffer"); break; @@ -220,6 +231,8 @@ static int apply_bops(struct sm_metadata *smm) r = commit_bop(smm, &bop); if (r) break; + + brb_pop(&smm->uncommitted); } return r; @@ -683,7 +696,6 @@ static struct dm_space_map bootstrap_ops = { static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks) { int r, i; - enum allocation_event ev; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); dm_block_t old_len = smm->ll.nr_blocks; @@ -705,11 +717,12 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks) * allocate any new blocks. */ do { - for (i = old_len; !r && i < smm->begin; i++) { - r = sm_ll_inc(&smm->ll, i, &ev); - if (r) - goto out; - } + for (i = old_len; !r && i < smm->begin; i++) + r = add_bop(smm, BOP_INC, i); + + if (r) + goto out; + old_len = smm->begin; r = apply_bops(smm); @@ -754,7 +767,6 @@ int dm_sm_metadata_create(struct dm_space_map *sm, { int r; dm_block_t i; - enum allocation_event ev; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); smm->begin = superblock + 1; @@ -782,7 +794,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm, * allocated blocks that they were built from. */ for (i = superblock; !r && i < smm->begin; i++) - r = sm_ll_inc(&smm->ll, i, &ev); + r = add_bop(smm, BOP_INC, i); if (r) return r; -- cgit v0.10.2 From d7e35dfa2531b53618b9e6edcd8752ce988ac555 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 3 Dec 2015 22:04:01 -0500 Subject: bitops.h: correctly handle rol32 with 0 byte shift ROL on a 32 bit integer with a shift of 32 or more is undefined and the result is arch-dependent. Avoid this by handling the trivial case of roling by 0 correctly. The trivial solution of checking if shift is 0 breaks gcc's detection of this code as a ROL instruction, which is unacceptable. This bug was reported and fixed in GCC (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157): The standard rotate idiom, (x << n) | (x >> (32 - n)) is recognized by gcc (for concreteness, I discuss only the case that x is an uint32_t here). However, this is portable C only for n in the range 0 < n < 32. For n == 0, we get x >> 32 which gives undefined behaviour according to the C standard (6.5.7, Bitwise shift operators). To portably support n == 0, one has to write the rotate as something like (x << n) | (x >> ((-n) & 31)) And this is apparently not recognized by gcc. Note that this is broken on older GCCs and will result in slower ROL. Acked-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Linus Torvalds diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 2b8ed12..defeaac 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -107,7 +107,7 @@ static inline __u64 ror64(__u64 word, unsigned int shift) */ static inline __u32 rol32(__u32 word, unsigned int shift) { - return (word << shift) | (word >> (32 - shift)); + return (word << shift) | (word >> ((-shift) & 31)); } /** -- cgit v0.10.2 From 27f972d3e00b50639deb4cc1392afaeb08d3cecc Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Tue, 8 Dec 2015 13:57:51 -0500 Subject: ipmi: move timer init to before irq is setup We encountered a panic on boot in ipmi_si on a dell per320 due to an uninitialized timer as follows. static int smi_start_processing(void *send_info, ipmi_smi_t intf) { /* Try to claim any interrupts. */ if (new_smi->irq_setup) new_smi->irq_setup(new_smi); --> IRQ arrives here and irq handler tries to modify uninitialized timer which triggers BUG_ON(!timer->function) in __mod_timer(). Call Trace: [] start_new_msg+0x47/0x80 [ipmi_si] [] start_check_enables+0x4e/0x60 [ipmi_si] [] smi_event_handler+0x1e8/0x640 [ipmi_si] [] ? __rcu_process_callbacks+0x54/0x350 [] si_irq_handler+0x3c/0x60 [ipmi_si] [] handle_IRQ_event+0x60/0x170 [] handle_edge_irq+0xde/0x180 [] handle_irq+0x49/0xa0 [] do_IRQ+0x6c/0xf0 [] ret_from_intr+0x0/0x11 /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); The following patch fixes the problem. To: Openipmi-developer@lists.sourceforge.net To: Corey Minyard CC: linux-kernel@vger.kernel.org Signed-off-by: Jan Stancek Signed-off-by: Tony Camuso Signed-off-by: Corey Minyard Cc: stable@vger.kernel.org # Applies cleanly to 3.10-, needs small rework before diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 55fe902..4cc72fa 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1230,14 +1230,14 @@ static int smi_start_processing(void *send_info, new_smi->intf = intf; - /* Try to claim any interrupts. */ - if (new_smi->irq_setup) - new_smi->irq_setup(new_smi); - /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); + /* Try to claim any interrupts. */ + if (new_smi->irq_setup) + new_smi->irq_setup(new_smi); + /* * Check if the user forcefully enabled the daemon. */ -- cgit v0.10.2 From 14054fb1da099fd89208b8b319a00e0b902c7645 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 30 Nov 2015 17:56:38 +0200 Subject: ARM: dts: am4372: fix clock source for arm twd and global timers ARM TWD and Global timer are clocked by PERIPHCLK which is MPU_CLK/2. But now they are clocked by dpll_mpu_m2_ck == MPU_CLK and, as result. Timekeeping core misbehaves. For example, execution of command "sleep 5" will take 10 sec instead of 5. Hence, fix it by adding mpu_periphclk ("fixed-factor-clock") and use it for clocking ARM TWD and Global timer (same way as on OMAP4). Cc: Tony Lindgren Cc: Felipe Balbi Cc: Tero Kristo Fixes:commit 8cbd4c2f6a99 ("arm: boot: dts: am4372: add ARM timers and SCU nodes") Signed-off-by: Grygorii Strashko Reviewed-by: Felipe Balbi Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d83ff9c..de8791a 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -74,7 +74,7 @@ reg = <0x48240200 0x100>; interrupts = ; interrupt-parent = <&gic>; - clocks = <&dpll_mpu_m2_ck>; + clocks = <&mpu_periphclk>; }; local_timer: timer@48240600 { @@ -82,7 +82,7 @@ reg = <0x48240600 0x100>; interrupts = ; interrupt-parent = <&gic>; - clocks = <&dpll_mpu_m2_ck>; + clocks = <&mpu_periphclk>; }; l2-cache-controller@48242000 { diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi index cc88728..a38af2b 100644 --- a/arch/arm/boot/dts/am43xx-clocks.dtsi +++ b/arch/arm/boot/dts/am43xx-clocks.dtsi @@ -259,6 +259,14 @@ ti,invert-autoidle-bit; }; + mpu_periphclk: mpu_periphclk { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clocks = <&dpll_mpu_m2_ck>; + clock-mult = <1>; + clock-div = <2>; + }; + dpll_ddr_ck: dpll_ddr_ck { #clock-cells = <0>; compatible = "ti,am3-dpll-clock"; -- cgit v0.10.2 From ed8b45a3679eb49069b094c0711b30833f27c734 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 10 Dec 2015 14:37:53 +0000 Subject: dm btree: fix bufio buffer leaks in dm_btree_del() error path If dm_btree_del()'s call to push_frame() fails, e.g. due to btree_node_validator finding invalid metadata, the dm_btree_del() error path must unlock all frames (which have active dm-bufio buffers) that were pushed onto the del_stack. Otherwise, dm_bufio_client_destroy() will BUG_ON() because dm-bufio buffers have leaked, e.g.: device-mapper: bufio: leaked buffer 3, hold count 1, list 0 Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index 7e5b7f1..b1ced58 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -257,6 +257,16 @@ static void pop_frame(struct del_stack *s) dm_tm_unlock(s->tm, f->b); } +static void unlock_all_frames(struct del_stack *s) +{ + struct frame *f; + + while (unprocessed_frames(s)) { + f = s->spine + s->top--; + dm_tm_unlock(s->tm, f->b); + } +} + int dm_btree_del(struct dm_btree_info *info, dm_block_t root) { int r; @@ -313,9 +323,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root) pop_frame(s); } } - out: + if (r) { + /* cleanup all frames of del_stack */ + unlock_all_frames(s); + } kfree(s); + return r; } EXPORT_SYMBOL_GPL(dm_btree_del); -- cgit v0.10.2 From 059393c5bdd1420bdf1bed2972f33196dff263ae Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 7 Dec 2015 10:11:11 +0000 Subject: irqchip/gic-v3: Add missing struct device_node declaration When the GICv3 header file is used in a C file that doesn't include any of the OF stuff, we end up with a bunch of ugly warnings. Let's keep GCC quiet by adding a forward declaration. Signed-off-by: Marc Zyngier Cc: Cc: Jason Cooper Link: http://lkml.kernel.org/r/1449483072-17694-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index c9ae0c6..d5d798b 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -330,6 +330,7 @@ struct rdists { }; struct irq_domain; +struct device_node; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); -- cgit v0.10.2 From 8e31ed9c189788463c3b6c1f950cd90755f05f76 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 7 Dec 2015 10:11:12 +0000 Subject: irqchip/gic-v3: Add missing include for barrier.h Both the 32bit and 64bit versions of the GICv3 header file are using barriers, but neglect to include barrier.h, leading to an interesting splat in some circumstances. Signed-off-by: Marc Zyngier Cc: Cc: Jason Cooper Link: http://lkml.kernel.org/r/1449483072-17694-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h index 6607d97..7da5503 100644 --- a/arch/arm/include/asm/arch_gicv3.h +++ b/arch/arm/include/asm/arch_gicv3.h @@ -21,6 +21,7 @@ #ifndef __ASSEMBLY__ #include +#include #define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 #define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 030cdcb..2731d3b 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -77,6 +77,7 @@ #ifndef __ASSEMBLY__ #include +#include /* * Low-level accessors -- cgit v0.10.2 From e2bf3e6ecaff79c5479682da2dc7b2035e52c5b8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Dec 2015 18:21:41 +0100 Subject: clocksource: Mmio: remove artificial 32bit limitation The EP93xx is registering a clocksource of 40 bits with clocksource_mmio_init() but this is not working because of this artificial limitation. It works fine to lift the uppe limit to 64 bits, and since cycle_t is u64, it should intuitively have been like that from the beginning. Fixes: 000bc17817bf "ARM: ep93xx: switch to GENERIC_CLOCKEVENTS" Reported-by: Alexander Sverdlin Signed-off-by: Linus Walleij Cc: Daniel Lezcano Link: http://lkml.kernel.org/r/1449768101-6879-1-git-send-email-linus.walleij@linaro.org Signed-off-by: Thomas Gleixner diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c index 1593ade..c4f7d7a 100644 --- a/drivers/clocksource/mmio.c +++ b/drivers/clocksource/mmio.c @@ -55,7 +55,7 @@ int __init clocksource_mmio_init(void __iomem *base, const char *name, { struct clocksource_mmio *cs; - if (bits > 32 || bits < 16) + if (bits > 64 || bits < 16) return -EINVAL; cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL); -- cgit v0.10.2 From 5d756147f7d356c3e85372373a0054dcf25a370e Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 7 Dec 2015 21:09:24 +0800 Subject: ARM: dts: berlin: correct BG2Q's sdhci2 2nd clock The optional 2nd clock is CLKID_SDIO. We removed CLK_IGNORE_UNUSED from CLKID_SDIO's flag, so the sdhci2 doesn't work. This patch fixes this issue by correcting the sdhci2's 2nd clock. Signed-off-by: Jisheng Zhang Signed-off-by: Sebastian Hesselbarth diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi index 8ea177f..5b10129 100644 --- a/arch/arm/boot/dts/berlin2q.dtsi +++ b/arch/arm/boot/dts/berlin2q.dtsi @@ -135,7 +135,7 @@ compatible = "mrvl,pxav3-mmc"; reg = <0xab1000 0x200>; interrupts = ; - clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_NFC>; + clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_SDIO>; clock-names = "io", "core"; status = "disabled"; }; -- cgit v0.10.2 From b5010d2081331e1c95358c4eb500bd30f5d532ce Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 7 Dec 2015 21:09:25 +0800 Subject: ARM: dts: berlin: add 2nd clock for BG2Q sdhci0 and sdhci1 We removed CLK_IGNORE_UNUSED from CLKID_SDIO's flag, so the sdhci0 and sdhci1 don't work. We fix this by adding the optional 2nd clock for BG2Q's sdhci0 and sdhci1. This patch brings another benefit: the 2nd clock can be disabled during runtime pm, so saves power a bit. Signed-off-by: Jisheng Zhang Signed-off-by: Sebastian Hesselbarth diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi index 5b10129..fb1da99 100644 --- a/arch/arm/boot/dts/berlin2q.dtsi +++ b/arch/arm/boot/dts/berlin2q.dtsi @@ -118,7 +118,8 @@ sdhci0: sdhci@ab0000 { compatible = "mrvl,pxav3-mmc"; reg = <0xab0000 0x200>; - clocks = <&chip_clk CLKID_SDIO1XIN>; + clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>; + clock-names = "io", "core"; interrupts = ; status = "disabled"; }; @@ -126,7 +127,8 @@ sdhci1: sdhci@ab0800 { compatible = "mrvl,pxav3-mmc"; reg = <0xab0800 0x200>; - clocks = <&chip_clk CLKID_SDIO1XIN>; + clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>; + clock-names = "io", "core"; interrupts = ; status = "disabled"; }; -- cgit v0.10.2 From ddd47fbcf68dd07487fd86f5e3d9f594f8349980 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 9 Dec 2015 15:11:12 +0100 Subject: ARM: pxa: use PWM lookup table for all machines The recent change to use a pwm lookup table for the ezx machines was incomplete and only changed the a780 model, but not the other ones in the same file. This adds the missing calls to pwm_add_table(). Signed-off-by: Arnd Bergmann Fixes: c3322022897c ("ARM: pxa: ezx: Use PWM lookup table") Acked-by: Thierry Reding Acked-by: Robert Jarzmik diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 9a9c15b..7c0d561 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -889,6 +889,7 @@ static void __init e680_init(void) pxa_set_keypad_info(&e680_keypad_platform_data); + pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(e680_devices)); } @@ -956,6 +957,7 @@ static void __init a1200_init(void) pxa_set_keypad_info(&a1200_keypad_platform_data); + pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a1200_devices)); } @@ -1148,6 +1150,7 @@ static void __init a910_init(void) platform_device_register(&a910_camera); } + pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a910_devices)); } @@ -1215,6 +1218,7 @@ static void __init e6_init(void) pxa_set_keypad_info(&e6_keypad_platform_data); + pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(e6_devices)); } @@ -1256,6 +1260,7 @@ static void __init e2_init(void) pxa_set_keypad_info(&e2_keypad_platform_data); + pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(e2_devices)); } -- cgit v0.10.2 From 9f5bd30818c42c6c36a51f93b4df75a2ea2bd85e Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 30 Nov 2015 04:17:31 +0200 Subject: vgaarb: fix signal handling in vga_get() There are few defects in vga_get() related to signal hadning: - we shouldn't check for pending signals for TASK_UNINTERRUPTIBLE case; - if we found pending signal we must remove ourself from wait queue and change task state back to running; - -ERESTARTSYS is more appropriate, I guess. Signed-off-by: Kirill A. Shutemov Cc: stable@vger.kernel.org Reviewed-by: David Herrmann Signed-off-by: Dave Airlie diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 3166e4b..9abcaa5 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -395,8 +395,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) set_current_state(interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; + if (interruptible && signal_pending(current)) { + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vga_wait_queue, &wait); + rc = -ERESTARTSYS; break; } schedule(); -- cgit v0.10.2 From 9c17190595840b4ed30e8d5f286636ceb28aae4f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 30 Nov 2015 17:59:26 -0800 Subject: ARM: dts: vf610: use reset values for L2 cache latencies Linux on Vybrid used several different L2 latencies so far, none of them seem to be the right ones. According to the application note AN4947 ("Understanding Vybrid Architecture"), the tag portion runs on CPU clock and is inside the L2 cache controller, whereas the data portion is stored in the external SRAM running on platform clock. Hence it is likely that the correct value requires a higher data latency then tag latency. These are the values which have been used so far: - The mainline values: arm,data-latency = <1 1 1>; arm,tag-latency = <2 2 2>; Those values have lead to problems on higher clocks. They look like a poor translation from the reset values (missing +1 offset and a mix up between tag/latency values). - The Linux 3.0 (SoC vendor BSP) values (converted to DT notation): arm,data-latency = <4 2 3> arm,tag-latency = <4 2 3> The cache initialization function along with the value matches the i.MX6 code from the same kernel, so it seems that those values have just been copied. - The Colibri values: arm,data-latency = <2 1 2>; arm,tag-latency = <3 2 3>; Those were a mix between the values of the Linux 3.0 based BSP and the mainline values above. - The SoC Reset values (converted to DT notation): arm,data-latency = <3 3 3>; arm,tag-latency = <2 2 2>; So far there is no official statement on what the correct values are. See also the related Freescale community thread: https://community.freescale.com/message/579785#579785 For now, the reset values seem to be the best bet. Remove all other "bogus" values and use the reset value on vf610.dtsi level. Signed-off-by: Stefan Agner Cc: Signed-off-by: Shawn Guo diff --git a/arch/arm/boot/dts/vf610-colibri.dtsi b/arch/arm/boot/dts/vf610-colibri.dtsi index 19fe045..2d7eab7 100644 --- a/arch/arm/boot/dts/vf610-colibri.dtsi +++ b/arch/arm/boot/dts/vf610-colibri.dtsi @@ -18,8 +18,3 @@ reg = <0x80000000 0x10000000>; }; }; - -&L2 { - arm,data-latency = <2 1 2>; - arm,tag-latency = <3 2 3>; -}; diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index 5f8eb1b..58bc6e4 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -19,7 +19,7 @@ reg = <0x40006000 0x1000>; cache-unified; cache-level = <2>; - arm,data-latency = <1 1 1>; + arm,data-latency = <3 3 3>; arm,tag-latency = <2 2 2>; }; }; -- cgit v0.10.2 From 82d340081b6f71237373d1452e3573a5a122794c Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 8 Dec 2015 17:39:15 +0000 Subject: arm64: Improve error reporting on set_pte_at() checks Currently the BUG_ON() checks do not give enough information about the PTEs being set. This patch changes BUG_ON to WARN_ONCE and dumps the values of the old and new PTEs. In addition, the checks are only made if the new PTE entry is valid. Signed-off-by: Catalin Marinas Reported-by: Ming Lei Cc: Will Deacon diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 7e074f9..63f52b5 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -276,10 +276,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, * hardware updates of the pte (ptep_set_access_flags safely changes * valid ptes without going through an invalid entry). */ - if (IS_ENABLED(CONFIG_DEBUG_VM) && IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && - pte_valid(*ptep)) { - BUG_ON(!pte_young(pte)); - BUG_ON(pte_write(*ptep) && !pte_dirty(pte)); + if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && + pte_valid(*ptep) && pte_valid(pte)) { + VM_WARN_ONCE(!pte_young(pte), + "%s: racy access flag clearing: 0x%016llx -> 0x%016llx", + __func__, pte_val(*ptep), pte_val(pte)); + VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte), + "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx", + __func__, pte_val(*ptep), pte_val(pte)); } set_pte(ptep, pte); -- cgit v0.10.2 From f69115fdbc1ac0718e7d19ad3caa3da2ecfe1c96 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 11 Dec 2015 14:38:06 +0200 Subject: xhci: fix usb2 resume timing and races. According to USB 2 specs ports need to signal resume for at least 20ms, in practice even longer, before moving to U0 state. Both host and devices can initiate resume. On device initiated resume, a port status interrupt with the port in resume state in issued. The interrupt handler tags a resume_done[port] timestamp with current time + USB_RESUME_TIMEOUT, and kick roothub timer. Root hub timer requests for port status, finds the port in resume state, checks if resume_done[port] timestamp passed, and set port to U0 state. On host initiated resume, current code sets the port to resume state, sleep 20ms, and finally sets the port to U0 state. This should also be changed to work in a similar way as the device initiated resume, with timestamp tagging, but that is not yet tested and will be a separate fix later. There are a few issues with this approach 1. A host initiated resume will also generate a resume event. The event handler will find the port in resume state, believe it's a device initiated resume, and act accordingly. 2. A port status request might cut the resume signalling short if a get_port_status request is handled during the host resume signalling. The port will be found in resume state. The timestamp is not set leading to time_after_eq(jiffies, timestamp) returning true, as timestamp = 0. get_port_status will proceed with moving the port to U0. 3. If an error, or anything else happens to the port during device initiated resume signalling it will leave all the device resume parameters hanging uncleared, preventing further suspend, returning -EBUSY, and cause the pm thread to busyloop trying to enter suspend. Fix this by using the existing resuming_ports bitfield to indicate that resume signalling timing is taken care of. Check if the resume_done[port] is set before using it for timestamp comparison, and also clear out any resume signalling related variables if port is not in U0 or Resume state This issue was discovered when a PM thread busylooped, trying to runtime suspend the xhci USB 2 roothub on a Dell XPS Cc: stable Reported-by: Daniel J Blueman Tested-by: Daniel J Blueman Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0230965..f980c23 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -733,8 +733,30 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, if ((raw_port_status & PORT_RESET) || !(raw_port_status & PORT_PE)) return 0xffffffff; - if (time_after_eq(jiffies, - bus_state->resume_done[wIndex])) { + /* did port event handler already start resume timing? */ + if (!bus_state->resume_done[wIndex]) { + /* If not, maybe we are in a host initated resume? */ + if (test_bit(wIndex, &bus_state->resuming_ports)) { + /* Host initated resume doesn't time the resume + * signalling using resume_done[]. + * It manually sets RESUME state, sleeps 20ms + * and sets U0 state. This should probably be + * changed, but not right now. + */ + } else { + /* port resume was discovered now and here, + * start resume timing + */ + unsigned long timeout = jiffies + + msecs_to_jiffies(USB_RESUME_TIMEOUT); + + set_bit(wIndex, &bus_state->resuming_ports); + bus_state->resume_done[wIndex] = timeout; + mod_timer(&hcd->rh_timer, timeout); + } + /* Has resume been signalled for USB_RESUME_TIME yet? */ + } else if (time_after_eq(jiffies, + bus_state->resume_done[wIndex])) { int time_left; xhci_dbg(xhci, "Resume USB2 port %d\n", @@ -775,13 +797,26 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, } else { /* * The resume has been signaling for less than - * 20ms. Report the port status as SUSPEND, - * let the usbcore check port status again - * and clear resume signaling later. + * USB_RESUME_TIME. Report the port status as SUSPEND, + * let the usbcore check port status again and clear + * resume signaling later. */ status |= USB_PORT_STAT_SUSPEND; } } + /* + * Clear stale usb2 resume signalling variables in case port changed + * state during resume signalling. For example on error + */ + if ((bus_state->resume_done[wIndex] || + test_bit(wIndex, &bus_state->resuming_ports)) && + (raw_port_status & PORT_PLS_MASK) != XDEV_U3 && + (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) { + bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); + } + + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 && (raw_port_status & PORT_POWER)) { if (bus_state->suspended_ports & (1 << wIndex)) { @@ -1115,6 +1150,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if ((temp & PORT_PE) == 0) goto error; + set_bit(wIndex, &bus_state->resuming_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_RESUME); spin_unlock_irqrestore(&xhci->lock, flags); @@ -1122,6 +1158,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_lock_irqsave(&xhci->lock, flags); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); + clear_bit(wIndex, &bus_state->resuming_ports); } bus_state->port_c_suspend |= 1 << wIndex; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6c5e813..eeaa6c6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1583,7 +1583,8 @@ static void handle_port_status(struct xhci_hcd *xhci, */ bogus_port_status = true; goto cleanup; - } else { + } else if (!test_bit(faked_port_index, + &bus_state->resuming_ports)) { xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); -- cgit v0.10.2 From ad87e03213b552a5c33d5e1e7a19a73768397010 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 10 Dec 2015 15:27:21 -0500 Subject: USB: add quirk for devices with broken LPM Some USB device / host controller combinations seem to have problems with Link Power Management. For example, Steinar found that his xHCI controller wouldn't handle bandwidth calculations correctly for two video cards simultaneously when LPM was enabled, even though the bus had plenty of bandwidth available. This patch introduces a new quirk flag for devices that should remain disabled for LPM, and creates quirk entries for Steinar's devices. Signed-off-by: Alan Stern Reported-by: Steinar H. Gunderson Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 585c3cb..a5cc032 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -124,6 +124,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) int usb_device_supports_lpm(struct usb_device *udev) { + /* Some devices have trouble with LPM */ + if (udev->quirks & USB_QUIRK_NO_LPM) + return 0; + /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. */ @@ -4512,6 +4516,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } + usb_detect_quirks(udev); + if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { @@ -4710,7 +4716,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, if (status < 0) goto loop; - usb_detect_quirks(udev); if (udev->quirks & USB_QUIRK_DELAY_INIT) msleep(1000); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index fcd6ac0..6dc810b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -202,6 +202,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Blackmagic Design Intensity Shuttle */ + { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, + + /* Blackmagic Design UltraStudio SDI */ + { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, + { } /* terminating entry must be last */ }; diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 9948c87..1d0043d 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -47,4 +47,7 @@ /* device generates spurious wakeup, ignore remote wakeup capability */ #define USB_QUIRK_IGNORE_REMOTE_WAKEUP BIT(9) +/* device can't handle Link Power Management */ +#define USB_QUIRK_NO_LPM BIT(10) + #endif /* __LINUX_USB_QUIRKS_H */ -- cgit v0.10.2 From 2dd2e4d1eaadfc39eae0399c5be1a122a73ed13b Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Fri, 4 Dec 2015 16:55:03 -0600 Subject: ARM64: dts: ls2080a: fix eSDHC endianness Add the "little-endian" property to fix the issue that eSDHC is not working and dumping out "mmc0: Controller never released inhibit bit(s)." error messages constantly. Fixes: 5461597f6ce0 ("dts/ls2080a: Update DTSI to add support of various peripherals") Signed-off-by: Yangbo Lu Signed-off-by: Li Yang Signed-off-by: Kevin Hilman diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index e81cd48..ed45e25 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -269,6 +269,7 @@ clock-frequency = <0>; /* Updated by bootloader */ voltage-ranges = <1800 1800 3300 3300>; sdhci,auto-cmd12; + little-endian; bus-width = <4>; }; -- cgit v0.10.2 From edb70e29f3c3e3b1064a7b7a5d129c8f32762e6f Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 4 Dec 2015 16:55:04 -0600 Subject: dt-bindings: define little-endian property for QorIQ GPIO The GPIO block on different QorIQ chips could have registers in different endianess. Define the property to specify which endian is used by the hardware. Signed-off-by: Liu Gang Acked-by: Rob Herring Signed-off-by: Li Yang Signed-off-by: Kevin Hilman diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt index f2455c5..120bc49 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt @@ -11,6 +11,10 @@ Required properties: 0 = active high 1 = active low +Optional properties: +- little-endian : GPIO registers are used as little endian. If not + present registers are used as big endian by default. + Example: gpio0: gpio@1100 { -- cgit v0.10.2 From 6534778371b157e375a28a70290201d9aa20ab08 Mon Sep 17 00:00:00 2001 From: Liu Gang Date: Fri, 4 Dec 2015 16:55:05 -0600 Subject: ls2080a/dts: Add little endian property for GPIO IP block The GPIO block for ls2080a platform has little endian registers, the GPIO driver needs this property to read/write registers by right interface. Signed-off-by: Liu Gang Signed-off-by: Li Yang Signed-off-by: Kevin Hilman diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi index ed45e25..925552e 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi @@ -278,6 +278,7 @@ reg = <0x0 0x2300000 0x0 0x10000>; interrupts = <0 36 0x4>; /* Level high type */ gpio-controller; + little-endian; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; @@ -288,6 +289,7 @@ reg = <0x0 0x2310000 0x0 0x10000>; interrupts = <0 36 0x4>; /* Level high type */ gpio-controller; + little-endian; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; @@ -298,6 +300,7 @@ reg = <0x0 0x2320000 0x0 0x10000>; interrupts = <0 37 0x4>; /* Level high type */ gpio-controller; + little-endian; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; @@ -308,6 +311,7 @@ reg = <0x0 0x2330000 0x0 0x10000>; interrupts = <0 37 0x4>; /* Level high type */ gpio-controller; + little-endian; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; -- cgit v0.10.2 From e46e31a3696ae2d66f32c207df3969613726e636 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 30 Nov 2015 14:47:46 -0500 Subject: parisc iommu: fix panic due to trying to allocate too large region When using the Promise TX2+ SATA controller on PA-RISC, the system often crashes with kernel panic, for example just writing data with the dd utility will make it crash. Kernel panic - not syncing: drivers/parisc/sba_iommu.c: I/O MMU @ 000000000000a000 is out of mapping resources CPU: 0 PID: 18442 Comm: mkspadfs Not tainted 4.4.0-rc2 #2 Backtrace: [<000000004021497c>] show_stack+0x14/0x20 [<0000000040410bf0>] dump_stack+0x88/0x100 [<000000004023978c>] panic+0x124/0x360 [<0000000040452c18>] sba_alloc_range+0x698/0x6a0 [<0000000040453150>] sba_map_sg+0x260/0x5b8 [<000000000c18dbb4>] ata_qc_issue+0x264/0x4a8 [libata] [<000000000c19535c>] ata_scsi_translate+0xe4/0x220 [libata] [<000000000c19a93c>] ata_scsi_queuecmd+0xbc/0x320 [libata] [<0000000040499bbc>] scsi_dispatch_cmd+0xfc/0x130 [<000000004049da34>] scsi_request_fn+0x6e4/0x970 [<00000000403e95a8>] __blk_run_queue+0x40/0x60 [<00000000403e9d8c>] blk_run_queue+0x3c/0x68 [<000000004049a534>] scsi_run_queue+0x2a4/0x360 [<000000004049be68>] scsi_end_request+0x1a8/0x238 [<000000004049de84>] scsi_io_completion+0xfc/0x688 [<0000000040493c74>] scsi_finish_command+0x17c/0x1d0 The cause of the crash is not exhaustion of the IOMMU space, there is plenty of free pages. The function sba_alloc_range is called with size 0x11000, thus the pages_needed variable is 0x11. The function sba_search_bitmap is called with bits_wanted 0x11 and boundary size is 0x10 (because dma_get_seg_boundary(dev) returns 0xffff). The function sba_search_bitmap attempts to allocate 17 pages that must not cross 16-page boundary - it can't satisfy this requirement (iommu_is_span_boundary always returns true) and fails even if there are many free entries in the IOMMU space. How did it happen that we try to allocate 17 pages that don't cross 16-page boundary? The cause is in the function iommu_coalesce_chunks. This function tries to coalesce adjacent entries in the scatterlist. The function does several checks if it may coalesce one entry with the next, one of those checks is this: if (startsg->length + dma_len > max_seg_size) break; When it finishes coalescing adjacent entries, it allocates the mapping: sg_dma_len(contig_sg) = dma_len; dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); sg_dma_address(contig_sg) = PIDE_FLAG | (iommu_alloc_range(ioc, dev, dma_len) << IOVP_SHIFT) | dma_offset; It is possible that (startsg->length + dma_len > max_seg_size) is false (we are just near the 0x10000 max_seg_size boundary), so the funcion decides to coalesce this entry with the next entry. When the coalescing succeeds, the function performs dma_len = ALIGN(dma_len + dma_offset, IOVP_SIZE); And now, because of non-zero dma_offset, dma_len is greater than 0x10000. iommu_alloc_range (a pointer to sba_alloc_range) is called and it attempts to allocate 17 pages for a device that must not cross 16-page boundary. To fix the bug, we must make sure that dma_len after addition of dma_offset and alignment doesn't cross the segment boundary. I.e. change if (startsg->length + dma_len > max_seg_size) break; to if (ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) > max_seg_size) break; This patch makes this change (it precalculates max_seg_boundary at the beginning of the function iommu_coalesce_chunks). I also added a check that the mapping length doesn't exceed dma_get_seg_boundary(dev) (it is not needed for Promise TX2+ SATA, but it may be needed for other devices that have dma_get_seg_boundary lower than dma_get_max_seg_size). Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Helge Deller diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h index 761e77b..e56f156 100644 --- a/drivers/parisc/iommu-helpers.h +++ b/drivers/parisc/iommu-helpers.h @@ -104,7 +104,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, struct scatterlist *contig_sg; /* contig chunk head */ unsigned long dma_offset, dma_len; /* start/len of DMA stream */ unsigned int n_mappings = 0; - unsigned int max_seg_size = dma_get_max_seg_size(dev); + unsigned int max_seg_size = min(dma_get_max_seg_size(dev), + (unsigned)DMA_CHUNK_SIZE); + unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1; + if (max_seg_boundary) /* check if the addition above didn't overflow */ + max_seg_size = min(max_seg_size, max_seg_boundary); while (nents > 0) { @@ -138,14 +142,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev, /* ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the + ** exceed max_seg_size if we coalesce the ** next entry. */ - if(unlikely(ALIGN(dma_len + dma_offset + startsg->length, - IOVP_SIZE) > DMA_CHUNK_SIZE)) - break; - - if (startsg->length + dma_len > max_seg_size) + if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) > + max_seg_size)) break; /* -- cgit v0.10.2 From 5f0e9b4c301742c860b8aedc3e7c471d4a611043 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 1 Dec 2015 10:41:47 -0600 Subject: parisc: Remove unused pcibios_init_bus() There are no callers of pcibios_init_bus(), so remove it. Signed-off-by: Bjorn Helgaas Signed-off-by: Helge Deller diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index 64f2764..c99f3dd 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -171,24 +171,6 @@ void pcibios_set_master(struct pci_dev *dev) } -void __init pcibios_init_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - unsigned short bridge_ctl; - - /* We deal only with pci controllers and pci-pci bridges. */ - if (!dev || (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) - return; - - /* PCI-PCI bridge - set the cache line and default latency - (32) for primary and secondary buses. */ - pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32); - - pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl); - bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; - pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl); -} - /* * pcibios align resources() is called every time generic PCI code * wants to generate a new address. The process of looking for -- cgit v0.10.2 From 5c477b45792fb8ccd279162483aa57cc8ee40ae1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 6 Dec 2015 21:56:26 +0100 Subject: parisc: Wire up mlock2 syscall Signed-off-by: Helge Deller diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h index 3317038..35bdccb 100644 --- a/arch/parisc/include/uapi/asm/unistd.h +++ b/arch/parisc/include/uapi/asm/unistd.h @@ -360,8 +360,9 @@ #define __NR_execveat (__NR_Linux + 342) #define __NR_membarrier (__NR_Linux + 343) #define __NR_userfaultfd (__NR_Linux + 344) +#define __NR_mlock2 (__NR_Linux + 345) -#define __NR_Linux_syscalls (__NR_userfaultfd + 1) +#define __NR_Linux_syscalls (__NR_mlock2 + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 78c3ef8..d4ffcfb 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -440,6 +440,7 @@ ENTRY_COMP(execveat) ENTRY_SAME(membarrier) ENTRY_SAME(userfaultfd) + ENTRY_SAME(mlock2) /* 345 */ .ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b)) -- cgit v0.10.2 From 78c0cbffebe60e1182c8f077de2c06a1a48dc5ae Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 6 Dec 2015 21:25:20 +0100 Subject: parisc: Disable huge pages on Mako machines Mako-based machines (PA8800 and PA8900 CPUs) don't allow aliasing on non-equaivalent addresses. Signed-off-by: Helge Deller diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index d8534f9..291cee2 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -372,7 +372,8 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; } */ #ifdef CONFIG_HUGETLB_PAGE #define pte_huge(pte) (pte_val(pte) & _PAGE_HUGE) -#define pte_mkhuge(pte) (__pte(pte_val(pte) | _PAGE_HUGE)) +#define pte_mkhuge(pte) (__pte(pte_val(pte) | \ + (parisc_requires_coherency() ? 0 : _PAGE_HUGE))) #else #define pte_huge(pte) (0) #define pte_mkhuge(pte) (pte) -- cgit v0.10.2 From a88c769548047b21f76fd71e04b6a3300ff17160 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Fri, 11 Dec 2015 13:40:24 -0800 Subject: mm: hugetlb: fix hugepage memory leak caused by wrong reserve count When dequeue_huge_page_vma() in alloc_huge_page() fails, we fall back on alloc_buddy_huge_page() to directly create a hugepage from the buddy allocator. In that case, however, if alloc_buddy_huge_page() succeeds we don't decrement h->resv_huge_pages, which means that successful hugetlb_fault() returns without releasing the reserve count. As a result, subsequent hugetlb_fault() might fail despite that there are still free hugepages. This patch simply adds decrementing code on that code path. I reproduced this problem when testing v4.3 kernel in the following situation: - the test machine/VM is a NUMA system, - hugepage overcommiting is enabled, - most of hugepages are allocated and there's only one free hugepage which is on node 0 (for example), - another program, which calls set_mempolicy(MPOL_BIND) to bind itself to node 1, tries to allocate a hugepage, - the allocation should fail but the reserve count is still hold. Signed-off-by: Naoya Horiguchi Cc: David Rientjes Cc: Dave Hansen Cc: Mel Gorman Cc: Joonsoo Kim Cc: Hillf Danton Cc: Mike Kravetz Cc: [3.16+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 827bb02..4fe4340 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1886,7 +1886,10 @@ struct page *alloc_huge_page(struct vm_area_struct *vma, page = __alloc_buddy_huge_page_with_mpol(h, vma, addr); if (!page) goto out_uncharge_cgroup; - + if (!avoid_reserve && vma_has_reserves(vma, gbl_chg)) { + SetPagePrivate(page); + h->resv_huge_pages--; + } spin_lock(&hugetlb_lock); list_move(&page->lru, &h->hugepage_activelist); /* Fall through */ -- cgit v0.10.2 From 9516a18a9a253a94292e74f11f92083126c5a237 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Fri, 11 Dec 2015 13:40:24 -0800 Subject: memcg: fix memory.high target When the memory.high threshold is exceeded, try_charge() schedules a task_work to reclaim the excess. The reclaim target is set to the number of pages requested by try_charge(). This is wrong, because try_charge() usually charges more pages than requested (batch > nr_pages) in order to refill per cpu stocks. As a result, a process in a cgroup can easily exceed memory.high significantly when doing a lot of charges w/o returning to userspace (e.g. reading a file in big chunks). Fix this issue by assuring that when exceeding memory.high a process reclaims as many pages as were actually charged (i.e. batch). Signed-off-by: Vladimir Davydov Acked-by: Johannes Weiner Acked-by: Michal Hocko Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index c92a65b..32259e3 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2128,7 +2128,7 @@ done_restock: */ do { if (page_counter_read(&memcg->memory) > memcg->high) { - current->memcg_nr_pages_over_high += nr_pages; + current->memcg_nr_pages_over_high += batch; set_notify_resume(current); break; } -- cgit v0.10.2 From 475a2f905d5a41d5fc569ef21841be67d0a7f788 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Fri, 11 Dec 2015 13:40:29 -0800 Subject: mm: fix swapped Movable and Reclaimable in /proc/pagetypeinfo Commit 016c13daa5c9 ("mm, page_alloc: use masks and shifts when converting GFP flags to migrate types") has swapped MIGRATE_MOVABLE and MIGRATE_RECLAIMABLE in the enum definition. However, migratetype_names wasn't updated to reflect that. As a result, the file /proc/pagetypeinfo shows the counts for Movable as Reclaimable and vice versa. Additionally, commit 0aaa29a56e4f ("mm, page_alloc: reserve pageblocks for high-order atomic allocations on demand") introduced MIGRATE_HIGHATOMIC, but did not add a letter to distinguish it into show_migration_types(), so it doesn't appear in the listing of free areas during page alloc failures or oom kills. This patch fixes both problems. The atomic reserves will show with a letter 'H' in the free areas listings. Fixes: 016c13daa5c9 ("mm, page_alloc: use masks and shifts when converting GFP flags to migrate types") Fixes: 0aaa29a56e4f ("mm, page_alloc: reserve pageblocks for high-order atomic allocations on demand") Signed-off-by: Vlastimil Babka Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 17a3c66..9d666df 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3647,8 +3647,9 @@ static void show_migration_types(unsigned char type) { static const char types[MIGRATE_TYPES] = { [MIGRATE_UNMOVABLE] = 'U', - [MIGRATE_RECLAIMABLE] = 'E', [MIGRATE_MOVABLE] = 'M', + [MIGRATE_RECLAIMABLE] = 'E', + [MIGRATE_HIGHATOMIC] = 'H', #ifdef CONFIG_CMA [MIGRATE_CMA] = 'C', #endif diff --git a/mm/vmstat.c b/mm/vmstat.c index 879a2be..2ec3434 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -921,8 +921,8 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, #ifdef CONFIG_PROC_FS static char * const migratetype_names[MIGRATE_TYPES] = { "Unmovable", - "Reclaimable", "Movable", + "Reclaimable", "HighAtomic", #ifdef CONFIG_CMA "CMA", -- cgit v0.10.2 From 373ccbe5927034b55bdc80b0f8b54d6e13fe8d12 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Fri, 11 Dec 2015 13:40:32 -0800 Subject: mm, vmstat: allow WQ concurrency to discover memory reclaim doesn't make any progress Tetsuo Handa has reported that the system might basically livelock in OOM condition without triggering the OOM killer. The issue is caused by internal dependency of the direct reclaim on vmstat counter updates (via zone_reclaimable) which are performed from the workqueue context. If all the current workers get assigned to an allocation request, though, they will be looping inside the allocator trying to reclaim memory but zone_reclaimable can see stalled numbers so it will consider a zone reclaimable even though it has been scanned way too much. WQ concurrency logic will not consider this situation as a congested workqueue because it relies that worker would have to sleep in such a situation. This also means that it doesn't try to spawn new workers or invoke the rescuer thread if the one is assigned to the queue. In order to fix this issue we need to do two things. First we have to let wq concurrency code know that we are in trouble so we have to do a short sleep. In order to prevent from issues handled by 0e093d99763e ("writeback: do not sleep on the congestion queue if there are no congested BDIs or if significant congestion is not being encountered in the current zone") we limit the sleep only to worker threads which are the ones of the interest anyway. The second thing to do is to create a dedicated workqueue for vmstat and mark it WQ_MEM_RECLAIM to note it participates in the reclaim and to have a spare worker thread for it. Signed-off-by: Michal Hocko Reported-by: Tetsuo Handa Cc: Tejun Heo Cc: Cristopher Lameter Cc: Joonsoo Kim Cc: Arkadiusz Miskiewicz Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 8ed2ffd..7340353 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -957,8 +957,9 @@ EXPORT_SYMBOL(congestion_wait); * jiffies for either a BDI to exit congestion of the given @sync queue * or a write to complete. * - * In the absence of zone congestion, cond_resched() is called to yield - * the processor if necessary but otherwise does not sleep. + * In the absence of zone congestion, a short sleep or a cond_resched is + * performed to yield the processor and to allow other subsystems to make + * a forward progress. * * The return value is 0 if the sleep is for the full timeout. Otherwise, * it is the number of jiffies that were still remaining when the function @@ -978,7 +979,19 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout) */ if (atomic_read(&nr_wb_congested[sync]) == 0 || !test_bit(ZONE_CONGESTED, &zone->flags)) { - cond_resched(); + + /* + * Memory allocation/reclaim might be called from a WQ + * context and the current implementation of the WQ + * concurrency control doesn't recognize that a particular + * WQ is congested if the worker thread is looping without + * ever sleeping. Therefore we have to do a short sleep + * here rather than calling cond_resched(). + */ + if (current->flags & PF_WQ_WORKER) + schedule_timeout(1); + else + cond_resched(); /* In case we scheduled, work out time remaining */ ret = timeout - (jiffies - start); diff --git a/mm/vmstat.c b/mm/vmstat.c index 2ec3434..0d5712b 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1379,6 +1379,7 @@ static const struct file_operations proc_vmstat_file_operations = { #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_SMP +static struct workqueue_struct *vmstat_wq; static DEFINE_PER_CPU(struct delayed_work, vmstat_work); int sysctl_stat_interval __read_mostly = HZ; static cpumask_var_t cpu_stat_off; @@ -1391,7 +1392,7 @@ static void vmstat_update(struct work_struct *w) * to occur in the future. Keep on running the * update worker thread. */ - schedule_delayed_work_on(smp_processor_id(), + queue_delayed_work_on(smp_processor_id(), vmstat_wq, this_cpu_ptr(&vmstat_work), round_jiffies_relative(sysctl_stat_interval)); } else { @@ -1460,7 +1461,7 @@ static void vmstat_shepherd(struct work_struct *w) if (need_update(cpu) && cpumask_test_and_clear_cpu(cpu, cpu_stat_off)) - schedule_delayed_work_on(cpu, + queue_delayed_work_on(cpu, vmstat_wq, &per_cpu(vmstat_work, cpu), 0); put_online_cpus(); @@ -1549,6 +1550,7 @@ static int __init setup_vmstat(void) start_shepherd_timer(); cpu_notifier_register_done(); + vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); #endif #ifdef CONFIG_PROC_FS proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); -- cgit v0.10.2 From ed0f1e2102b6f245210be5f93a08d708b6ac070f Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Fri, 11 Dec 2015 13:40:35 -0800 Subject: MAINTAINERS: make Vladimir co-maintainer of the memory controller Vladimir architected and authored much of the current state of the memcg's slab memory accounting and tracking. Make sure he gets CC'd on bug reports ;-) Signed-off-by: Johannes Weiner Acked-by: Vladimir Davydov Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 38df53f..9bff63c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2975,6 +2975,7 @@ F: kernel/cpuset.c CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG) M: Johannes Weiner M: Michal Hocko +M: Vladimir Davydov L: cgroups@vger.kernel.org L: linux-mm@kvack.org S: Maintained -- cgit v0.10.2 From 3066a9670ba6f57dd5046640a2494912a2110f1e Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 11 Dec 2015 13:40:38 -0800 Subject: osd fs: __r4w_get_page rely on PageUptodate for uptodate Commit 42cb14b110a5 ("mm: migrate dirty page without clear_page_dirty_for_io etc") simplified the migration of a PageDirty pagecache page: one stat needs moving from zone to zone and that's about all. It's convenient and safest for it to shift the PageDirty bit from old page to new, just before updating the zone stats: before copying data and marking the new PageUptodate. This is all done while both pages are isolated and locked, just as before; and just as before, there's a moment when the new page is visible in the radix_tree, but not yet PageUptodate. What's new is that it may now be briefly visible as PageDirty before it is PageUptodate. When I scoured the tree to see if this could cause a problem anywhere, the only places I found were in two similar functions __r4w_get_page(): which look up a page with find_get_page() (not using page lock), then claim it's uptodate if it's PageDirty or PageWriteback or PageUptodate. I'm not sure whether that was right before, but now it might be wrong (on rare occasions): only claim the page is uptodate if PageUptodate. Or perhaps the page in question could never be migratable anyway? Signed-off-by: Hugh Dickins Tested-by: Boaz Harrosh Cc: Benny Halevy Cc: Trond Myklebust Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 73c64da..60f03b7 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -592,10 +592,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) } unlock_page(page); } - if (PageDirty(page) || PageWriteback(page)) - *uptodate = true; - else - *uptodate = PageUptodate(page); + *uptodate = PageUptodate(page); EXOFS_DBGMSG2("index=0x%lx uptodate=%d\n", index, *uptodate); return page; } else { diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 5c0c6b5..9aebffb 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -476,10 +476,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) } unlock_page(page); } - if (PageDirty(page) || PageWriteback(page)) - *uptodate = true; - else - *uptodate = PageUptodate(page); + *uptodate = PageUptodate(page); dprintk("%s: index=0x%lx uptodate=%d\n", __func__, index, *uptodate); return page; } -- cgit v0.10.2 From 25be6a659598791d511c09ed71dca24e4844d128 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 11 Dec 2015 13:40:40 -0800 Subject: mm: fix kerneldoc on mem_cgroup_replace_page Whoops, I missed removing the kerneldoc comment of the lrucare arg removed from mem_cgroup_replace_page; but it's a good comment, keep it. Signed-off-by: Hugh Dickins Acked-by: Michal Hocko Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 32259e3..e234c21 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5512,11 +5512,11 @@ void mem_cgroup_uncharge_list(struct list_head *page_list) * mem_cgroup_replace_page - migrate a charge to another page * @oldpage: currently charged page * @newpage: page to transfer the charge to - * @lrucare: either or both pages might be on the LRU already * * Migrate the charge from @oldpage to @newpage. * * Both pages must be locked, @newpage->mapping must be set up. + * Either or both pages might be on the LRU already. */ void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage) { -- cgit v0.10.2 From 98e89cf02aed11166698dd53c6f14865613babb3 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Fri, 11 Dec 2015 13:40:43 -0800 Subject: mm: kmemleak: mark kmemleak_init prototype as __init The kmemleak_init() definition in mm/kmemleak.c is marked __init but its prototype in include/linux/kmemleak.h is marked __ref since commit a6186d89c913 ("kmemleak: Mark the early log buffer as __initdata"). This causes a section mismatch which is reported as a warning when building with clang -Wsection, because kmemleak_init() is declared in section .ref.text but defined in .init.text. Fix this by marking kmemleak_init() prototype __init. Signed-off-by: Nicolas Iooss Signed-off-by: Catalin Marinas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index d0a1f99..4894c68 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h @@ -25,7 +25,7 @@ #ifdef CONFIG_DEBUG_KMEMLEAK -extern void kmemleak_init(void) __ref; +extern void kmemleak_init(void) __init; extern void kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp) __ref; extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size, -- cgit v0.10.2 From 86fffe4a61dd972d5a4e23260d530be6da02f614 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 11 Dec 2015 13:40:46 -0800 Subject: kernel: remove stop_machine() Kconfig dependency Currently the full stop_machine() routine is only enabled on SMP if module unloading is enabled, or if the CPUs are hotpluggable. This leads to configurations where stop_machine() is broken as it will then only run the callback on the local CPU with irqs disabled, and not stop the other CPUs or run the callback on them. For example, this breaks MTRR setup on x86 in certain configs since ea8596bb2d8d379 ("kprobes/x86: Remove unused text_poke_smp() and text_poke_smp_batch() functions") as the MTRR is only established on the boot CPU. This patch removes the Kconfig option for STOP_MACHINE and uses the SMP and HOTPLUG_CPU config options to compile the correct stop_machine() for the architecture, removing the false dependency on MODULE_UNLOAD in the process. Link: https://lkml.org/lkml/2014/10/8/124 References: https://bugs.freedesktop.org/show_bug.cgi?id=84794 Signed-off-by: Chris Wilson Acked-by: Ingo Molnar Cc: "Paul E. McKenney" Cc: Pranith Kumar Cc: Michal Hocko Cc: Vladimir Davydov Cc: Johannes Weiner Cc: H. Peter Anvin Cc: Tejun Heo Cc: Iulia Manda Cc: Andy Lutomirski Cc: Rusty Russell Cc: Peter Zijlstra Cc: Chuck Ebbert Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 0adedca..0e1b154 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h @@ -99,7 +99,7 @@ static inline int try_stop_cpus(const struct cpumask *cpumask, * grabbing every spinlock (and more). So the "read" side to such a * lock is anything which disables preemption. */ -#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP) +#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) /** * stop_machine: freeze the machine on all CPUs and run this function @@ -118,7 +118,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); -#else /* CONFIG_STOP_MACHINE && CONFIG_SMP */ +#else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ static inline int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus) @@ -137,5 +137,5 @@ static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, return stop_machine(fn, data, cpus); } -#endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */ +#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ #endif /* _LINUX_STOP_MACHINE */ diff --git a/init/Kconfig b/init/Kconfig index c24b6f7..235c7a2 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2030,13 +2030,6 @@ config INIT_ALL_POSSIBLE it was better to provide this option than to break all the archs and have several arch maintainers pursuing me down dark alleys. -config STOP_MACHINE - bool - default y - depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU - help - Need stop_machine() primitive. - source "block/Kconfig" config PREEMPT_NOTIFIERS diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 867bc20..a3bbaee 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -531,7 +531,7 @@ static int __init cpu_stop_init(void) } early_initcall(cpu_stop_init); -#ifdef CONFIG_STOP_MACHINE +#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus) { @@ -631,4 +631,4 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, return ret ?: done.ret; } -#endif /* CONFIG_STOP_MACHINE */ +#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ -- cgit v0.10.2 From 0d777df5d8953293be090d9ab5a355db893e8357 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Fri, 11 Dec 2015 13:40:49 -0800 Subject: mm: hugetlb: call huge_pte_alloc() only if ptep is null Currently at the beginning of hugetlb_fault(), we call huge_pte_offset() and check whether the obtained *ptep is a migration/hwpoison entry or not. And if not, then we get to call huge_pte_alloc(). This is racy because the *ptep could turn into migration/hwpoison entry after the huge_pte_offset() check. This race results in BUG_ON in huge_pte_alloc(). We don't have to call huge_pte_alloc() when the huge_pte_offset() returns non-NULL, so let's fix this bug with moving the code into else block. Note that the *ptep could turn into a migration/hwpoison entry after this block, but that's not a problem because we have another !pte_present check later (we never go into hugetlb_no_page() in that case.) Fixes: 290408d4a250 ("hugetlb: hugepage migration core") Signed-off-by: Naoya Horiguchi Acked-by: Hillf Danton Acked-by: David Rientjes Cc: Hugh Dickins Cc: Dave Hansen Cc: Mel Gorman Cc: Joonsoo Kim Cc: Mike Kravetz Cc: [2.6.36+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 4fe4340..9e3fa71 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3696,12 +3696,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) return VM_FAULT_HWPOISON_LARGE | VM_FAULT_SET_HINDEX(hstate_index(h)); + } else { + ptep = huge_pte_alloc(mm, address, huge_page_size(h)); + if (!ptep) + return VM_FAULT_OOM; } - ptep = huge_pte_alloc(mm, address, huge_page_size(h)); - if (!ptep) - return VM_FAULT_OOM; - mapping = vma->vm_file->f_mapping; idx = vma_hugecache_offset(h, vma, address); -- cgit v0.10.2 From dbe409e4f5e5075bd9ff7f8dd5c627abf3ee38c1 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Fri, 11 Dec 2015 13:40:52 -0800 Subject: mm/hugetlb.c: fix resv map memory leak for placeholder entries Dmitry Vyukov reported the following memory leak unreferenced object 0xffff88002eaafd88 (size 32): comm "a.out", pid 5063, jiffies 4295774645 (age 15.810s) hex dump (first 32 bytes): 28 e9 4e 63 00 88 ff ff 28 e9 4e 63 00 88 ff ff (.Nc....(.Nc.... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: kmalloc include/linux/slab.h:458 region_chg+0x2d4/0x6b0 mm/hugetlb.c:398 __vma_reservation_common+0x2c3/0x390 mm/hugetlb.c:1791 vma_needs_reservation mm/hugetlb.c:1813 alloc_huge_page+0x19e/0xc70 mm/hugetlb.c:1845 hugetlb_no_page mm/hugetlb.c:3543 hugetlb_fault+0x7a1/0x1250 mm/hugetlb.c:3717 follow_hugetlb_page+0x339/0xc70 mm/hugetlb.c:3880 __get_user_pages+0x542/0xf30 mm/gup.c:497 populate_vma_page_range+0xde/0x110 mm/gup.c:919 __mm_populate+0x1c7/0x310 mm/gup.c:969 do_mlock+0x291/0x360 mm/mlock.c:637 SYSC_mlock2 mm/mlock.c:658 SyS_mlock2+0x4b/0x70 mm/mlock.c:648 Dmitry identified a potential memory leak in the routine region_chg, where a region descriptor is not free'ed on an error path. However, the root cause for the above memory leak resides in region_del. In this specific case, a "placeholder" entry is created in region_chg. The associated page allocation fails, and the placeholder entry is left in the reserve map. This is "by design" as the entry should be deleted when the map is released. The bug is in the region_del routine which is used to delete entries within a specific range (and when the map is released). region_del did not handle the case where a placeholder entry exactly matched the start of the range range to be deleted. In this case, the entry would not be deleted and leaked. The fix is to take these special placeholder entries into account in region_del. The region_chg error path leak is also fixed. Fixes: feba16e25a57 ("mm/hugetlb: add region_del() to delete a specific range of entries") Signed-off-by: Mike Kravetz Reported-by: Dmitry Vyukov Acked-by: Hillf Danton Cc: [4.3+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 9e3fa71..ef6963b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -372,8 +372,10 @@ retry_locked: spin_unlock(&resv->lock); trg = kmalloc(sizeof(*trg), GFP_KERNEL); - if (!trg) + if (!trg) { + kfree(nrg); return -ENOMEM; + } spin_lock(&resv->lock); list_add(&trg->link, &resv->region_cache); @@ -483,8 +485,16 @@ static long region_del(struct resv_map *resv, long f, long t) retry: spin_lock(&resv->lock); list_for_each_entry_safe(rg, trg, head, link) { - if (rg->to <= f) + /* + * Skip regions before the range to be deleted. file_region + * ranges are normally of the form [from, to). However, there + * may be a "placeholder" entry in the map which is of the form + * (from, to) with from == to. Check for placeholder entries + * at the beginning of the range to be deleted. + */ + if (rg->to <= f && (rg->to != rg->from || rg->to != f)) continue; + if (rg->from >= t) break; -- cgit v0.10.2 From 267a4c76bbdb950688d3aeb020976c2918064584 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 11 Dec 2015 13:40:55 -0800 Subject: tmpfs: fix shmem_evict_inode() warnings on i_blocks Dmitry Vyukov provides a little program, autogenerated by syzkaller, which races a fault on a mapping of a sparse memfd object, against truncation of that object below the fault address: run repeatedly for a few minutes, it reliably generates shmem_evict_inode()'s WARN_ON(inode->i_blocks). (But there's nothing specific to memfd here, nor to the fstat which it happened to use to generate the fault: though that looked suspicious, since a shmem_recalc_inode() had been added there recently. The same problem can be reproduced with open+unlink in place of memfd_create, and with fstatfs in place of fstat.) v3.7 commit 0f3c42f522dc ("tmpfs: change final i_blocks BUG to WARNING") explains one cause of such a warning (a race with shmem_writepage to swap), and possible solutions; but we never took it further, and this syzkaller incident turns out to have a different cause. shmem_getpage_gfp()'s error recovery, when a freshly allocated page is then found to be beyond eof, looks plausible - decrementing the alloced count that was just before incremented - but in fact can go wrong, if a racing thread (the truncator, for example) gets its shmem_recalc_inode() in just after our delete_from_page_cache(). delete_from_page_cache() decrements nrpages, that shmem_recalc_inode() will balance the books by decrementing alloced itself, then our decrement of alloced take it one too low: leading to the WARNING when the object is finally evicted. Once the new page has been exposed in the page cache, shmem_getpage_gfp() must leave it to shmem_recalc_inode() itself to get the accounting right in all cases (and not fall through from "trunc:" to "decused:"). Adjust that error recovery block; and the reinitialization of info and sbinfo can be removed too. While we're here, fix shmem_writepage() to avoid the original issue: it will be safe against a racing shmem_recalc_inode(), if it merely increments swapped before the shmem_delete_from_page_cache() which decrements nrpages (but it must then do its own shmem_recalc_inode() before that, while still in balance, instead of after). (Aside: why do we shmem_recalc_inode() here in the swap path? Because its raison d'etre is to cope with clean sparse shmem pages being reclaimed behind our back: so here when swapping is a good place to look for that case.) But I've not now managed to reproduce this bug, even without the patch. I don't see why I didn't do that earlier: perhaps inhibited by the preference to eliminate shmem_recalc_inode() altogether. Driven by this incident, I do now have a patch to do so at last; but still want to sit on it for a bit, there's a couple of questions yet to be resolved. Signed-off-by: Hugh Dickins Reported-by: Dmitry Vyukov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index 9187eee..2afcdbb 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -843,14 +843,14 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) list_add_tail(&info->swaplist, &shmem_swaplist); if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) { - swap_shmem_alloc(swap); - shmem_delete_from_page_cache(page, swp_to_radix_entry(swap)); - spin_lock(&info->lock); - info->swapped++; shmem_recalc_inode(inode); + info->swapped++; spin_unlock(&info->lock); + swap_shmem_alloc(swap); + shmem_delete_from_page_cache(page, swp_to_radix_entry(swap)); + mutex_unlock(&shmem_swaplist_mutex); BUG_ON(page_mapped(page)); swap_writepage(page, wbc); @@ -1078,7 +1078,7 @@ repeat: if (sgp != SGP_WRITE && sgp != SGP_FALLOC && ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { error = -EINVAL; - goto failed; + goto unlock; } if (page && sgp == SGP_WRITE) @@ -1246,11 +1246,15 @@ clear: /* Perhaps the file has been truncated since we checked */ if (sgp != SGP_WRITE && sgp != SGP_FALLOC && ((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) { + if (alloced) { + ClearPageDirty(page); + delete_from_page_cache(page); + spin_lock(&info->lock); + shmem_recalc_inode(inode); + spin_unlock(&info->lock); + } error = -EINVAL; - if (alloced) - goto trunc; - else - goto failed; + goto unlock; } *pagep = page; return 0; @@ -1258,23 +1262,13 @@ clear: /* * Error recovery. */ -trunc: - info = SHMEM_I(inode); - ClearPageDirty(page); - delete_from_page_cache(page); - spin_lock(&info->lock); - info->alloced--; - inode->i_blocks -= BLOCKS_PER_PAGE; - spin_unlock(&info->lock); decused: - sbinfo = SHMEM_SB(inode->i_sb); if (sbinfo->max_blocks) percpu_counter_add(&sbinfo->used_blocks, -1); unacct: shmem_unacct_blocks(info->flags, 1); failed: - if (swap.val && error != -EINVAL && - !shmem_confirm_swap(mapping, index, swap)) + if (swap.val && !shmem_confirm_swap(mapping, index, swap)) error = -EEXIST; unlock: if (page) { -- cgit v0.10.2 From 26bbe7ef6d5cdc7ec08cba6d433fca4060f258f3 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Fri, 11 Dec 2015 13:40:57 -0800 Subject: drivers/base/memory.c: prohibit offlining of memory blocks with missing sections Commit bdee237c0343 ("x86: mm: Use 2GB memory block size on large-memory x86-64 systems") and 982792c782ef ("x86, mm: probe memory block size for generic x86 64bit") introduced large block sizes for x86. This made it possible to have multiple sections per memory block where previously, there was a only every one section per block. Since blocks consist of contiguous ranges of section, there can be holes in the blocks where sections are not present. If one attempts to offline such a block, a crash occurs since the code is not designed to deal with this. This patch is a quick fix to gaurd against the crash by not allowing blocks with non-present sections to be offlined. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=107781 Signed-off-by: Seth Jennings Reported-by: Andrew Banman Cc: Daniel J Blueman Cc: Yinghai Lu Cc: Greg KH Cc: Russ Anderson Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2804aed..25425d3 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -303,6 +303,10 @@ static int memory_subsys_offline(struct device *dev) if (mem->state == MEM_OFFLINE) return 0; + /* Can't offline block with non-present sections */ + if (mem->section_count != sections_per_block) + return -EINVAL; + return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); } -- cgit v0.10.2 From a2b829d95958da2025ef844c0f53ac15ad720fac Mon Sep 17 00:00:00 2001 From: Chen Jie Date: Fri, 11 Dec 2015 13:41:00 -0800 Subject: mm/oom_kill.c: avoid attempting to kill init sharing same memory It's possible that an oom killed victim shares an ->mm with the init process and thus oom_kill_process() would end up trying to kill init as well. This has been shown in practice: Out of memory: Kill process 9134 (init) score 3 or sacrifice child Killed process 9134 (init) total-vm:1868kB, anon-rss:84kB, file-rss:572kB Kill process 1 (init) sharing same memory ... Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000009 And this will result in a kernel panic. If a process is forked by init and selected for oom kill while still sharing init_mm, then it's likely this system is in a recoverable state. However, it's better not to try to kill init and allow the machine to panic due to unkillable processes. [rientjes@google.com: rewrote changelog] [akpm@linux-foundation.org: fix inverted test, per Ben] Signed-off-by: Chen Jie Signed-off-by: David Rientjes Acked-by: Michal Hocko Acked-by: Hillf Danton Cc: Ben Hutchings Cc: Li Zefan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index d13a339..c126809 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -608,6 +608,8 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p, continue; if (unlikely(p->flags & PF_KTHREAD)) continue; + if (is_global_init(p)) + continue; if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) continue; -- cgit v0.10.2 From 854ee2e944b4daf795e32562a7d2f9e90ab5a6a8 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Fri, 11 Dec 2015 13:41:03 -0800 Subject: ocfs2: fix SGID not inherited issue Commit 8f1eb48758aa ("ocfs2: fix umask ignored issue") introduced an issue, SGID of sub dir was not inherited from its parents dir. It is because SGID is set into "inode->i_mode" in ocfs2_get_init_inode(), but is overwritten by "mode" which don't have SGID set later. Fixes: 8f1eb48758aa ("ocfs2: fix umask ignored issue") Signed-off-by: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Acked-by: Srinivas Eeda Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index a03f6f4..3123408 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -367,13 +367,11 @@ static int ocfs2_mknod(struct inode *dir, goto leave; } - status = posix_acl_create(dir, &mode, &default_acl, &acl); + status = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); if (status) { mlog_errno(status); goto leave; } - /* update inode->i_mode after mask with "umask". */ - inode->i_mode = mode; handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb, S_ISDIR(mode), -- cgit v0.10.2 From 2d33fa1059da4c8e816627a688d950b613ec0474 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 11 Dec 2015 13:41:06 -0800 Subject: sh64: fix __NR_fgetxattr According to arch/sh/kernel/syscalls_64.S and common sense, __NR_fgetxattr has to be defined to 259, but it doesn't. Instead, it's defined to 269, which is of course used by another syscall, __NR_sched_setaffinity in this case. This bug was found by strace test suite. Signed-off-by: Dmitry V. Levin Acked-by: Geert Uytterhoeven Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h index e6820c8..47ebd5b 100644 --- a/arch/sh/include/uapi/asm/unistd_64.h +++ b/arch/sh/include/uapi/asm/unistd_64.h @@ -278,7 +278,7 @@ #define __NR_fsetxattr 256 #define __NR_getxattr 257 #define __NR_lgetxattr 258 -#define __NR_fgetxattr 269 +#define __NR_fgetxattr 259 #define __NR_listxattr 260 #define __NR_llistxattr 261 #define __NR_flistxattr 262 -- cgit v0.10.2 From 9530d0fe129c0197d5df13319ccefd08a827383b Mon Sep 17 00:00:00 2001 From: Qais Yousef Date: Fri, 11 Dec 2015 13:41:09 -0800 Subject: MIPS: fix DMA contiguous allocation Recent changes to how GFP_ATOMIC is defined seems to have broken the condition to use mips_alloc_from_contiguous() in mips_dma_alloc_coherent(). I couldn't bottom out the exact change but I think it's this commit d0164adc89f6 ("mm, page_alloc: distinguish between being unable to sleep, unwilling to sleep and avoiding waking kswapd"). GFP_ATOMIC has multiple bits set and the check for !(gfp & GFP_ATOMIC) isn't enough. The reason behind this condition is to check whether we can potentially do a sleeping memory allocation. Use gfpflags_allow_blocking() instead which should be more robust. Signed-off-by: Qais Yousef Acked-by: Mel Gorman Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index d8117be..730d394 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -145,7 +145,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, gfp = massage_gfp_flags(dev, gfp); - if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC)) + if (IS_ENABLED(CONFIG_DMA_CMA) && gfpflags_allow_blocking(gfp)) page = dma_alloc_from_contiguous(dev, count, get_order(size)); if (!page) -- cgit v0.10.2 From dfd01f026058a59a513f8a365b439a0681b803af Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 13 Dec 2015 22:11:16 +0100 Subject: sched/wait: Fix the signal handling fix Jan Stancek reported that I wrecked things for him by fixing things for Vladimir :/ His report was due to an UNINTERRUPTIBLE wait getting -EINTR, which should not be possible, however my previous patch made this possible by unconditionally checking signal_pending(). We cannot use current->state as was done previously, because the instruction after the store to that variable it can be changed. We must instead pass the initial state along and use that. Fixes: 68985633bccb ("sched/wait: Fix signal handling in bit wait helpers") Reported-by: Jan Stancek Reported-by: Chris Mason Tested-by: Jan Stancek Tested-by: Vladimir Murzin Tested-by: Chris Mason Reviewed-by: Paul Turner Cc: Ingo Molnar Cc: tglx@linutronix.de Cc: Oleg Nesterov Cc: hpa@zytor.com Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Linus Torvalds diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6b66dd5..a329f5b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1831,11 +1831,11 @@ cifs_invalidate_mapping(struct inode *inode) * @word: long word containing the bit lock */ static int -cifs_wait_bit_killable(struct wait_bit_key *key) +cifs_wait_bit_killable(struct wait_bit_key *key, int mode) { - if (fatal_signal_pending(current)) - return -ERESTARTSYS; freezable_schedule_unsafe(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; return 0; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 31b0a52..c7e8b87 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -75,11 +75,11 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks * @word: long word containing the bit lock */ -int nfs_wait_bit_killable(struct wait_bit_key *key) +int nfs_wait_bit_killable(struct wait_bit_key *key, int mode) { - if (fatal_signal_pending(current)) - return -ERESTARTSYS; freezable_schedule_unsafe(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; return 0; } EXPORT_SYMBOL_GPL(nfs_wait_bit_killable); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 56cfde2..9dea85f 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -379,7 +379,7 @@ extern int nfs_drop_inode(struct inode *); extern void nfs_clear_inode(struct inode *); extern void nfs_evict_inode(struct inode *); void nfs_zap_acl_cache(struct inode *inode); -extern int nfs_wait_bit_killable(struct wait_bit_key *key); +extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode); /* super.c */ extern const struct super_operations nfs_sops; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index fe3ddd2..452a011 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -129,7 +129,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c) set_bit(NFS_IO_INPROGRESS, &c->flags); if (atomic_read(&c->io_count) == 0) break; - ret = nfs_wait_bit_killable(&q.key); + ret = nfs_wait_bit_killable(&q.key, TASK_KILLABLE); } while (atomic_read(&c->io_count) != 0 && !ret); finish_wait(wq, &q.wait); return ret; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 5a8ae21..bec0384 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1466,11 +1466,11 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx, } /* stop waiting if someone clears NFS_LAYOUT_RETRY_LAYOUTGET bit. */ -static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key) +static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key, int mode) { if (!test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, key->flags)) return 1; - return nfs_wait_bit_killable(key); + return nfs_wait_bit_killable(key, mode); } static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo) diff --git a/include/linux/wait.h b/include/linux/wait.h index 1e1bf9f..513b36f 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -145,7 +145,7 @@ __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) list_del(&old->task_list); } -typedef int wait_bit_action_f(struct wait_bit_key *); +typedef int wait_bit_action_f(struct wait_bit_key *, int mode); void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key); void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key); void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key); @@ -960,10 +960,10 @@ int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key); } while (0) -extern int bit_wait(struct wait_bit_key *); -extern int bit_wait_io(struct wait_bit_key *); -extern int bit_wait_timeout(struct wait_bit_key *); -extern int bit_wait_io_timeout(struct wait_bit_key *); +extern int bit_wait(struct wait_bit_key *, int); +extern int bit_wait_io(struct wait_bit_key *, int); +extern int bit_wait_timeout(struct wait_bit_key *, int); +extern int bit_wait_io_timeout(struct wait_bit_key *, int); /** * wait_on_bit - wait for a bit to be cleared diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index f10bd87..f15d6b6 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -392,7 +392,7 @@ __wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q, do { prepare_to_wait(wq, &q->wait, mode); if (test_bit(q->key.bit_nr, q->key.flags)) - ret = (*action)(&q->key); + ret = (*action)(&q->key, mode); } while (test_bit(q->key.bit_nr, q->key.flags) && !ret); finish_wait(wq, &q->wait); return ret; @@ -431,7 +431,7 @@ __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q, prepare_to_wait_exclusive(wq, &q->wait, mode); if (!test_bit(q->key.bit_nr, q->key.flags)) continue; - ret = action(&q->key); + ret = action(&q->key, mode); if (!ret) continue; abort_exclusive_wait(wq, &q->wait, mode, &q->key); @@ -581,43 +581,43 @@ void wake_up_atomic_t(atomic_t *p) } EXPORT_SYMBOL(wake_up_atomic_t); -__sched int bit_wait(struct wait_bit_key *word) +__sched int bit_wait(struct wait_bit_key *word, int mode) { schedule(); - if (signal_pending(current)) + if (signal_pending_state(mode, current)) return -EINTR; return 0; } EXPORT_SYMBOL(bit_wait); -__sched int bit_wait_io(struct wait_bit_key *word) +__sched int bit_wait_io(struct wait_bit_key *word, int mode) { io_schedule(); - if (signal_pending(current)) + if (signal_pending_state(mode, current)) return -EINTR; return 0; } EXPORT_SYMBOL(bit_wait_io); -__sched int bit_wait_timeout(struct wait_bit_key *word) +__sched int bit_wait_timeout(struct wait_bit_key *word, int mode) { unsigned long now = READ_ONCE(jiffies); if (time_after_eq(now, word->timeout)) return -EAGAIN; schedule_timeout(word->timeout - now); - if (signal_pending(current)) + if (signal_pending_state(mode, current)) return -EINTR; return 0; } EXPORT_SYMBOL_GPL(bit_wait_timeout); -__sched int bit_wait_io_timeout(struct wait_bit_key *word) +__sched int bit_wait_io_timeout(struct wait_bit_key *word, int mode) { unsigned long now = READ_ONCE(jiffies); if (time_after_eq(now, word->timeout)) return -EAGAIN; io_schedule_timeout(word->timeout - now); - if (signal_pending(current)) + if (signal_pending_state(mode, current)) return -EINTR; return 0; } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f14f24e..73ad57a 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -250,11 +250,11 @@ void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) } EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); -static int rpc_wait_bit_killable(struct wait_bit_key *key) +static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) { - if (fatal_signal_pending(current)) - return -ERESTARTSYS; freezable_schedule_unsafe(); + if (signal_pending_state(mode, current)) + return -ERESTARTSYS; return 0; } -- cgit v0.10.2 From 9f9499ae8e6415cefc4fe0a96ad0e27864353c89 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 13 Dec 2015 17:42:58 -0800 Subject: Linux 4.4-rc5 diff --git a/Makefile b/Makefile index d644f6e..bc0165d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Blurry Fish Butt # *DOCUMENTATION* -- cgit v0.10.2