From 9fdd04918a452980631ecc499317881c1d120b70 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Fri, 23 Apr 2021 00:02:13 -0400 Subject: net: ieee802154: fix null deref in parse dev addr Fix a logic error that could result in a null deref if the user sets the mode incorrectly for the given addr type. Signed-off-by: Dan Robertson Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20210423040214.15438-2-dan@dlrobertson.com Signed-off-by: Stefan Schmidt --- net/ieee802154/nl802154.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 05f6bd89a7dd..0cf2374c143b 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1298,19 +1298,20 @@ ieee802154_llsec_parse_dev_addr(struct nlattr *nla, if (!nla || nla_parse_nested_deprecated(attrs, NL802154_DEV_ADDR_ATTR_MAX, nla, nl802154_dev_addr_policy, NULL)) return -EINVAL; - if (!attrs[NL802154_DEV_ADDR_ATTR_PAN_ID] || - !attrs[NL802154_DEV_ADDR_ATTR_MODE] || - !(attrs[NL802154_DEV_ADDR_ATTR_SHORT] || - attrs[NL802154_DEV_ADDR_ATTR_EXTENDED])) + if (!attrs[NL802154_DEV_ADDR_ATTR_PAN_ID] || !attrs[NL802154_DEV_ADDR_ATTR_MODE]) return -EINVAL; addr->pan_id = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_PAN_ID]); addr->mode = nla_get_u32(attrs[NL802154_DEV_ADDR_ATTR_MODE]); switch (addr->mode) { case NL802154_DEV_ADDR_SHORT: + if (!attrs[NL802154_DEV_ADDR_ATTR_SHORT]) + return -EINVAL; addr->short_addr = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_SHORT]); break; case NL802154_DEV_ADDR_EXTENDED: + if (!attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]) + return -EINVAL; addr->extended_addr = nla_get_le64(attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]); break; default: -- cgit v1.2.3 From 6c9762a78c325107dc37d20ee21002b841679209 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 23 Apr 2021 15:54:02 +0200 Subject: ASoC: max98088: fix ni clock divider calculation The ni1/ni2 ratio formula [1] uses the pclk which is the prescaled mclk. The max98088 datasheet [2] has no such formula but table-12 equals so we can assume that it is the same for both devices. While on it make use of DIV_ROUND_CLOSEST_ULL(). [1] https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf; page 86 [2] https://datasheets.maximintegrated.com/en/ds/MAX98088.pdf; page 82 Signed-off-by: Marco Felsch Link: https://lore.kernel.org/r/20210423135402.32105-1-m.felsch@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 4be24e7f51c8..f8e49e45ce33 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -41,6 +41,7 @@ struct max98088_priv { enum max98088_type devtype; struct max98088_pdata *pdata; struct clk *mclk; + unsigned char mclk_prescaler; unsigned int sysclk; struct max98088_cdata dai[2]; int eq_textcnt; @@ -998,13 +999,16 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream, /* Configure NI when operating as master */ if (snd_soc_component_read(component, M98088_REG_14_DAI1_FORMAT) & M98088_DAI_MAS) { + unsigned long pclk; + if (max98088->sysclk == 0) { dev_err(component->dev, "Invalid system clock frequency\n"); return -EINVAL; } ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL) * (unsigned long long int)rate; - do_div(ni, (unsigned long long int)max98088->sysclk); + pclk = DIV_ROUND_CLOSEST(max98088->sysclk, max98088->mclk_prescaler); + ni = DIV_ROUND_CLOSEST_ULL(ni, pclk); snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI, (ni >> 8) & 0x7F); snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO, @@ -1065,13 +1069,16 @@ static int max98088_dai2_hw_params(struct snd_pcm_substream *substream, /* Configure NI when operating as master */ if (snd_soc_component_read(component, M98088_REG_1C_DAI2_FORMAT) & M98088_DAI_MAS) { + unsigned long pclk; + if (max98088->sysclk == 0) { dev_err(component->dev, "Invalid system clock frequency\n"); return -EINVAL; } ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL) * (unsigned long long int)rate; - do_div(ni, (unsigned long long int)max98088->sysclk); + pclk = DIV_ROUND_CLOSEST(max98088->sysclk, max98088->mclk_prescaler); + ni = DIV_ROUND_CLOSEST_ULL(ni, pclk); snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI, (ni >> 8) & 0x7F); snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO, @@ -1113,8 +1120,10 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, */ if ((freq >= 10000000) && (freq < 20000000)) { snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x10); + max98088->mclk_prescaler = 1; } else if ((freq >= 20000000) && (freq < 30000000)) { snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x20); + max98088->mclk_prescaler = 2; } else { dev_err(component->dev, "Invalid master clock frequency\n"); return -EINVAL; -- cgit v1.2.3 From a0695853e5906a9558eef9f79856e07659b7a1e6 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 28 Apr 2021 14:26:31 +0200 Subject: ASoC: stm32: do not request a new clock consummer reference This reverts commit 65d1cce726d4912793d0a84c55ecdb0ef5832130. There is problem with clk_hw_get_hw(). Using it pins the clock provider to itself, making it impossible to remove the module. Revert commit 65d1cce726d4 ("ASoC: stm32: properly get clk from the provider") until this gets sorted out. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210428122632.46244-2-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index c1561237ee24..3aa1cf262402 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -484,10 +484,7 @@ static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) dev_err(dev, "mclk register returned %d\n", ret); return ret; } - - sai->sai_mclk = devm_clk_hw_get_clk(dev, hw, NULL); - if (IS_ERR(sai->sai_mclk)) - return PTR_ERR(sai->sai_mclk); + sai->sai_mclk = hw->clk; /* register mclk provider */ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); -- cgit v1.2.3 From 97c733654ab4a5ac910216b4b74e605acf3e1cce Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 28 Apr 2021 14:26:32 +0200 Subject: ASoC: da7219: do not request a new clock consummer reference This reverts commit 12f8127fe9e6154dd4197df97e44f3fd67583071. There is problem with clk_hw_get_hw(). Using it pins the clock provider to itself, making it impossible to remove the module. Revert commit 12f8127fe9e6 ("ASoC: da7219: properly get clk from the provider") until this gets sorted out. Reported-by: Pierre-Louis Bossart Signed-off-by: Jerome Brunet Tested-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210428122632.46244-3-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index bd3c523a8617..13009d08b09a 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2181,10 +2181,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) ret); goto err; } - - da7219->dai_clks[i] = devm_clk_hw_get_clk(dev, dai_clk_hw, NULL); - if (IS_ERR(da7219->dai_clks[i])) - return PTR_ERR(da7219->dai_clks[i]); + da7219->dai_clks[i] = dai_clk_hw->clk; /* For DT setup onecell data, otherwise create lookup */ if (np) { -- cgit v1.2.3 From 6879e8e759bf9e05eaee85e32ca1a936e6b46da1 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 28 Apr 2021 01:53:31 +0530 Subject: ASoC: amd: fix for pcm_read() error Below phython script throwing pcm_read() error. import subprocess p = subprocess.Popen(["aplay -t raw -D plughw:1,0 /dev/zero"], shell=True) subprocess.call(["arecord -Dhw:1,0 --dump-hw-params"], shell=True) subprocess.call(["arecord -Dhw:1,0 -fdat -d1 /dev/null"], shell=True) p.kill() Handling ACP global external interrupt enable register causing this issue. This register got updated wrongly when there is active stream causing interrupts disabled for active stream. Refactored code to handle enabling and disabling external interrupts. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1619555017-29858-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-pcm-dma.c | 10 ---------- sound/soc/amd/raven/acp3x.h | 1 + sound/soc/amd/raven/pci-acp3x.c | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 417cda24030c..2447a1e6e913 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -237,10 +237,6 @@ static int acp3x_dma_open(struct snd_soc_component *component, return ret; } - if (!adata->play_stream && !adata->capture_stream && - !adata->i2ssp_play_stream && !adata->i2ssp_capture_stream) - rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); - i2s_data->acp3x_base = adata->acp3x_base; runtime->private_data = i2s_data; return ret; @@ -367,12 +363,6 @@ static int acp3x_dma_close(struct snd_soc_component *component, } } - /* Disable ACP irq, when the current stream is being closed and - * another stream is also not active. - */ - if (!adata->play_stream && !adata->capture_stream && - !adata->i2ssp_play_stream && !adata->i2ssp_capture_stream) - rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); return 0; } diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h index 03fe93913e12..c3f0c8b7545d 100644 --- a/sound/soc/amd/raven/acp3x.h +++ b/sound/soc/amd/raven/acp3x.h @@ -77,6 +77,7 @@ #define ACP_POWER_OFF_IN_PROGRESS 0x03 #define ACP3x_ITER_IRER_SAMP_LEN_MASK 0x38 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF struct acp3x_platform_info { u16 play_i2s_instance; diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index d3536fd6a124..a013a607b3d4 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -76,6 +76,19 @@ static int acp3x_reset(void __iomem *acp3x_base) return -ETIMEDOUT; } +static void acp3x_enable_interrupts(void __iomem *acp_base) +{ + rv_writel(0x01, acp_base + mmACP_EXTERNAL_INTR_ENB); +} + +static void acp3x_disable_interrupts(void __iomem *acp_base) +{ + rv_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + + mmACP_EXTERNAL_INTR_STAT); + rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_CNTL); + rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_ENB); +} + static int acp3x_init(struct acp3x_dev_data *adata) { void __iomem *acp3x_base = adata->acp3x_base; @@ -93,6 +106,7 @@ static int acp3x_init(struct acp3x_dev_data *adata) pr_err("ACP3x reset failed\n"); return ret; } + acp3x_enable_interrupts(acp3x_base); return 0; } @@ -100,6 +114,7 @@ static int acp3x_deinit(void __iomem *acp3x_base) { int ret; + acp3x_disable_interrupts(acp3x_base); /* Reset */ ret = acp3x_reset(acp3x_base); if (ret) { -- cgit v1.2.3 From c7299fea67696db5bd09d924d1f1080d894f92ef Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 26 Apr 2021 16:56:38 -0700 Subject: spi: Fix spi device unregister flow When an SPI device is unregistered, the spi->controller->cleanup() is called in the device's release callback. That's wrong for a couple of reasons: 1. spi_dev_put() can be called before spi_add_device() is called. And it's spi_add_device() that calls spi_setup(). This will cause clean() to get called without the spi device ever being setup. 2. There's no guarantee that the controller's driver would be present by the time the spi device's release function gets called. 3. It also causes "sleeping in atomic context" stack dump[1] when device link deletion code does a put_device() on the spi device. Fix these issues by simply moving the cleanup from the device release callback to the actual spi_unregister_device() function. [1] - https://lore.kernel.org/lkml/CAHp75Vc=FCGcUyS0v6fnxme2YJ+qD+Y-hQDQLa2JhWNON9VmsQ@mail.gmail.com/ Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20210426235638.1285530-1-saravanak@google.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ba425b9c7700..f9885c096563 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -47,10 +47,6 @@ static void spidev_release(struct device *dev) { struct spi_device *spi = to_spi_device(dev); - /* spi controllers may cleanup for released devices */ - if (spi->controller->cleanup) - spi->controller->cleanup(spi); - spi_controller_put(spi->controller); kfree(spi->driver_override); kfree(spi); @@ -558,6 +554,12 @@ static int spi_dev_check(struct device *dev, void *data) return 0; } +static void spi_cleanup(struct spi_device *spi) +{ + if (spi->controller->cleanup) + spi->controller->cleanup(spi); +} + /** * spi_add_device - Add spi_device allocated with spi_alloc_device * @spi: spi_device to register @@ -622,11 +624,13 @@ int spi_add_device(struct spi_device *spi) /* Device may be bound to an active driver when this returns */ status = device_add(&spi->dev); - if (status < 0) + if (status < 0) { dev_err(dev, "can't add %s, status %d\n", dev_name(&spi->dev), status); - else + spi_cleanup(spi); + } else { dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev)); + } done: mutex_unlock(&spi_add_lock); @@ -710,6 +714,8 @@ void spi_unregister_device(struct spi_device *spi) if (!spi) return; + spi_cleanup(spi); + if (spi->dev.of_node) { of_node_clear_flag(spi->dev.of_node, OF_POPULATED); of_node_put(spi->dev.of_node); -- cgit v1.2.3 From 41f48a29ebd5ce944e412f491f1876b5abeff1d6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 27 Apr 2021 16:38:42 +0200 Subject: spi: altera: Make SPI_ALTERA_CORE invisible The SPI_ALTERA_CORE config symbol controls compilation of the Altera SPI Controller core code. It is already selected by all of its users, so there is no reason to make it visible, unless compile-testing. Fixes: b0c3d9354de1f87e ("spi: altera: separate core code from platform code") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/f0cb8e66baba4506db6f42fca74dc51b76883507.1619534253.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8b161ec4943b..f4481fe48bf0 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -65,7 +65,7 @@ config SPI_ALTERA This is the driver for the Altera SPI Controller. config SPI_ALTERA_CORE - tristate "Altera SPI Controller core code" + tristate "Altera SPI Controller core code" if COMPILE_TEST select REGMAP help "The core code for the Altera SPI Controller" -- cgit v1.2.3 From 121271f08809e5dc01d15d3e529988ac5d740af6 Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Wed, 28 Apr 2021 23:38:01 -0600 Subject: spi: spi-zynq-qspi: Fix kernel-doc warning Fix kernel-doc warning. Signed-off-by: Amit Kumar Mahapatra Link: https://lore.kernel.org/r/20210429053802.17650-2-amit.kumar-mahapatra@xilinx.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 5d8a5ee62fa2..1acde9e24973 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -367,7 +367,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi) } /** - * zynq_qspi_setup - Configure the QSPI controller + * zynq_qspi_setup_op - Configure the QSPI controller * @spi: Pointer to the spi_device structure * * Sets the operational mode of QSPI controller for the next QSPI transfer, baud -- cgit v1.2.3 From 6d5ff8e632a4f2389c331e5554cd1c2a9a28c7aa Mon Sep 17 00:00:00 2001 From: Karen Dombroski Date: Wed, 28 Apr 2021 23:38:02 -0600 Subject: spi: spi-zynq-qspi: Fix stack violation bug When the number of bytes for the op is greater than one, the read could run off the end of the function stack and cause a crash. This patch restores the behaviour of safely reading out of the original opcode location. Signed-off-by: Karen Dombroski Signed-off-by: Amit Kumar Mahapatra Link: https://lore.kernel.org/r/20210429053802.17650-3-amit.kumar-mahapatra@xilinx.com Signed-off-by: Mark Brown --- drivers/spi/spi-zynq-qspi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 1acde9e24973..5a3d81c31d04 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -528,18 +528,17 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master); int err = 0, i; u8 *tmpbuf; - u8 opcode = op->cmd.opcode; dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n", - opcode, op->cmd.buswidth, op->addr.buswidth, + op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, op->dummy.buswidth, op->data.buswidth); zynq_qspi_chipselect(mem->spi, true); zynq_qspi_config_op(xqspi, mem->spi); - if (op->cmd.nbytes) { + if (op->cmd.opcode) { reinit_completion(&xqspi->data_completion); - xqspi->txbuf = &opcode; + xqspi->txbuf = (u8 *)&op->cmd.opcode; xqspi->rxbuf = NULL; xqspi->tx_bytes = op->cmd.nbytes; xqspi->rx_bytes = op->cmd.nbytes; -- cgit v1.2.3 From 6a01268687c8d00e59dff341c519a337de980d2e Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Sun, 7 Feb 2021 13:47:04 -0500 Subject: HID: semitek: new driver for GK6X series keyboards A number of USB keyboards, using the Semitek firmware, are capable of handling arbitrary N-key rollover, but due to a buggy report descriptor, keys beyond the sixth cannot be detected by the generic HID driver. There are numerous hardware variants sold by several vendors, mostly using generic names like "GK61" for the 61-key version. These keyboards are sometimes known collectively as the "GK6X" series. The keyboard has three USB interfaces. Interface 0 uses the standard HID boot protocol, limited to eight modifier keys and six normal keys; interface 2 uses a custom report format that permits any number of keys. If more than six keys are pressed simultaneously, the first six are reported via interface 0 while subsequent keys are reported via interface 2. (Interface 1 uses a custom protocol for reprogramming the keyboard; this can be controlled through userspace tools and is not of concern for the present driver.) The report descriptor for interface 2, however, is incorrect (for report ID 0x04, the input field is marked as "array" rather than "variable".) The descriptor appears to be correct in other respects, so we simply replace the incorrect byte before parsing the descriptor. Signed-off-by: Benjamin Moody Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 15 +++++++++++++++ drivers/hid/Makefile | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-semitek.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 drivers/hid/hid-semitek.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4bf263c2d61a..5756203af068 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -922,6 +922,21 @@ config HID_SAMSUNG help Support for Samsung InfraRed remote control or keyboards. +config HID_SEMITEK + tristate "Semitek USB keyboards" + depends on HID + help + Support for Semitek USB keyboards that are not fully compliant + with the HID standard. + + There are many variants, including: + - GK61, GK64, GK68, GK84, GK96, etc. + - SK61, SK64, SK68, SK84, SK96, etc. + - Dierya DK61/DK66 + - Tronsmart TK09R + - Woo-dy + - X-Bows Nature/Knight + config HID_SONY tristate "Sony PS2/3/4 accessories" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 193431ec4db8..1ea1a7c0b20f 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ obj-$(CONFIG_HID_RMI) += hid-rmi.o obj-$(CONFIG_HID_SAITEK) += hid-saitek.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o +obj-$(CONFIG_HID_SEMITEK) += hid-semitek.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 84b8da3e7d09..e0d8dab18a7d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1060,6 +1060,9 @@ #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023 #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD2 0x0027 +#define USB_VENDOR_ID_SEMITEK 0x1ea7 +#define USB_DEVICE_ID_SEMITEK_KEYBOARD 0x0907 + #define USB_VENDOR_ID_SENNHEISER 0x1395 #define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c diff --git a/drivers/hid/hid-semitek.c b/drivers/hid/hid-semitek.c new file mode 100644 index 000000000000..ba6607d5e051 --- /dev/null +++ b/drivers/hid/hid-semitek.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for Semitek keyboards + * + * Copyright (c) 2021 Benjamin Moody + */ + +#include +#include +#include + +#include "hid-ids.h" + +static __u8 *semitek_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* In the report descriptor for interface 2, fix the incorrect + description of report ID 0x04 (the report contains a + bitmask, not an array of keycodes.) */ + if (*rsize == 0xcb && rdesc[0x83] == 0x81 && rdesc[0x84] == 0x00) { + hid_info(hdev, "fixing up Semitek report descriptor\n"); + rdesc[0x84] = 0x02; + } + return rdesc; +} + +static const struct hid_device_id semitek_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SEMITEK, USB_DEVICE_ID_SEMITEK_KEYBOARD) }, + { } +}; +MODULE_DEVICE_TABLE(hid, semitek_devices); + +static struct hid_driver semitek_driver = { + .name = "semitek", + .id_table = semitek_devices, + .report_fixup = semitek_report_fixup, +}; +module_hid_driver(semitek_driver); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4bfb2c72b2bfca8684c2f5c25a3119bad016a9d3 Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Fri, 19 Feb 2021 10:38:46 +1300 Subject: HID: asus: Filter keyboard EC for old ROG keyboard Older ROG keyboards emit a similar stream of bytes to the new N-Key keyboards and require filtering to prevent a lot of unmapped key warnings showing. As all the ROG keyboards use QUIRK_USE_KBD_BACKLIGHT this is now used to branch to filtering in asus_raw_event. Signed-off-by: Luke D Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 2ab22b925941..1ed1c05c3d54 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -335,7 +335,7 @@ static int asus_raw_event(struct hid_device *hdev, if (drvdata->quirks & QUIRK_MEDION_E1239T) return asus_e1239t_event(drvdata, data, size); - if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) { /* * Skip these report ID, the device emits a continuous stream associated * with the AURA mode it is in which looks like an 'echo'. -- cgit v1.2.3 From 25bdbfbb2d8331a67824dd03d0087e9c98835f3a Mon Sep 17 00:00:00 2001 From: Nirenjan Krishnan Date: Mon, 29 Mar 2021 09:10:02 -0700 Subject: HID: quirks: Set INCREMENT_USAGE_ON_DUPLICATE for Saitek X65 The Saitek X65 joystick has a pair of axes that were used as mouse pointer controls by the Windows driver. The corresponding usage page is the Game Controls page, which is not recognized by the generic HID driver, and therefore, both axes get mapped to ABS_MISC. The quirk makes the second axis get mapped to ABS_MISC+1, and therefore made available separately. Signed-off-by: Nirenjan Krishnan Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e0d8dab18a7d..7601ec19ab28 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1051,6 +1051,7 @@ #define USB_DEVICE_ID_SAITEK_X52 0x075c #define USB_DEVICE_ID_SAITEK_X52_2 0x0255 #define USB_DEVICE_ID_SAITEK_X52_PRO 0x0762 +#define USB_DEVICE_ID_SAITEK_X65 0x0b6a #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 3dd6f15f2a67..152c6aab11b5 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -158,6 +158,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, -- cgit v1.2.3 From ed1ab6ff213a701d4a635883c63e0d6fcbbab27d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 2 Apr 2021 09:40:41 +0000 Subject: HID: thrustmaster: fix return value check in thrustmaster_probe() Fix the return value check which testing the wrong variable in thrustmaster_probe(). Fixes: c49c33637802 ("HID: support for initialization of some Thrustmaster wheels") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: Jiri Kosina --- drivers/hid/hid-thrustmaster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c index 2e452c6e8ef4..f643b1cb112d 100644 --- a/drivers/hid/hid-thrustmaster.c +++ b/drivers/hid/hid-thrustmaster.c @@ -312,7 +312,7 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i } tm_wheel->change_request = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!tm_wheel->model_request) { + if (!tm_wheel->change_request) { ret = -ENOMEM; goto error5; } -- cgit v1.2.3 From ed80bdc4571fae177c44eba0997a0d551fc21e15 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Apr 2021 17:40:54 +0200 Subject: HID: quirks: Add HID_QUIRK_NO_INIT_REPORTS quirk for Dell K15A keyboard-dock Just like the K12A the Dell K15A keyboard-dock has problems with get_feature requests. This sometimes leads to several "failed to fetch feature 8" messages getting logged, after which the touchpad may or may not work. Just like the K15A these errors are triggered by undocking and docking the tablet. There also seem to be other problems when undocking and then docking again in quick succession. It seems that in this case the keyboard-controller still retains some power from capacitors and does not go through a power-on-reset leaving it in a confuses state, symptoms of this are: 1. The USB-ids changing to 048d:8910 2. Failure to read the HID descriptors on the second (mouse) USB intf. 3. The touchpad freezing after a while These problems can all be cleared by undocking the keyboard and waiting a full minute before redocking it. Unfortunately there is nothing we can do about this in the kernel. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7601ec19ab28..c6a6c8f54795 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1165,6 +1165,7 @@ #define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819 #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 +#define USB_DEVICE_ID_SYNAPTICS_DELL_K15A 0x6e21 #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4 #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5 #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 152c6aab11b5..fc6173a91af5 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -177,6 +177,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K15A), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD), HID_QUIRK_BADPAD }, { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET }, -- cgit v1.2.3 From 9858c74c29e12be5886280725e781cb735b2aca6 Mon Sep 17 00:00:00 2001 From: Mateusz Jończyk Date: Tue, 6 Apr 2021 20:25:38 +0200 Subject: HID: a4tech: use A4_2WHEEL_MOUSE_HACK_B8 for A4TECH NB-95 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This mouse has a horizontal wheel that requires special handling. Without this patch, the horizontal wheel acts like a vertical wheel. In the output of `hidrd-convert` for this mouse, there is a `Usage (B8h)` field. It corresponds to a byte in packets sent by the device that specifies which wheel generated an input event. The name "A4TECH" is spelled in all capitals on the company website. Signed-off-by: Mateusz Jończyk Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 4 ++-- drivers/hid/hid-a4tech.c | 2 ++ drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 5756203af068..160554903ef9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -93,11 +93,11 @@ menu "Special HID drivers" depends on HID config HID_A4TECH - tristate "A4 tech mice" + tristate "A4TECH mice" depends on HID default !EXPERT help - Support for A4 tech X5 and WOP-35 / Trust 450L mice. + Support for some A4TECH mice with two scroll wheels. config HID_ACCUTOUCH tristate "Accutouch touch device" diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 3a8c4a5971f7..2cbc32dda7f7 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c @@ -147,6 +147,8 @@ static const struct hid_device_id a4_devices[] = { .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649), .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_NB_95), + .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, { } }; MODULE_DEVICE_TABLE(hid, a4_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c6a6c8f54795..933b0ed9d3ed 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -26,6 +26,7 @@ #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_X5_005D 0x000a #define USB_DEVICE_ID_A4TECH_RP_649 0x001a +#define USB_DEVICE_ID_A4TECH_NB_95 0x022b #define USB_VENDOR_ID_AASHIMA 0x06d6 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index fc6173a91af5..d2933f2ffec5 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -213,6 +213,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_NB_95) }, #endif #if IS_ENABLED(CONFIG_HID_ACCUTOUCH) { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) }, -- cgit v1.2.3 From 7b229b13d78d112e2c5d4a60a3c6f602289959fa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Apr 2021 19:56:05 -0700 Subject: HID: hid-input: add mapping for emoji picker key HUTRR101 added a new usage code for a key that is supposed to invoke and dismiss an emoji picker widget to assist users to locate and enter emojis. This patch adds a new key definition KEY_EMOJI_PICKER and maps 0x0c/0x0d9 usage code to this new keycode. Additionally hid-debug is adjusted to recognize this new usage code as well. Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 1 + drivers/hid/hid-input.c | 3 +++ include/uapi/linux/input-event-codes.h | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 59f8d716d78f..75a59e41724d 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -930,6 +930,7 @@ static const char *keys[KEY_MAX + 1] = { [KEY_APPSELECT] = "AppSelect", [KEY_SCREENSAVER] = "ScreenSaver", [KEY_VOICECOMMAND] = "VoiceCommand", + [KEY_EMOJI_PICKER] = "EmojiPicker", [KEY_BRIGHTNESS_MIN] = "BrightnessMin", [KEY_BRIGHTNESS_MAX] = "BrightnessMax", [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 18f5e28d475c..abbfa91e73e4 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -964,6 +964,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; + + case 0x0d9: map_key_clear(KEY_EMOJI_PICKER); break; + case 0x0e0: map_abs_clear(ABS_VOLUME); break; case 0x0e2: map_key_clear(KEY_MUTE); break; case 0x0e5: map_key_clear(KEY_BASSBOOST); break; diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index ee93428ced9a..225ec87d4f22 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -611,6 +611,7 @@ #define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ #define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */ #define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */ +#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ -- cgit v1.2.3 From 0f0fb3d27e5ba51e40f2af4288efeaf3d293ef1a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Apr 2021 19:56:06 -0700 Subject: HID: hid-debug: recognize KEY_ASSISTANT and KEY_KBD_LAYOUT_NEXT Add missing descriptions for KEY_ASSISTANT and KEY_KBD_LAYOUT_NEXT. Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 75a59e41724d..a311fb87b02a 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -930,6 +930,8 @@ static const char *keys[KEY_MAX + 1] = { [KEY_APPSELECT] = "AppSelect", [KEY_SCREENSAVER] = "ScreenSaver", [KEY_VOICECOMMAND] = "VoiceCommand", + [KEY_ASSISTANT] = "Assistant", + [KEY_KBD_LAYOUT_NEXT] = "KbdLayoutNext", [KEY_EMOJI_PICKER] = "EmojiPicker", [KEY_BRIGHTNESS_MIN] = "BrightnessMin", [KEY_BRIGHTNESS_MAX] = "BrightnessMax", -- cgit v1.2.3 From b0d713c60c75cdd04bf8ad8cfb046c8530709de3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 11 Apr 2021 13:34:02 +0200 Subject: HID: surface-hid: Fix integer endian conversion We want to convert from 16 bit (unsigned) little endian values contained in a packed struct to CPU native endian values here, not the other way around. So replace cpu_to_le16() with get_unaligned_le16(), using the latter instead of le16_to_cpu() to acknowledge that we are reading from a packed struct. Reported-by: kernel test robot Fixes: b05ff1002a5c ("HID: Add support for Surface Aggregator Module HID transport") Signed-off-by: Maximilian Luz Signed-off-by: Jiri Kosina --- drivers/hid/surface-hid/surface_hid_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c index 7b27ec392232..5571e74abe91 100644 --- a/drivers/hid/surface-hid/surface_hid_core.c +++ b/drivers/hid/surface-hid/surface_hid_core.c @@ -168,9 +168,9 @@ int surface_hid_device_add(struct surface_hid_device *shid) shid->hid->dev.parent = shid->dev; shid->hid->bus = BUS_HOST; - shid->hid->vendor = cpu_to_le16(shid->attrs.vendor); - shid->hid->product = cpu_to_le16(shid->attrs.product); - shid->hid->version = cpu_to_le16(shid->hid_desc.hid_version); + shid->hid->vendor = get_unaligned_le16(&shid->attrs.vendor); + shid->hid->product = get_unaligned_le16(&shid->attrs.product); + shid->hid->version = get_unaligned_le16(&shid->hid_desc.hid_version); shid->hid->country = shid->hid_desc.country_code; snprintf(shid->hid->name, sizeof(shid->hid->name), "Microsoft Surface %04X:%04X", -- cgit v1.2.3 From b45ef5db7bf268f6851bb5395d60301338374abc Mon Sep 17 00:00:00 2001 From: Michael Zaidman Date: Tue, 13 Apr 2021 18:12:00 +0300 Subject: HID: ft260: check data size in ft260_smbus_write() The SMbus block transaction limits the number of bytes transferred to 32, but nothing prevents a user from specifying via ioctl a larger data size than the ft260 can handle in a single transfer. i2cdev_ioctl_smbus() --> i2c_smbus_xfer --> __i2c_smbus_xfer --> ft260_smbus_xfer --> ft260_smbus_write This patch adds data size checking in the ft260_smbus_write(). Fixes: 98189a0adfa0 ("HID: ft260: add usb hid to i2c host bridge driver") Signed-off-by: Michael Zaidman Reported-by: Dan Carpenter Signed-off-by: Jiri Kosina --- drivers/hid/hid-ft260.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c index a5751607ce24..7a9ba984a75a 100644 --- a/drivers/hid/hid-ft260.c +++ b/drivers/hid/hid-ft260.c @@ -201,7 +201,7 @@ struct ft260_i2c_write_request_report { u8 address; /* 7-bit I2C address */ u8 flag; /* I2C transaction condition */ u8 length; /* data payload length */ - u8 data[60]; /* data payload */ + u8 data[FT260_WR_DATA_MAX]; /* data payload */ } __packed; struct ft260_i2c_read_request_report { @@ -429,6 +429,9 @@ static int ft260_smbus_write(struct ft260_device *dev, u8 addr, u8 cmd, struct ft260_i2c_write_request_report *rep = (struct ft260_i2c_write_request_report *)dev->write_buf; + if (data_len >= sizeof(rep->data)) + return -EINVAL; + rep->address = addr; rep->data[0] = cmd; rep->length = data_len + 1; -- cgit v1.2.3 From edb032033da0dc850f6e7740fa1023c73195bc89 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 15 Apr 2021 11:52:31 -0700 Subject: HID: hid-sensor-hub: Return error for hid_set_field() failure In the function sensor_hub_set_feature(), return error when hid_set_field() fails. Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 95cf88f3bafb..6abd3e2a9094 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -209,16 +209,21 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, buffer_size = buffer_size / sizeof(__s32); if (buffer_size) { for (i = 0; i < buffer_size; ++i) { - hid_set_field(report->field[field_index], i, - (__force __s32)cpu_to_le32(*buf32)); + ret = hid_set_field(report->field[field_index], i, + (__force __s32)cpu_to_le32(*buf32)); + if (ret) + goto done_proc; + ++buf32; } } if (remaining_bytes) { value = 0; memcpy(&value, (u8 *)buf32, remaining_bytes); - hid_set_field(report->field[field_index], i, - (__force __s32)cpu_to_le32(value)); + ret = hid_set_field(report->field[field_index], i, + (__force __s32)cpu_to_le32(value)); + if (ret) + goto done_proc; } hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); hid_hw_wait(hsdev->hdev); -- cgit v1.2.3 From c980512b4512adf2c6f9edb948ce19423b23124d Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Sun, 18 Apr 2021 21:12:29 +1200 Subject: HID: asus: filter G713/G733 key event to prevent shutdown The G713 and G733 both emit an unexpected keycode on some key presses such as Fn+Pause. The device in this case is emitting two events on key down, and 3 on key up, the third key up event is report ID 0x02 and is unfiltered, causing incorrect event. This patch filters out the single problematic event. Signed-off-by: Luke D Jones Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 1ed1c05c3d54..60606c11bdaf 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -355,6 +355,16 @@ static int asus_raw_event(struct hid_device *hdev, return -1; } } + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + /* + * G713 and G733 send these codes on some keypresses, depending on + * the key pressed it can trigger a shutdown event if not caught. + */ + if(data[0] == 0x02 && data[1] == 0x30) { + return -1; + } + } + } return 0; -- cgit v1.2.3 From 3b2520076822f15621509a6da3bc4a8636cd33b4 Mon Sep 17 00:00:00 2001 From: Saeed Mirzamohammadi Date: Thu, 29 Apr 2021 11:50:39 -0700 Subject: HID: quirks: Add quirk for Lenovo optical mouse The Lenovo optical mouse with vendor id of 0x17ef and product id of 0x600e experiences disconnecting issues every 55 seconds: [38565.706242] usb 1-1.4: Product: Lenovo Optical Mouse [38565.728603] input: Lenovo Optical Mouse as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:17EF:600E.029A/input/input665 [38565.755949] hid-generic 0003:17EF:600E.029A: input,hidraw1: USB HID v1.11 Mouse [Lenovo Optical Mouse] on usb-0000:01:00.0-1.4/input0 [38619.360692] usb 1-1.4: USB disconnect, device number 48 [38620.864990] usb 1-1.4: new low-speed USB device number 49 using xhci_hcd [38620.984011] usb 1-1.4: New USB device found, idVendor=17ef,idProduct=600e, bcdDevice= 1.00 [38620.998117] usb 1-1.4: New USB device strings: Mfr=0, Product=2,SerialNumber=0 This adds HID_QUIRK_ALWAYS_POLL for this device in order to work properly. Signed-off-by: Saeed Mirzamohammadi Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 933b0ed9d3ed..fad61ac349b7 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -752,6 +752,7 @@ #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3 #define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5 +#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index d2933f2ffec5..51b39bda9a9d 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -110,6 +110,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL }, -- cgit v1.2.3 From 670a23111e720dd50b07c25437b480f1bdfecc78 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Wed, 28 Apr 2021 20:05:14 -0400 Subject: HID: remove the unnecessary redefinition of a macro USB_VENDOR_ID_CORSAIR is defined twice in the same file with the same value. Signed-off-by: Hamza Mahfooz Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index fad61ac349b7..b84a0a11e05b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -300,8 +300,6 @@ #define USB_VENDOR_ID_CORSAIR 0x1b1c #define USB_DEVICE_ID_CORSAIR_K90 0x1b02 - -#define USB_VENDOR_ID_CORSAIR 0x1b1c #define USB_DEVICE_ID_CORSAIR_K70R 0x1b09 #define USB_DEVICE_ID_CORSAIR_K95RGB 0x1b11 #define USB_DEVICE_ID_CORSAIR_M65RGB 0x1b12 -- cgit v1.2.3 From a2353e3b26012ff43bcdf81d37a3eaddd7ecdbf3 Mon Sep 17 00:00:00 2001 From: Ahelenia Ziemiańska Date: Mon, 8 Mar 2021 18:42:03 +0100 Subject: HID: multitouch: require Finger field to mark Win8 reports as MT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This effectively changes collection_is_mt from contact ID in report->field to (device is Win8 => collection is finger) && contact ID in report->field Some devices erroneously report Pen for fingers, and Win8 stylus-on-touchscreen devices report contact ID, but mark the accompanying touchscreen device's collection correctly Cc: stable@vger.kernel.org Signed-off-by: Ahelenia Ziemiańska Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 9d9f3e1bd5f4..55dcb8536286 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -604,9 +604,13 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td, if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) continue; - for (n = 0; n < field->report_count; n++) { - if (field->usage[n].hid == HID_DG_CONTACTID) - rdata->is_mt_collection = true; + if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) { + for (n = 0; n < field->report_count; n++) { + if (field->usage[n].hid == HID_DG_CONTACTID) { + rdata->is_mt_collection = true; + break; + } + } } } -- cgit v1.2.3 From bc8b796f618c3ccb0a2a8ed1e96c00a1a7849415 Mon Sep 17 00:00:00 2001 From: Ahelenia Ziemiańska Date: Mon, 8 Mar 2021 18:42:08 +0100 Subject: HID: multitouch: set Stylus suffix for Stylus-application devices, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This re-adds the suffix to Win8 stylus-on-touchscreen devices, now that they aren't erroneously marked as MT Signed-off-by: Ahelenia Ziemiańska Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 55dcb8536286..eed81bdc2e86 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1580,13 +1580,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) /* we do not set suffix = "Touchscreen" */ hi->input->name = hdev->name; break; - case HID_DG_STYLUS: - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); - break; case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: suffix = "Custom Media Keys"; break; + case HID_DG_STYLUS: + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + fallthrough; case HID_DG_PEN: suffix = "Stylus"; break; -- cgit v1.2.3 From 48e33befe61a7d407753c53d1a06fc8d6b5dab80 Mon Sep 17 00:00:00 2001 From: Mark Bolhuis Date: Mon, 3 May 2021 17:39:38 +0100 Subject: HID: Add BUS_VIRTUAL to hid_connect logging Add BUS_VIRTUAL to hid_connect logging since it's a valid hid bus type and it should not print Signed-off-by: Mark Bolhuis Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 0ae9f6df59d1..265cbe592374 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2005,6 +2005,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) case BUS_I2C: bus = "I2C"; break; + case BUS_VIRTUAL: + bus = "VIRTUAL"; + break; default: bus = ""; } -- cgit v1.2.3 From 682ae59ca2876f83396ccc5674235da99beed06c Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 4 May 2021 18:04:24 +0800 Subject: ASoC: rt711-sdca: fix the function number of SDCA control for feature unit 0x1E The function number should be FUNC_NUM_MIC_ARRAY(0x2) for the feature unit 0x1E. Fixes: ca5118c0c00f6 ('ASoC: rt711-sdca: change capture switch controls') Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210504100424.8760-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index cc36739f7fcf..24a084e0b48a 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -683,13 +683,13 @@ static int rt711_sdca_set_fu1e_capture_ctl(struct rt711_sdca_priv *rt711) ch_r = (rt711->fu1e_dapm_mute || rt711->fu1e_mixer_r_mute) ? 0x01 : 0x00; err = regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), ch_l); if (err < 0) return err; err = regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), ch_r); if (err < 0) return err; -- cgit v1.2.3 From 6be388f4a35d2ce5ef7dbf635a8964a5da7f799f Mon Sep 17 00:00:00 2001 From: Anirudh Rayabharam Date: Sun, 25 Apr 2021 23:03:53 +0530 Subject: HID: usbhid: fix info leak in hid_submit_ctrl In hid_submit_ctrl(), the way of calculating the report length doesn't take into account that report->size can be zero. When running the syzkaller reproducer, a report of size 0 causes hid_submit_ctrl) to calculate transfer_buffer_length as 16384. When this urb is passed to the usb core layer, KMSAN reports an info leak of 16384 bytes. To fix this, first modify hid_report_len() to account for the zero report size case by using DIV_ROUND_UP for the division. Then, call it from hid_submit_ctrl(). Reported-by: syzbot+7c2bb71996f95a82524c@syzkaller.appspotmail.com Signed-off-by: Anirudh Rayabharam Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 2 +- include/linux/hid.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 86257ce6d619..4e9077363c96 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -374,7 +374,7 @@ static int hid_submit_ctrl(struct hid_device *hid) raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; dir = usbhid->ctrl[usbhid->ctrltail].dir; - len = ((report->size - 1) >> 3) + 1 + (report->id > 0); + len = hid_report_len(report); if (dir == USB_DIR_OUT) { usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); usbhid->urbctrl->transfer_buffer_length = len; diff --git a/include/linux/hid.h b/include/linux/hid.h index 271021e20a3f..10e922cee4eb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1167,8 +1167,7 @@ static inline void hid_hw_wait(struct hid_device *hdev) */ static inline u32 hid_report_len(struct hid_report *report) { - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ - return ((report->size - 1) >> 3) + 1 + (report->id > 0); + return DIV_ROUND_UP(report->size, 8) + (report->id > 0); } int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, -- cgit v1.2.3 From 9683e5775c75097c46bd24e65411b16ac6c6cbb3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 4 May 2021 16:49:10 -0700 Subject: libbpf: Add NULL check to add_dummy_ksym_var Avoids a segv if btf isn't present. Seen on the call path __bpf_object__open calling bpf_object__collect_externs. Fixes: 5bd022ec01f0 (libbpf: Support extern kernel function) Suggested-by: Stanislav Fomichev Suggested-by: Petar Penkov Signed-off-by: Ian Rogers Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20210504234910.976501-1-irogers@google.com --- tools/lib/bpf/libbpf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e2a3cf437814..c41d9b2b59ac 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -3216,6 +3216,9 @@ static int add_dummy_ksym_var(struct btf *btf) const struct btf_var_secinfo *vs; const struct btf_type *sec; + if (!btf) + return 0; + sec_btf_id = btf__find_by_name_kind(btf, KSYMS_SEC, BTF_KIND_DATASEC); if (sec_btf_id < 0) -- cgit v1.2.3 From 3b80d106e110d39d3f678954d3b55078669cf07e Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Thu, 6 May 2021 14:43:49 +0200 Subject: samples/bpf: Consider frame size in tx_only of xdpsock sample Fix the tx_only micro-benchmark in xdpsock to take frame size into consideration. It was hardcoded to the default value of frame_size which is 4K. Changing this on the command line to 2K made half of the packets illegal as they were outside the umem and were therefore discarded by the kernel. Fixes: 46738f73ea4f ("samples/bpf: add use of need_wakeup flag in xdpsock") Signed-off-by: Magnus Karlsson Signed-off-by: Daniel Borkmann Acked-by: Maciej Fijalkowski Link: https://lore.kernel.org/bpf/20210506124349.6666-1-magnus.karlsson@gmail.com --- samples/bpf/xdpsock_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index aa696854be78..53e300f860bb 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -1255,7 +1255,7 @@ static void tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size) for (i = 0; i < batch_size; i++) { struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); - tx_desc->addr = (*frame_nb + i) << XSK_UMEM__DEFAULT_FRAME_SHIFT; + tx_desc->addr = (*frame_nb + i) * opt_xsk_frame_size; tx_desc->len = PKT_SIZE; } -- cgit v1.2.3 From 31379397dcc364a59ce764fabb131b645c43e340 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 5 May 2021 15:25:29 +0200 Subject: bpf: Forbid trampoline attach for functions with variable arguments We can't currently allow to attach functions with variable arguments. The problem is that we should save all the registers for arguments, which is probably doable, but if caller uses more than 6 arguments, we need stack data, which will be wrong, because of the extra stack frame we do in bpf trampoline, so we could crash. Also currently there's malformed trampoline code generated for such functions at the moment as described in: https://lore.kernel.org/bpf/20210429212834.82621-1-jolsa@kernel.org/ Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20210505132529.401047-1-jolsa@kernel.org --- kernel/bpf/btf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 0600ed325fa0..f982a9f0dbc4 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5206,6 +5206,12 @@ int btf_distill_func_proto(struct bpf_verifier_log *log, m->ret_size = ret; for (i = 0; i < nargs; i++) { + if (i == nargs - 1 && args[i].type == 0) { + bpf_log(log, + "The function %s with variable args is unsupported.\n", + tname); + return -EINVAL; + } ret = __get_type_size(btf, args[i].type, &t); if (ret < 0) { bpf_log(log, @@ -5213,6 +5219,12 @@ int btf_distill_func_proto(struct bpf_verifier_log *log, tname, i, btf_kind_str[BTF_INFO_KIND(t->info)]); return -EINVAL; } + if (ret == 0) { + bpf_log(log, + "The function %s has malformed void argument.\n", + tname); + return -EINVAL; + } m->arg_size[i] = ret; } m->nr_args = nargs; -- cgit v1.2.3 From db8e712e06874e37a1fdb9bb011618811fc96dbd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 7 May 2021 12:09:03 +0300 Subject: bus: ti-sysc: Fix missing quirk flags for sata Naresh Kamboju reported that Beaglebone-X15 does not detect sata drives any longer after dra7 was flipped to boot with device tree data only. Turns out we are now missing the sata related quirk flags in ti-sysc that we used to have earlier. Fixes: 98feab31ac49 ("ARM: OMAP2+: Drop legacy platform data for dra7 sata") Fixes: 21206c8f2cb5 ("ARM: OMAP2+: Drop legacy platform data for omap5 sata") Link: https://lore.kernel.org/regressions/CA+G9fYtTN6ug3eBAW3wMcDeESUo+ebj7L5HBe5_fj4uqDExFQg@mail.gmail.com/ Reported-by: Naresh Kamboju Tested-by: Naresh Kamboju Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 8880259b41ae..b3e7a6e8de71 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -1459,6 +1459,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), SYSC_QUIRK("tptc", 0, 0, -ENODEV, -ENODEV, 0x40007c00, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), + SYSC_QUIRK("sata", 0, 0xfc, 0x1100, -ENODEV, 0x5e412000, 0xffffffff, + SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff, @@ -1524,7 +1526,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0), SYSC_QUIRK("rfbi", 0x4832a800, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), SYSC_QUIRK("rfbi", 0x58002000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), - SYSC_QUIRK("sata", 0, 0xfc, 0x1100, -ENODEV, 0x5e412000, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0), SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0), -- cgit v1.2.3 From ca66a6770bd9d6d99e469debd1c7363ac455daf9 Mon Sep 17 00:00:00 2001 From: Johnny Chuang Date: Tue, 13 Apr 2021 09:20:50 +0800 Subject: HID: i2c-hid: Skip ELAN power-on command after reset For ELAN touchscreen, we found our boot code of IC was not flexible enough to receive and handle this command. Once the FW main code of our controller is crashed for some reason, the controller could not be enumerated successfully to be recognized by the system host. therefore, it lost touch functionality. Add quirk for skip send power-on command after reset. It will impact to ELAN touchscreen and touchpad on HID over I2C projects. Fixes: 43b7029f475e ("HID: i2c-hid: Send power-on command after reset"). Cc: stable@vger.kernel.org Signed-off-by: Johnny Chuang Reviewed-by: Harry Cutts Reviewed-by: Douglas Anderson Tested-by: Douglas Anderson Signed-off-by: Benjamin Tissoires --- drivers/hid/i2c-hid/i2c-hid-core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 9993133989a5..ce91b1e57876 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -45,6 +45,7 @@ #define I2C_HID_QUIRK_BOGUS_IRQ BIT(4) #define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5) #define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6) +#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7) /* flags */ @@ -178,6 +179,11 @@ static const struct i2c_hid_quirks { I2C_HID_QUIRK_RESET_ON_RESUME }, { USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720, I2C_HID_QUIRK_BAD_INPUT_SIZE }, + /* + * Sending the wakeup after reset actually break ELAN touchscreen controller + */ + { USB_VENDOR_ID_ELAN, HID_ANY_ID, + I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET }, { 0, 0 } }; @@ -461,7 +467,8 @@ static int i2c_hid_hwreset(struct i2c_client *client) } /* At least some SIS devices need this after reset */ - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); + if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET)) + ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); out_unlock: mutex_unlock(&ihid->reset_lock); -- cgit v1.2.3 From c5a80540e425a5f9a82b0f3163e3b6a4331f33bc Mon Sep 17 00:00:00 2001 From: Dominik Andreas Schorpp Date: Thu, 22 Apr 2021 09:58:52 +0200 Subject: USB: serial: ftdi_sio: add IDs for IDS GmbH Products Add the IDS GmbH Vendor ID and the Product IDs for SI31A (2xRS232) and CM31A (LoRaWAN Modem). Signed-off-by: Dominik Andreas Schorpp Signed-off-by: Juergen Borleis Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6f2659e59b2e..369ef140df78 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1034,6 +1034,9 @@ static const struct usb_device_id id_table_combined[] = { /* Sienna devices */ { USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) }, { USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) }, + /* IDS GmbH devices */ + { USB_DEVICE(IDS_VID, IDS_SI31A_PID) }, + { USB_DEVICE(IDS_VID, IDS_CM31A_PID) }, /* U-Blox devices */ { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) }, { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 3d47c6d72256..d854e04a4286 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1567,6 +1567,13 @@ #define UNJO_VID 0x22B7 #define UNJO_ISODEBUG_V1_PID 0x150D +/* + * IDS GmbH + */ +#define IDS_VID 0x2CAF +#define IDS_SI31A_PID 0x13A2 +#define IDS_CM31A_PID 0x13A3 + /* * U-Blox products (http://www.u-blox.com). */ -- cgit v1.2.3 From e467714f822b5d167a7fb03d34af91b5b6af1827 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Wed, 28 Apr 2021 09:26:34 +0200 Subject: USB: serial: option: add Telit LE910-S1 compositions 0x7010, 0x7011 Add support for the following Telit LE910-S1 compositions: 0x7010: rndis, tty, tty, tty 0x7011: ecm, tty, tty, tty Signed-off-by: Daniele Palmas Link: https://lore.kernel.org/r/20210428072634.5091-1-dnlplm@gmail.com Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 3e79a543d3e7..7608584ef4fe 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1240,6 +1240,10 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x7010, 0xff), /* Telit LE910-S1 (RNDIS) */ + .driver_info = NCTRL(2) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x7011, 0xff), /* Telit LE910-S1 (ECM) */ + .driver_info = NCTRL(2) }, { USB_DEVICE(TELIT_VENDOR_ID, 0x9010), /* Telit SBL FN980 flashing device */ .driver_info = NCTRL(0) | ZLP }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ -- cgit v1.2.3 From 89b1a3d811e6f8065d6ae8a25e7682329b4a31e2 Mon Sep 17 00:00:00 2001 From: Sean MacLennan Date: Sat, 1 May 2021 20:40:45 -0400 Subject: USB: serial: ti_usb_3410_5052: add startech.com device id This adds support for the Startech.com generic serial to USB converter. It seems to be a bone stock TI_3410. I have been using this patch for years. Signed-off-by: Sean MacLennan Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index caa46ac23db9..310db5abea9d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -37,6 +37,7 @@ /* Vendor and product ids */ #define TI_VENDOR_ID 0x0451 #define IBM_VENDOR_ID 0x04b3 +#define STARTECH_VENDOR_ID 0x14b0 #define TI_3410_PRODUCT_ID 0x3410 #define IBM_4543_PRODUCT_ID 0x4543 #define IBM_454B_PRODUCT_ID 0x454b @@ -370,6 +371,7 @@ static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, + { USB_DEVICE(STARTECH_VENDOR_ID, TI_3410_PRODUCT_ID) }, { } /* terminator */ }; @@ -408,6 +410,7 @@ static const struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, + { USB_DEVICE(STARTECH_VENDOR_ID, TI_3410_PRODUCT_ID) }, { } /* terminator */ }; -- cgit v1.2.3 From f8e8c1b2f782e7391e8a1c25648ce756e2a7d481 Mon Sep 17 00:00:00 2001 From: Zolton Jheng Date: Mon, 10 May 2021 10:32:00 +0800 Subject: USB: serial: pl2303: add device id for ADLINK ND-6530 GC This adds the device id for the ADLINK ND-6530 which is a PL2303GC based device. Signed-off-by: Zolton Jheng Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index fd773d252691..940050c31482 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -113,6 +113,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530GC_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, { } /* Terminating entry */ diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 0f681ddbfd28..6097ee8fccb2 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -158,6 +158,7 @@ /* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ #define ADLINK_VENDOR_ID 0x0b63 #define ADLINK_ND6530_PRODUCT_ID 0x6530 +#define ADLINK_ND6530GC_PRODUCT_ID 0x653a /* SMART USB Serial Adapter */ #define SMART_VENDOR_ID 0x0b8c -- cgit v1.2.3 From d4335d058f8430a0ce2b43dab9531f3a3cf9fe2c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 10 May 2021 11:38:44 +0100 Subject: ASoC: codecs: lpass-rx-macro: add missing MODULE_DEVICE_TABLE Fix module loading by adding missing MODULE_DEVICE_TABLE. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210510103844.1532-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 4f1b569d7c47..e074c7908c23 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3579,6 +3579,7 @@ static const struct of_device_id rx_macro_dt_match[] = { { .compatible = "qcom,sm8250-lpass-rx-macro" }, { } }; +MODULE_DEVICE_TABLE(of, rx_macro_dt_match); static struct platform_driver rx_macro_driver = { .driver = { -- cgit v1.2.3 From 14c0c423746fe7232a093a68809a4bc6233eed60 Mon Sep 17 00:00:00 2001 From: Bixuan Cui Date: Sat, 8 May 2021 11:15:12 +0800 Subject: ASoC: codecs: lpass-tx-macro: add missing MODULE_DEVICE_TABLE This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot Signed-off-by: Bixuan Cui Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210508031512.53783-1-cuibixuan@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 4eede9ad57bf..3d3a6e31551b 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1846,6 +1846,7 @@ static const struct of_device_id tx_macro_dt_match[] = { { .compatible = "qcom,sm8250-lpass-tx-macro" }, { } }; +MODULE_DEVICE_TABLE(of, tx_macro_dt_match); static struct platform_driver tx_macro_driver = { .driver = { .name = "tx_macro", -- cgit v1.2.3 From b23584d6ce0212b9ad6cb7be19a7123461ed9e09 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Sat, 8 May 2021 18:46:47 +0800 Subject: ASoC: ak5558: Correct the dai name for ak5552 Correct the dai name for ak5552. The name should be "ak5552-aif". Fixes: d8c5c82e4e5b ("ASoC: ak5558: Add support for ak5552") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1620470807-12056-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 34aed80db0eb..37d4600b6f2c 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -307,7 +307,7 @@ static struct snd_soc_dai_driver ak5558_dai = { }; static struct snd_soc_dai_driver ak5552_dai = { - .name = "ak5558-aif", + .name = "ak5552-aif", .capture = { .stream_name = "Capture", .channels_min = 1, -- cgit v1.2.3 From 680ec0549a055eb464dce6ffb4bfb736ef87236e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 9 May 2021 21:12:27 +0200 Subject: spi: spi-fsl-dspi: Fix a resource leak in an error handling path 'dspi_request_dma()' should be undone by a 'dspi_release_dma()' call in the error handling path of the probe function, as already done in the remove function Fixes: 90ba37033cb9 ("spi: spi-fsl-dspi: Add DMA support for Vybrid") Signed-off-by: Christophe JAILLET Reviewed-by: Vladimir Oltean Link: https://lore.kernel.org/r/d51caaac747277a1099ba8dea07acd85435b857e.1620587472.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 028736687488..fb45e6af6638 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1375,11 +1375,13 @@ poll_mode: ret = spi_register_controller(ctlr); if (ret != 0) { dev_err(&pdev->dev, "Problem registering DSPI ctlr\n"); - goto out_free_irq; + goto out_release_dma; } return ret; +out_release_dma: + dspi_release_dma(dspi); out_free_irq: if (dspi->irq) free_irq(dspi->irq, dspi); -- cgit v1.2.3 From dc5fa590273890a8541ce6e999d606bfb2d73797 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Sat, 8 May 2021 14:02:14 +0800 Subject: spi: take the SPI IO-mutex in the spi_set_cs_timing method this patch takes the io_mutex to prevent an unprotected HW register modification in the set_cs_timing callback. Fixes: 4cea6b8cc34e ("spi: add power control when set_cs_timing") Signed-off-by: Leilk Liu Link: https://lore.kernel.org/r/20210508060214.1485-1-leilk.liu@mediatek.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f9885c096563..a565e7d6bf3b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3457,9 +3457,12 @@ int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup, if (spi->controller->set_cs_timing && !(spi->cs_gpiod || gpio_is_valid(spi->cs_gpio))) { + mutex_lock(&spi->controller->io_mutex); + if (spi->controller->auto_runtime_pm) { status = pm_runtime_get_sync(parent); if (status < 0) { + mutex_unlock(&spi->controller->io_mutex); pm_runtime_put_noidle(parent); dev_err(&spi->controller->dev, "Failed to power device: %d\n", status); @@ -3470,11 +3473,13 @@ int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup, hold, inactive); pm_runtime_mark_last_busy(parent); pm_runtime_put_autosuspend(parent); - return status; } else { - return spi->controller->set_cs_timing(spi, setup, hold, + status = spi->controller->set_cs_timing(spi, setup, hold, inactive); } + + mutex_unlock(&spi->controller->io_mutex); + return status; } if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) || -- cgit v1.2.3 From 1c4841ccbd2b185587010d6178aac11953f61d4c Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 26 Apr 2021 16:09:19 -0700 Subject: dmaengine: idxd: add engine 'struct device' missing bus type assignment engine 'struct device' setup is missing assigning the bus type. Add it to dsa_bus_type. Fixes: 75b911309060 ("dmaengine: idxd: fix engine conf_dev lifetime") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/161947841562.984844.17505646725993659651.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 2a926bef87f2..ec7305f86bf7 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -242,6 +242,7 @@ static int idxd_setup_engines(struct idxd_device *idxd) engine->idxd = idxd; device_initialize(&engine->conf_dev); engine->conf_dev.parent = &idxd->conf_dev; + engine->conf_dev.bus = &dsa_bus_type; engine->conf_dev.type = &idxd_engine_device_type; rc = dev_set_name(&engine->conf_dev, "engine%d.%d", idxd->id, engine->id); if (rc < 0) { -- cgit v1.2.3 From 077cdb355b3d8ee0f258856962e6dac06e744401 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 26 Apr 2021 16:32:24 -0700 Subject: dmaengine: idxd: add missing dsa driver unregister The idxd_unregister_driver() has never been called for the idxd driver upon removal. Add fix to call unregister driver on module removal. Fixes: c52ca478233c ("dmaengine: idxd: add configuration component of driver") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/161947994449.1053102.13189942817915448216.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index ec7305f86bf7..6201f52f13f5 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -788,6 +788,7 @@ module_init(idxd_init_module); static void __exit idxd_exit_module(void) { + idxd_unregister_driver(); pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); idxd_unregister_bus_type(); -- cgit v1.2.3 From b577750e4157050ed6de5ca9083893027b8ece33 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 3 May 2021 12:06:03 +0200 Subject: MAINTAINERS: Add Matthew Bobrowski as a reviewer Matthew helps with fanotify already for some time and he'd like to do more so let's add him as a reviewer. CC: Matthew Bobrowski Signed-off-by: Jan Kara --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..e15e155ff10e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6938,6 +6938,7 @@ F: net/core/failover.c FANOTIFY M: Jan Kara R: Amir Goldstein +R: Matthew Bobrowski L: linux-fsdevel@vger.kernel.org S: Maintained F: fs/notify/fanotify/ -- cgit v1.2.3 From 17866bc6b2ae1c3075c9fe7bcbeb8ea50eb4c3fc Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 8 May 2021 11:00:56 +0800 Subject: dmaengine: fsl-dpaa2-qdma: Fix error return code in two functions Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in the function where it is. Fixes: 7fdf9b05c73b ("dmaengine: fsl-dpaa2-qdma: Add NXP dpaa2 qDMA controller driver for Layerscape SoCs") Reported-by: Hulk Robot Signed-off-by: Zhen Lei Link: https://lore.kernel.org/r/20210508030056.2027-1-thunder.leizhen@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c index 4ec909e0b810..4ae057922ef1 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c @@ -332,6 +332,7 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev) } if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) { + err = -EINVAL; dev_err(dev, "DPDMAI major version mismatch\n" "Found %u.%u, supported version is %u.%u\n", priv->dpdmai_attr.version.major, @@ -341,6 +342,7 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev) } if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) { + err = -EINVAL; dev_err(dev, "DPDMAI minor version mismatch\n" "Found %u.%u, supported version is %u.%u\n", priv->dpdmai_attr.version.major, @@ -475,6 +477,7 @@ static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv) ppriv->store = dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, dev); if (!ppriv->store) { + err = -ENOMEM; dev_err(dev, "dpaa2_io_store_create() failed\n"); goto err_store; } -- cgit v1.2.3 From 4ad5dd2d7876d79507a20f026507d1a93b8fff10 Mon Sep 17 00:00:00 2001 From: Bumyong Lee Date: Fri, 7 May 2021 15:36:47 +0900 Subject: dmaengine: pl330: fix wrong usage of spinlock flags in dma_cyclc flags varible which is the input parameter of pl330_prep_dma_cyclic() should not be used by spinlock_irq[save/restore] function. Signed-off-by: Jongho Park Signed-off-by: Bumyong Lee Signed-off-by: Chanho Park Link: https://lore.kernel.org/r/20210507063647.111209-1-chanho61.park@samsung.com Fixes: f6f2421c0a1c ("dmaengine: pl330: Merge dma_pl330_dmac and pl330_dmac structs") Cc: stable@vger.kernel.org Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index fd8d2bc3be9f..110de8a60058 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2694,13 +2694,15 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( for (i = 0; i < len / period_len; i++) { desc = pl330_get_desc(pch); if (!desc) { + unsigned long iflags; + dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n", __func__, __LINE__); if (!first) return NULL; - spin_lock_irqsave(&pl330->pool_lock, flags); + spin_lock_irqsave(&pl330->pool_lock, iflags); while (!list_empty(&first->node)) { desc = list_entry(first->node.next, @@ -2710,7 +2712,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( list_move_tail(&first->node, &pl330->desc_pool); - spin_unlock_irqrestore(&pl330->pool_lock, flags); + spin_unlock_irqrestore(&pl330->pool_lock, iflags); return NULL; } -- cgit v1.2.3 From 538ea65a9fd1194352a41313bff876b74b5d90c5 Mon Sep 17 00:00:00 2001 From: Quanyang Wang Date: Fri, 30 Apr 2021 14:40:41 +0800 Subject: dmaengine: xilinx: dpdma: initialize registers before request_irq In some scenarios (kdump), dpdma hardware irqs has been enabled when calling request_irq in probe function, and then the dpdma irq handler xilinx_dpdma_irq_handler is invoked to access xdev->chan[i]. But at this moment xdev->chan[i] hasn't been initialized. We should ensure the dpdma controller to be in a consistent and clean state before further initialization. So add dpdma_hw_init() to do this. Furthermore, in xilinx_dpdma_disable_irq, disable all interrupts instead of error interrupts. This patch is to fix the kdump kernel crash as below: [ 3.696128] Unable to handle kernel NULL pointer dereference at virtual address 000000000000012c [ 3.696710] xilinx-zynqmp-dpdma fd4c0000.dma-controller: Xilinx DPDMA engine is probed [ 3.704900] Mem abort info: [ 3.704902] ESR = 0x96000005 [ 3.704905] EC = 0x25: DABT (current EL), IL = 32 bits [ 3.704907] SET = 0, FnV = 0 [ 3.704912] EA = 0, S1PTW = 0 [ 3.713800] ahci-ceva fd0c0000.ahci: supply ahci not found, using dummy regulator [ 3.715585] Data abort info: [ 3.715587] ISV = 0, ISS = 0x00000005 [ 3.715589] CM = 0, WnR = 0 [ 3.715592] [000000000000012c] user address but active_mm is swapper [ 3.715596] Internal error: Oops: 96000005 [#1] SMP [ 3.715599] Modules linked in: [ 3.715608] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.0-12170-g60894882155f-dirty #77 [ 3.723937] Hardware name: ZynqMP ZCU102 Rev1.0 (DT) [ 3.723942] pstate: 80000085 (Nzcv daIf -PAN -UAO -TCO BTYPE=--) [ 3.723956] pc : xilinx_dpdma_irq_handler+0x418/0x560 [ 3.793049] lr : xilinx_dpdma_irq_handler+0x3d8/0x560 [ 3.798089] sp : ffffffc01186bdf0 [ 3.801388] x29: ffffffc01186bdf0 x28: ffffffc011836f28 [ 3.806692] x27: ffffff8023e0ac80 x26: 0000000000000080 [ 3.811996] x25: 0000000008000408 x24: 0000000000000003 [ 3.817300] x23: ffffffc01186be70 x22: ffffffc011291740 [ 3.822604] x21: 0000000000000000 x20: 0000000008000408 [ 3.827908] x19: 0000000000000000 x18: 0000000000000010 [ 3.833212] x17: 0000000000000000 x16: 0000000000000000 [ 3.838516] x15: 0000000000000000 x14: ffffffc011291740 [ 3.843820] x13: ffffffc02eb4d000 x12: 0000000034d4d91d [ 3.849124] x11: 0000000000000040 x10: ffffffc0112d2d48 [ 3.854428] x9 : ffffffc0112d2d40 x8 : ffffff8021c00268 [ 3.859732] x7 : 0000000000000000 x6 : ffffffc011836000 [ 3.865036] x5 : 0000000000000003 x4 : 0000000000000000 [ 3.870340] x3 : 0000000000000001 x2 : 0000000000000000 [ 3.875644] x1 : 0000000000000000 x0 : 000000000000012c [ 3.880948] Call trace: [ 3.883382] xilinx_dpdma_irq_handler+0x418/0x560 [ 3.888079] __handle_irq_event_percpu+0x5c/0x178 [ 3.892774] handle_irq_event_percpu+0x34/0x98 [ 3.897210] handle_irq_event+0x44/0xb8 [ 3.901030] handle_fasteoi_irq+0xd0/0x190 [ 3.905117] generic_handle_irq+0x30/0x48 [ 3.909111] __handle_domain_irq+0x64/0xc0 [ 3.913192] gic_handle_irq+0x78/0xa0 [ 3.916846] el1_irq+0xc4/0x180 [ 3.919982] cpuidle_enter_state+0x134/0x2f8 [ 3.924243] cpuidle_enter+0x38/0x50 [ 3.927810] call_cpuidle+0x1c/0x40 [ 3.931290] do_idle+0x20c/0x270 [ 3.934502] cpu_startup_entry+0x28/0x58 [ 3.938410] rest_init+0xbc/0xcc [ 3.941631] arch_call_rest_init+0x10/0x1c [ 3.945718] start_kernel+0x51c/0x558 Fixes: 7cbb0c63de3f ("dmaengine: xilinx: dpdma: Add the Xilinx DisplayPort DMA engine driver") Signed-off-by: Quanyang Wang Link: https://lore.kernel.org/r/20210430064041.4058180-1-quanyang.wang@windriver.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dpdma.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index 70b29bd079c9..ff7dfb3fdeb4 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -1459,7 +1459,7 @@ static void xilinx_dpdma_enable_irq(struct xilinx_dpdma_device *xdev) */ static void xilinx_dpdma_disable_irq(struct xilinx_dpdma_device *xdev) { - dpdma_write(xdev->reg, XILINX_DPDMA_IDS, XILINX_DPDMA_INTR_ERR_ALL); + dpdma_write(xdev->reg, XILINX_DPDMA_IDS, XILINX_DPDMA_INTR_ALL); dpdma_write(xdev->reg, XILINX_DPDMA_EIDS, XILINX_DPDMA_EINTR_ALL); } @@ -1596,6 +1596,26 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec, return dma_get_slave_channel(&xdev->chan[chan_id]->vchan.chan); } +static void dpdma_hw_init(struct xilinx_dpdma_device *xdev) +{ + unsigned int i; + void __iomem *reg; + + /* Disable all interrupts */ + xilinx_dpdma_disable_irq(xdev); + + /* Stop all channels */ + for (i = 0; i < ARRAY_SIZE(xdev->chan); i++) { + reg = xdev->reg + XILINX_DPDMA_CH_BASE + + XILINX_DPDMA_CH_OFFSET * i; + dpdma_clr(reg, XILINX_DPDMA_CH_CNTL, XILINX_DPDMA_CH_CNTL_ENABLE); + } + + /* Clear the interrupt status registers */ + dpdma_write(xdev->reg, XILINX_DPDMA_ISR, XILINX_DPDMA_INTR_ALL); + dpdma_write(xdev->reg, XILINX_DPDMA_EISR, XILINX_DPDMA_EINTR_ALL); +} + static int xilinx_dpdma_probe(struct platform_device *pdev) { struct xilinx_dpdma_device *xdev; @@ -1622,6 +1642,8 @@ static int xilinx_dpdma_probe(struct platform_device *pdev) if (IS_ERR(xdev->reg)) return PTR_ERR(xdev->reg); + dpdma_hw_init(xdev); + xdev->irq = platform_get_irq(pdev, 0); if (xdev->irq < 0) { dev_err(xdev->dev, "failed to get platform irq\n"); -- cgit v1.2.3 From 56a8d3fd1f342d10ee7b27e9ac0f4d00b5fbb91c Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:34 +0200 Subject: mtd: rawnand: cs553x: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-2-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/cs553x_nand.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index 6edf78c16fc8..df40927e5678 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -240,6 +241,15 @@ static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat, return 0; } +static int cs553x_ecc_correct(struct nand_chip *chip, + unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); +} + static struct cs553x_nand_controller *controllers[4]; static int cs553x_attach_chip(struct nand_chip *chip) @@ -251,7 +261,7 @@ static int cs553x_attach_chip(struct nand_chip *chip) chip->ecc.bytes = 3; chip->ecc.hwctl = cs_enable_hwecc; chip->ecc.calculate = cs_calculate_ecc; - chip->ecc.correct = rawnand_sw_hamming_correct; + chip->ecc.correct = cs553x_ecc_correct; chip->ecc.strength = 1; return 0; -- cgit v1.2.3 From ad9ffdce453934cdc22fac0a0268119bd630260f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:35 +0200 Subject: mtd: rawnand: fsmc: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-3-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/fsmc_nand.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index bf695255b43a..a3e66155ae40 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -432,6 +433,15 @@ static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const u8 *data, return 0; } +static int fsmc_correct_ecc1(struct nand_chip *chip, + unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); +} + /* Count the number of 0's in buff upto a max of max_bits */ static int count_written_bits(u8 *buff, int size, int max_bits) { @@ -917,7 +927,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) case NAND_ECC_ENGINE_TYPE_ON_HOST: dev_info(host->dev, "Using 1-bit HW ECC scheme\n"); nand->ecc.calculate = fsmc_read_hwecc_ecc1; - nand->ecc.correct = rawnand_sw_hamming_correct; + nand->ecc.correct = fsmc_correct_ecc1; nand->ecc.hwctl = fsmc_enable_hwecc; nand->ecc.bytes = 3; nand->ecc.strength = 1; -- cgit v1.2.3 From c4b7d7c480d607e4f52d310d9d16b194868d0917 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:36 +0200 Subject: mtd: rawnand: lpc32xx_slc: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Cc: Vladimir Zapolskiy Reported-by: Trevor Woerner Signed-off-by: Miquel Raynal Tested-by: Trevor Woerner Acked-by: Vladimir Zapolskiy Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-4-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/lpc32xx_slc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 6b7269cfb7d8..d7dfc6fd85ca 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -27,6 +27,7 @@ #include #include #include +#include #define LPC32XX_MODNAME "lpc32xx-nand" @@ -344,6 +345,18 @@ static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip, return 0; } +/* + * Corrects the data + */ +static int lpc32xx_nand_ecc_correct(struct nand_chip *chip, + unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); +} + /* * Read a single byte from NAND device */ @@ -802,7 +815,7 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip) chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome; chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome; chip->ecc.calculate = lpc32xx_nand_ecc_calculate; - chip->ecc.correct = rawnand_sw_hamming_correct; + chip->ecc.correct = lpc32xx_nand_ecc_correct; chip->ecc.hwctl = lpc32xx_nand_ecc_enable; /* -- cgit v1.2.3 From 3e09c0252501829b14b10f14e1982aaab77d0b80 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:37 +0200 Subject: mtd: rawnand: ndfc: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-5-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/ndfc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 338d6b1a189e..98d5a94c3a24 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,15 @@ static int ndfc_calculate_ecc(struct nand_chip *chip, return 0; } +static int ndfc_correct_ecc(struct nand_chip *chip, + unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); +} + /* * Speedups for buffer read/write/verify * @@ -145,7 +155,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, chip->controller = &ndfc->ndfc_control; chip->legacy.read_buf = ndfc_read_buf; chip->legacy.write_buf = ndfc_write_buf; - chip->ecc.correct = rawnand_sw_hamming_correct; + chip->ecc.correct = ndfc_correct_ecc; chip->ecc.hwctl = ndfc_enable_hwecc; chip->ecc.calculate = ndfc_calculate_ecc; chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; -- cgit v1.2.3 From 46fcb57e6b7283533ebf8ba17a6bd30fa88bdc9f Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:38 +0200 Subject: mtd: rawnand: sharpsl: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-6-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/sharpsl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index 5612ee628425..2f1fe464e663 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,15 @@ static int sharpsl_nand_calculate_ecc(struct nand_chip *chip, return readb(sharpsl->io + ECCCNTR) != 0; } +static int sharpsl_nand_correct_ecc(struct nand_chip *chip, + unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); +} + static int sharpsl_attach_chip(struct nand_chip *chip) { if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) @@ -106,7 +116,7 @@ static int sharpsl_attach_chip(struct nand_chip *chip) chip->ecc.strength = 1; chip->ecc.hwctl = sharpsl_nand_enable_hwecc; chip->ecc.calculate = sharpsl_nand_calculate_ecc; - chip->ecc.correct = rawnand_sw_hamming_correct; + chip->ecc.correct = sharpsl_nand_correct_ecc; return 0; } -- cgit v1.2.3 From 6a4c5ada577467a5f79e06f2c5e69c09983c22fb Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:39 +0200 Subject: mtd: rawnand: tmio: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-7-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/tmio_nand.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c index de8e919d0ebe..6d93dd31969b 100644 --- a/drivers/mtd/nand/raw/tmio_nand.c +++ b/drivers/mtd/nand/raw/tmio_nand.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -292,11 +293,12 @@ static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf, int r0, r1; /* assume ecc.size = 512 and ecc.bytes = 6 */ - r0 = rawnand_sw_hamming_correct(chip, buf, read_ecc, calc_ecc); + r0 = ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); if (r0 < 0) return r0; - r1 = rawnand_sw_hamming_correct(chip, buf + 256, read_ecc + 3, - calc_ecc + 3); + r1 = ecc_sw_hamming_correct(buf + 256, read_ecc + 3, calc_ecc + 3, + chip->ecc.size, false); if (r1 < 0) return r1; return r0 + r1; -- cgit v1.2.3 From 3d227a0b0ce319edbff6fd0d8af4d66689e477cc Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 13 Apr 2021 18:18:40 +0200 Subject: mtd: rawnand: txx9ndfmc: Fix external use of SW Hamming ECC helper Since the Hamming software ECC engine has been updated to become a proper and independent ECC engine, it is now mandatory to either initialize the engine before using any one of his functions or use one of the bare helpers which only perform the calculations. As there is no actual need for a proper ECC initialization, let's just use the bare helper instead of the rawnand one. Fixes: 90ccf0a0192f ("mtd: nand: ecc-hamming: Rename the exported functions") Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210413161840.345208-8-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/txx9ndfmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index 1a9449e53bf9..b8894ac27073 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -193,8 +194,8 @@ static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf, int stat; for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) { - stat = rawnand_sw_hamming_correct(chip, buf, read_ecc, - calc_ecc); + stat = ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, + chip->ecc.size, false); if (stat < 0) return stat; corrected += stat; -- cgit v1.2.3 From 562b4e91d3b221f737f84ff78ee7d348c8a6891f Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sat, 8 May 2021 19:32:14 +0200 Subject: mtd: parsers: ofpart: fix parsing subpartitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ofpart was recently patched to not scan random partition nodes as subpartitions. That change unfortunately broke scanning valid subpartitions like: partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; partition@0 { compatible = "fixed-partitions"; label = "bootloader"; reg = <0x0 0x100000>; partition@0 { label = "config"; reg = <0x80000 0x80000>; }; }; }; Fix that regression by adding 1 more code path. We actually need 3 conditional blocks to support 3 possible cases. This change also makes code easier to understand & follow. Reported-by: David Bauer Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax Signed-off-by: Rafał Miłecki Tested-by: Andrew Cameron Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210508173214.28365-1-zajec5@gmail.com --- drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c index 0fd8d2a0db97..192190c42fc8 100644 --- a/drivers/mtd/parsers/ofpart_core.c +++ b/drivers/mtd/parsers/ofpart_core.c @@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct mtd_info *master, if (!mtd_node) return 0; - ofpart_node = of_get_child_by_name(mtd_node, "partitions"); - if (!ofpart_node && !master->parent) { - /* - * We might get here even when ofpart isn't used at all (e.g., - * when using another parser), so don't be louder than - * KERN_DEBUG - */ - pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", - master->name, mtd_node); + if (!master->parent) { /* Master */ + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); + if (!ofpart_node) { + /* + * We might get here even when ofpart isn't used at all (e.g., + * when using another parser), so don't be louder than + * KERN_DEBUG + */ + pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", + master->name, mtd_node); + ofpart_node = mtd_node; + dedicated = false; + } + } else { /* Partition */ ofpart_node = mtd_node; - dedicated = false; } - if (!ofpart_node) - return 0; of_id = of_match_node(parse_ofpart_match_table, ofpart_node); if (dedicated && !of_id) { -- cgit v1.2.3 From 8ab78863e9eff11910e1ac8bcf478060c29b379e Mon Sep 17 00:00:00 2001 From: Jeimon Date: Sat, 8 May 2021 11:52:30 +0800 Subject: net/nfc/rawsock.c: fix a permission check bug The function rawsock_create() calls a privileged function sk_alloc(), which requires a ns-aware check to check net->user_ns, i.e., ns_capable(). However, the original code checks the init_user_ns using capable(). So we replace the capable() with ns_capable(). Signed-off-by: Jeimon Signed-off-by: David S. Miller --- net/nfc/rawsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 9c7eb8455ba8..5f1d438a0a23 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -329,7 +329,7 @@ static int rawsock_create(struct net *net, struct socket *sock, return -ESOCKTNOSUPPORT; if (sock->type == SOCK_RAW) { - if (!capable(CAP_NET_RAW)) + if (!ns_capable(net->user_ns, CAP_NET_RAW)) return -EPERM; sock->ops = &rawsock_raw_ops; } else { -- cgit v1.2.3 From ddb6e00f8413e885ff826e32521cff7924661de0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 8 May 2021 07:38:22 +0200 Subject: net: netcp: Fix an error message 'ret' is known to be 0 here. The expected error code is stored in 'tx_pipe->dma_queue', so use it instead. While at it, switch from %d to %pe which is more user friendly. Fixes: 84640e27f230 ("net: netcp: Add Keystone NetCP core ethernet driver") Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 9030e619e543..97942b0e3897 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -1350,8 +1350,8 @@ int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id, KNAV_QUEUE_SHARED); if (IS_ERR(tx_pipe->dma_queue)) { - dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n", - name, ret); + dev_err(dev, "Could not open DMA queue for channel \"%s\": %pe\n", + name, tx_pipe->dma_queue); ret = PTR_ERR(tx_pipe->dma_queue); goto err; } -- cgit v1.2.3 From a269333fa5c0c8e53c92b5a28a6076a28cde3e83 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 May 2021 16:30:35 +0300 Subject: net: dsa: fix a crash if ->get_sset_count() fails If ds->ops->get_sset_count() fails then it "count" is a negative error code such as -EOPNOTSUPP. Because "i" is an unsigned int, the negative error code is type promoted to a very high value and the loop will corrupt memory until the system crashes. Fix this by checking for error codes and changing the type of "i" to just int. Fixes: badf3ada60ab ("net: dsa: Provide CPU port statistics to master netdev") Signed-off-by: Dan Carpenter Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- net/dsa/master.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/dsa/master.c b/net/dsa/master.c index 052a977914a6..63adbc21a735 100644 --- a/net/dsa/master.c +++ b/net/dsa/master.c @@ -147,8 +147,7 @@ static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset, struct dsa_switch *ds = cpu_dp->ds; int port = cpu_dp->index; int len = ETH_GSTRING_LEN; - int mcount = 0, count; - unsigned int i; + int mcount = 0, count, i; uint8_t pfx[4]; uint8_t *ndata; @@ -178,6 +177,8 @@ static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset, */ ds->ops->get_strings(ds, port, stringset, ndata); count = ds->ops->get_sset_count(ds, port, stringset); + if (count < 0) + return; for (i = 0; i < count; i++) { memmove(ndata + (i * len + sizeof(pfx)), ndata + i * len, len - sizeof(pfx)); -- cgit v1.2.3 From db825feefc6868896fed5e361787ba3bee2fd906 Mon Sep 17 00:00:00 2001 From: Vladyslav Tarasiuk Date: Sun, 9 May 2021 09:43:18 +0300 Subject: net/mlx4: Fix EEPROM dump support Fix SFP and QSFP* EEPROM queries by setting i2c_address, offset and page number correctly. For SFP set the following params: - I2C address for offsets 0-255 is 0x50. For 256-511 - 0x51. - Page number is zero. - Offset is 0-255. At the same time, QSFP* parameters are different: - I2C address is always 0x50. - Page number is not limited to zero. - Offset is 0-255 for page zero and 128-255 for others. To set parameters accordingly to cable used, implement function to query module ID and implement respective helper functions to set parameters correctly. Fixes: 135dd9594f12 ("net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query") Signed-off-by: Vladyslav Tarasiuk Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 4 +- drivers/net/ethernet/mellanox/mlx4/port.c | 107 +++++++++++++++++++++++- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 1434df66fcf2..3616b77caa0a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -2027,8 +2027,6 @@ static int mlx4_en_set_tunable(struct net_device *dev, return ret; } -#define MLX4_EEPROM_PAGE_LEN 256 - static int mlx4_en_get_module_info(struct net_device *dev, struct ethtool_modinfo *modinfo) { @@ -2063,7 +2061,7 @@ static int mlx4_en_get_module_info(struct net_device *dev, break; case MLX4_MODULE_ID_SFP: modinfo->type = ETH_MODULE_SFF_8472; - modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; break; default: return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index ba6ac31a339d..256a06b3c096 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -1973,6 +1973,7 @@ EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); #define I2C_ADDR_LOW 0x50 #define I2C_ADDR_HIGH 0x51 #define I2C_PAGE_SIZE 256 +#define I2C_HIGH_PAGE_SIZE 128 /* Module Info Data */ struct mlx4_cable_info { @@ -2026,6 +2027,88 @@ static inline const char *cable_info_mad_err_str(u16 mad_status) return "Unknown Error"; } +static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id) +{ + struct mlx4_cmd_mailbox *inbox, *outbox; + struct mlx4_mad_ifc *inmad, *outmad; + struct mlx4_cable_info *cable_info; + int ret; + + inbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(inbox)) + return PTR_ERR(inbox); + + outbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(outbox)) { + mlx4_free_cmd_mailbox(dev, inbox); + return PTR_ERR(outbox); + } + + inmad = (struct mlx4_mad_ifc *)(inbox->buf); + outmad = (struct mlx4_mad_ifc *)(outbox->buf); + + inmad->method = 0x1; /* Get */ + inmad->class_version = 0x1; + inmad->mgmt_class = 0x1; + inmad->base_version = 0x1; + inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ + + cable_info = (struct mlx4_cable_info *)inmad->data; + cable_info->dev_mem_address = 0; + cable_info->page_num = 0; + cable_info->i2c_addr = I2C_ADDR_LOW; + cable_info->size = cpu_to_be16(1); + + ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, + MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, + MLX4_CMD_NATIVE); + if (ret) + goto out; + + if (be16_to_cpu(outmad->status)) { + /* Mad returned with bad status */ + ret = be16_to_cpu(outmad->status); + mlx4_warn(dev, + "MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n", + 0xFF60, port, I2C_ADDR_LOW, 0, 1, ret, + cable_info_mad_err_str(ret)); + ret = -ret; + goto out; + } + cable_info = (struct mlx4_cable_info *)outmad->data; + *module_id = cable_info->data[0]; +out: + mlx4_free_cmd_mailbox(dev, inbox); + mlx4_free_cmd_mailbox(dev, outbox); + return ret; +} + +static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset) +{ + *i2c_addr = I2C_ADDR_LOW; + *page_num = 0; + + if (*offset < I2C_PAGE_SIZE) + return; + + *i2c_addr = I2C_ADDR_HIGH; + *offset -= I2C_PAGE_SIZE; +} + +static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset) +{ + /* Offsets 0-255 belong to page 0. + * Offsets 256-639 belong to pages 01, 02, 03. + * For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2 + */ + if (*offset < I2C_PAGE_SIZE) + *page_num = 0; + else + *page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE; + *i2c_addr = I2C_ADDR_LOW; + *offset -= *page_num * I2C_HIGH_PAGE_SIZE; +} + /** * mlx4_get_module_info - Read cable module eeprom data * @dev: mlx4_dev. @@ -2045,12 +2128,30 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, struct mlx4_cmd_mailbox *inbox, *outbox; struct mlx4_mad_ifc *inmad, *outmad; struct mlx4_cable_info *cable_info; - u16 i2c_addr; + u8 module_id, i2c_addr, page_num; int ret; if (size > MODULE_INFO_MAX_READ) size = MODULE_INFO_MAX_READ; + ret = mlx4_get_module_id(dev, port, &module_id); + if (ret) + return ret; + + switch (module_id) { + case MLX4_MODULE_ID_SFP: + mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset); + break; + case MLX4_MODULE_ID_QSFP: + case MLX4_MODULE_ID_QSFP_PLUS: + case MLX4_MODULE_ID_QSFP28: + mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset); + break; + default: + mlx4_err(dev, "Module ID not recognized: %#x\n", module_id); + return -EINVAL; + } + inbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(inbox)) return PTR_ERR(inbox); @@ -2076,11 +2177,9 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, */ size -= offset + size - I2C_PAGE_SIZE; - i2c_addr = I2C_ADDR_LOW; - cable_info = (struct mlx4_cable_info *)inmad->data; cable_info->dev_mem_address = cpu_to_be16(offset); - cable_info->page_num = 0; + cable_info->page_num = page_num; cable_info->i2c_addr = i2c_addr; cable_info->size = cpu_to_be16(size); -- cgit v1.2.3 From b94cbc909f1d80378a1f541968309e5c1178c98b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 9 May 2021 22:33:38 +0300 Subject: net: dsa: fix error code getting shifted with 4 in dsa_slave_get_sset_count DSA implements a bunch of 'standardized' ethtool statistics counters, namely tx_packets, tx_bytes, rx_packets, rx_bytes. So whatever the hardware driver returns in .get_sset_count(), we need to add 4 to that. That is ok, except that .get_sset_count() can return a negative error code, for example: b53_get_sset_count -> phy_ethtool_get_sset_count -> return -EIO -EIO is -5, and with 4 added to it, it becomes -1, aka -EPERM. One can imagine that certain error codes may even become positive, although based on code inspection I did not see instances of that. Check the error code first, if it is negative return it as-is. Based on a similar patch for dsa_master_get_strings from Dan Carpenter: https://patchwork.kernel.org/project/netdevbpf/patch/YJaSe3RPgn7gKxZv@mwanda/ Fixes: 91da11f870f0 ("net: Distributed Switch Architecture protocol support") Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- net/dsa/slave.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8c0f3c6ab365..d4756b920108 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -776,13 +776,15 @@ static int dsa_slave_get_sset_count(struct net_device *dev, int sset) struct dsa_switch *ds = dp->ds; if (sset == ETH_SS_STATS) { - int count; + int count = 0; - count = 4; - if (ds->ops->get_sset_count) - count += ds->ops->get_sset_count(ds, dp->index, sset); + if (ds->ops->get_sset_count) { + count = ds->ops->get_sset_count(ds, dp->index, sset); + if (count < 0) + return count; + } - return count; + return count + 4; } else if (sset == ETH_SS_TEST) { return net_selftest_get_count(); } -- cgit v1.2.3 From 3058e01d31bbdbe50e02cafece2b22817a6a0eae Mon Sep 17 00:00:00 2001 From: Hoang Le Date: Mon, 10 May 2021 09:57:38 +0700 Subject: tipc: make node link identity publish thread safe The using of the node address and node link identity are not thread safe, meaning that two publications may be published the same values, as result one of them will get failure because of already existing in the name table. To avoid this we have to use the node address and node link identity values from inside the node item's write lock protection. Fixes: 50a3499ab853 ("tipc: simplify signature of tipc_namtbl_publish()") Acked-by: Jon Maloy Signed-off-by: Hoang Le Signed-off-by: David S. Miller --- net/tipc/node.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 8217905348f4..81af92954c6c 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -423,18 +423,18 @@ static void tipc_node_write_unlock(struct tipc_node *n) write_unlock_bh(&n->lock); if (flags & TIPC_NOTIFY_NODE_DOWN) - tipc_publ_notify(net, publ_list, n->addr, n->capabilities); + tipc_publ_notify(net, publ_list, sk.node, n->capabilities); if (flags & TIPC_NOTIFY_NODE_UP) - tipc_named_node_up(net, n->addr, n->capabilities); + tipc_named_node_up(net, sk.node, n->capabilities); if (flags & TIPC_NOTIFY_LINK_UP) { - tipc_mon_peer_up(net, n->addr, bearer_id); - tipc_nametbl_publish(net, &ua, &sk, n->link_id); + tipc_mon_peer_up(net, sk.node, bearer_id); + tipc_nametbl_publish(net, &ua, &sk, sk.ref); } if (flags & TIPC_NOTIFY_LINK_DOWN) { - tipc_mon_peer_down(net, n->addr, bearer_id); - tipc_nametbl_withdraw(net, &ua, &sk, n->link_id); + tipc_mon_peer_down(net, sk.node, bearer_id); + tipc_nametbl_withdraw(net, &ua, &sk, sk.ref); } } -- cgit v1.2.3 From 297c4de6f780b63b6d2af75a730720483bf1904a Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 10 May 2021 13:07:08 +0200 Subject: net: dsa: felix: re-enable TAS guard band mode Commit 316bcffe4479 ("net: dsa: felix: disable always guard band bit for TAS config") disabled the guard band and broke 802.3Qbv compliance. There are two issues here: (1) Without the guard band the end of the scheduling window could be overrun by a frame in transit. (2) Frames that don't fit into a configured window will still be sent. The reason for both issues is that the switch will schedule the _start_ of a frame transmission inside the predefined window without taking the length of the frame into account. Thus, we'll need the guard band which will close the gate early, so that a complete frame can still be sent. Revert the commit and add a note. For a lengthy discussion see [1]. [1] https://lore.kernel.org/netdev/c7618025da6723418c56a54fe4683bd7@walle.cc/ Fixes: 316bcffe4479 ("net: dsa: felix: disable always guard band bit for TAS config") Signed-off-by: Michael Walle Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 2473bebe48e6..f966a253d1c7 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1227,12 +1227,17 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) return -ERANGE; - /* Set port num and disable ALWAYS_GUARD_BAND_SCH_Q, which means set - * guard band to be implemented for nonschedule queues to schedule - * queues transition. + /* Enable guard band. The switch will schedule frames without taking + * their length into account. Thus we'll always need to enable the + * guard band which reserves the time of a maximum sized frame at the + * end of the time window. + * + * Although the ALWAYS_GUARD_BAND_SCH_Q bit is global for all ports, we + * need to set PORT_NUM, because subsequent writes to PARAM_CFG_REG_n + * operate on the port number. */ - ocelot_rmw(ocelot, - QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port), + ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) | + QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M | QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q, QSYS_TAS_PARAM_CFG_CTRL); -- cgit v1.2.3 From a00593737f8bac2c9e97b696e7ff84a4446653e8 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 22 Apr 2021 11:36:10 -0700 Subject: interconnect: qcom: bcm-voter: add a missing of_node_put() Add a missing of_node_put() in of_bcm_voter_get() to avoid the reference leak. Signed-off-by: Subbaraman Narayanamurthy Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/1619116570-13308-1-git-send-email-subbaram@codeaurora.org Fixes: 976daac4a1c5 ("interconnect: qcom: Consolidate interconnect RPMh support") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/bcm-voter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c index d1591a28b743..547f4c2593f4 100644 --- a/drivers/interconnect/qcom/bcm-voter.c +++ b/drivers/interconnect/qcom/bcm-voter.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #include @@ -205,6 +205,7 @@ struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name) } mutex_unlock(&bcm_voter_lock); + of_node_put(node); return voter; } EXPORT_SYMBOL_GPL(of_bcm_voter_get); -- cgit v1.2.3 From 1fd86e280d8b21762901e43d42d66dbfe8b8e0d3 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Tue, 11 May 2021 11:44:33 +0800 Subject: interconnect: qcom: Add missing MODULE_DEVICE_TABLE This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot Signed-off-by: Zou Wei Link: https://lore.kernel.org/r/1620704673-104205-1-git-send-email-zou_wei@huawei.com Fixes: 976daac4a1c5 ("interconnect: qcom: Consolidate interconnect RPMh support") Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/bcm-voter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c index 547f4c2593f4..8f385f9c2dd3 100644 --- a/drivers/interconnect/qcom/bcm-voter.c +++ b/drivers/interconnect/qcom/bcm-voter.c @@ -363,6 +363,7 @@ static const struct of_device_id bcm_voter_of_match[] = { { .compatible = "qcom,bcm-voter" }, { } }; +MODULE_DEVICE_TABLE(of, bcm_voter_of_match); static struct platform_driver qcom_icc_bcm_voter_driver = { .probe = qcom_icc_bcm_voter_probe, -- cgit v1.2.3 From 07adc0225484fc199e3dc15ec889f75f498c4fca Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Mon, 12 Apr 2021 13:49:07 +0800 Subject: usb: cdns3: Fix runtime PM imbalance on error When cdns3_gadget_start() fails, a pairing PM usage counter decrement is needed to keep the counter balanced. Signed-off-by: Dinghao Liu Link: https://lore.kernel.org/r/20210412054908.7975-1-dinghao.liu@zju.edu.cn Signed-off-by: Peter Chen --- drivers/usb/cdns3/cdns3-gadget.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 9b1bd417cec0..a8b7b50abf64 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -3268,8 +3268,10 @@ static int __cdns3_gadget_init(struct cdns *cdns) pm_runtime_get_sync(cdns->dev); ret = cdns3_gadget_start(cdns); - if (ret) + if (ret) { + pm_runtime_put_sync(cdns->dev); return ret; + } /* * Because interrupt line can be shared with other components in -- cgit v1.2.3 From 3b414d1b0107fa51ad6063de9752d4b2a8063980 Mon Sep 17 00:00:00 2001 From: Pawel Laszczak Date: Tue, 20 Apr 2021 06:28:13 +0200 Subject: usb: cdnsp: Fix lack of removing request from pending list. Patch fixes lack of removing request from ep->pending_list on failure of the stop endpoint command. Driver even after failing this command must remove request from ep->pending_list. Without this fix driver can stuck in cdnsp_gadget_ep_disable function in loop: while (!list_empty(&pep->pending_list)) { preq = next_request(&pep->pending_list); cdnsp_ep_dequeue(pep, preq); } Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver") Signed-off-by: Pawel Laszczak Link: https://lore.kernel.org/r/20210420042813.34917-1-pawell@gli-login.cadence.com Signed-off-by: Peter Chen --- drivers/usb/cdns3/cdnsp-gadget.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index 56707b6b0f57..c083985e387b 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -422,17 +422,17 @@ unmap: int cdnsp_ep_dequeue(struct cdnsp_ep *pep, struct cdnsp_request *preq) { struct cdnsp_device *pdev = pep->pdev; - int ret; + int ret_stop = 0; + int ret_rem; trace_cdnsp_request_dequeue(preq); - if (GET_EP_CTX_STATE(pep->out_ctx) == EP_STATE_RUNNING) { - ret = cdnsp_cmd_stop_ep(pdev, pep); - if (ret) - return ret; - } + if (GET_EP_CTX_STATE(pep->out_ctx) == EP_STATE_RUNNING) + ret_stop = cdnsp_cmd_stop_ep(pdev, pep); + + ret_rem = cdnsp_remove_request(pdev, preq, pep); - return cdnsp_remove_request(pdev, preq, pep); + return ret_rem ? ret_rem : ret_stop; } static void cdnsp_zero_in_ctx(struct cdnsp_device *pdev) -- cgit v1.2.3 From 049c4e13714ecbca567b4d5f6d563f05d431c80e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 10 May 2021 13:10:44 +0000 Subject: bpf: Fix alu32 const subreg bound tracking on bitwise operations Fix a bug in the verifier's scalar32_min_max_*() functions which leads to incorrect tracking of 32 bit bounds for the simulation of and/or/xor bitops. When both the src & dst subreg is a known constant, then the assumption is that scalar_min_max_*() will take care to update bounds correctly. However, this is not the case, for example, consider a register R2 which has a tnum of 0xffffffff00000000, meaning, lower 32 bits are known constant and in this case of value 0x00000001. R2 is then and'ed with a register R3 which is a 64 bit known constant, here, 0x100000002. What can be seen in line '10:' is that 32 bit bounds reach an invalid state where {u,s}32_min_value > {u,s}32_max_value. The reason is scalar32_min_max_*() delegates 32 bit bounds updates to scalar_min_max_*(), however, that really only takes place when both the 64 bit src & dst register is a known constant. Given scalar32_min_max_*() is intended to be designed as closely as possible to scalar_min_max_*(), update the 32 bit bounds in this situation through __mark_reg32_known() which will set all {u,s}32_{min,max}_value to the correct constant, which is 0x00000000 after the fix (given 0x00000001 & 0x00000002 in 32 bit space). This is possible given var32_off already holds the final value as dst_reg->var_off is updated before calling scalar32_min_max_*(). Before fix, invalid tracking of R2: [...] 9: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=-9223372036854775807 (0x8000000000000001),smax_value=9223372032559808513 (0x7fffffff00000001),umin_value=1,umax_value=0xffffffff00000001,var_off=(0x1; 0xffffffff00000000),s32_min_value=1,s32_max_value=1,u32_min_value=1,u32_max_value=1) R3_w=inv4294967298 R10=fp0 9: (5f) r2 &= r3 10: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=0,smax_value=4294967296 (0x100000000),umin_value=0,umax_value=0x100000000,var_off=(0x0; 0x100000000),s32_min_value=1,s32_max_value=0,u32_min_value=1,u32_max_value=0) R3_w=inv4294967298 R10=fp0 [...] After fix, correct tracking of R2: [...] 9: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=-9223372036854775807 (0x8000000000000001),smax_value=9223372032559808513 (0x7fffffff00000001),umin_value=1,umax_value=0xffffffff00000001,var_off=(0x1; 0xffffffff00000000),s32_min_value=1,s32_max_value=1,u32_min_value=1,u32_max_value=1) R3_w=inv4294967298 R10=fp0 9: (5f) r2 &= r3 10: R0_w=inv1337 R1=ctx(id=0,off=0,imm=0) R2_w=inv(id=0,smin_value=0,smax_value=4294967296 (0x100000000),umin_value=0,umax_value=0x100000000,var_off=(0x0; 0x100000000),s32_min_value=0,s32_max_value=0,u32_min_value=0,u32_max_value=0) R3_w=inv4294967298 R10=fp0 [...] Fixes: 3f50f132d840 ("bpf: Verifier, do explicit ALU32 bounds tracking") Fixes: 2921c90d4718 ("bpf: Fix a verifier failure with xor") Reported-by: Manfred Paul (@_manfp) Reported-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Borkmann Reviewed-by: John Fastabend Acked-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 757476c91c98..9352a1b7de2d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7084,11 +7084,10 @@ static void scalar32_min_max_and(struct bpf_reg_state *dst_reg, s32 smin_val = src_reg->s32_min_value; u32 umax_val = src_reg->u32_max_value; - /* Assuming scalar64_min_max_and will be called so its safe - * to skip updating register for known 32-bit case. - */ - if (src_known && dst_known) + if (src_known && dst_known) { + __mark_reg32_known(dst_reg, var32_off.value); return; + } /* We get our minimum from the var_off, since that's inherently * bitwise. Our maximum is the minimum of the operands' maxima. @@ -7108,7 +7107,6 @@ static void scalar32_min_max_and(struct bpf_reg_state *dst_reg, dst_reg->s32_min_value = dst_reg->u32_min_value; dst_reg->s32_max_value = dst_reg->u32_max_value; } - } static void scalar_min_max_and(struct bpf_reg_state *dst_reg, @@ -7155,11 +7153,10 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg, s32 smin_val = src_reg->s32_min_value; u32 umin_val = src_reg->u32_min_value; - /* Assuming scalar64_min_max_or will be called so it is safe - * to skip updating register for known case. - */ - if (src_known && dst_known) + if (src_known && dst_known) { + __mark_reg32_known(dst_reg, var32_off.value); return; + } /* We get our maximum from the var_off, and our minimum is the * maximum of the operands' minima @@ -7224,11 +7221,10 @@ static void scalar32_min_max_xor(struct bpf_reg_state *dst_reg, struct tnum var32_off = tnum_subreg(dst_reg->var_off); s32 smin_val = src_reg->s32_min_value; - /* Assuming scalar64_min_max_xor will be called so it is safe - * to skip updating register for known case. - */ - if (src_known && dst_known) + if (src_known && dst_known) { + __mark_reg32_known(dst_reg, var32_off.value); return; + } /* We get both minimum and maximum from the var32_off. */ dst_reg->u32_min_value = var32_off.value; -- cgit v1.2.3 From 35f3f8504c3b60a1ae5576e178b27fc0ddd6157d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:42 +0300 Subject: spi: Switch to signed types for *_native_cs SPI controller fields While fixing undefined behaviour the commit f60d7270c8a3 ("spi: Avoid undefined behaviour when counting unused native CSs") missed the case when all CSs are GPIOs and thus unused_native_cs will be evaluated to -1 in unsigned representation. This will falsely trigger a condition in the spi_get_gpio_descs(). Switch to signed types for *_native_cs SPI controller fields to fix above. Fixes: f60d7270c8a3 ("spi: Avoid undefined behaviour when counting unused native CSs") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131242.49455-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 360a3bc767ca..74239d65c7fd 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -644,8 +644,8 @@ struct spi_controller { int *cs_gpios; struct gpio_desc **cs_gpiods; bool use_gpio_descriptors; - u8 unused_native_cs; - u8 max_native_cs; + s8 unused_native_cs; + s8 max_native_cs; /* statistics */ struct spi_statistics statistics; -- cgit v1.2.3 From 4b81ccebaeee885ab1aa1438133f2991e3a2b6ea Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 27 Apr 2021 10:12:12 -0300 Subject: bpf, ringbuf: Deny reserve of buffers larger than ringbuf A BPF program might try to reserve a buffer larger than the ringbuf size. If the consumer pointer is way ahead of the producer, that would be successfully reserved, allowing the BPF program to read or write out of the ringbuf allocated area. Reported-by: Ryota Shiga (Flatt Security) Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it") Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Daniel Borkmann Acked-by: Andrii Nakryiko Acked-by: Alexei Starovoitov --- kernel/bpf/ringbuf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c index f25b719ac786..b86d80c9cd59 100644 --- a/kernel/bpf/ringbuf.c +++ b/kernel/bpf/ringbuf.c @@ -315,6 +315,9 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size) return NULL; len = round_up(size + BPF_RINGBUF_HDR_SZ, 8); + if (len > rb->mask + 1) + return NULL; + cons_pos = smp_load_acquire(&rb->consumer_pos); if (in_nmi()) { -- cgit v1.2.3 From 04ea3086c4d73da7009de1e84962a904139af219 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 4 May 2021 16:38:00 -0700 Subject: bpf: Prevent writable memory-mapping of read-only ringbuf pages Only the very first page of BPF ringbuf that contains consumer position counter is supposed to be mapped as writeable by user-space. Producer position is read-only and can be modified only by the kernel code. BPF ringbuf data pages are read-only as well and are not meant to be modified by user-code to maintain integrity of per-record headers. This patch allows to map only consumer position page as writeable and everything else is restricted to be read-only. remap_vmalloc_range() internally adds VM_DONTEXPAND, so all the established memory mappings can't be extended, which prevents any future violations through mremap()'ing. Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it") Reported-by: Ryota Shiga (Flatt Security) Reported-by: Thadeu Lima de Souza Cascardo Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- kernel/bpf/ringbuf.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c index b86d80c9cd59..84b3b35fc0d0 100644 --- a/kernel/bpf/ringbuf.c +++ b/kernel/bpf/ringbuf.c @@ -221,25 +221,20 @@ static int ringbuf_map_get_next_key(struct bpf_map *map, void *key, return -ENOTSUPP; } -static size_t bpf_ringbuf_mmap_page_cnt(const struct bpf_ringbuf *rb) -{ - size_t data_pages = (rb->mask + 1) >> PAGE_SHIFT; - - /* consumer page + producer page + 2 x data pages */ - return RINGBUF_POS_PAGES + 2 * data_pages; -} - static int ringbuf_map_mmap(struct bpf_map *map, struct vm_area_struct *vma) { struct bpf_ringbuf_map *rb_map; - size_t mmap_sz; rb_map = container_of(map, struct bpf_ringbuf_map, map); - mmap_sz = bpf_ringbuf_mmap_page_cnt(rb_map->rb) << PAGE_SHIFT; - - if (vma->vm_pgoff * PAGE_SIZE + (vma->vm_end - vma->vm_start) > mmap_sz) - return -EINVAL; + if (vma->vm_flags & VM_WRITE) { + /* allow writable mapping for the consumer_pos only */ + if (vma->vm_pgoff != 0 || vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EPERM; + } else { + vma->vm_flags &= ~VM_MAYWRITE; + } + /* remap_vmalloc_range() checks size and offset constraints */ return remap_vmalloc_range(vma, rb_map->rb, vma->vm_pgoff + RINGBUF_PGOFF); } -- cgit v1.2.3 From 0919a3acc0c87049a7d787c4b8b9e64bd7c59eb3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 May 2021 10:17:07 +0900 Subject: ASoC: simple-card: add simple_parse_node() Original commit 59c35c44a9cf89a83a9 ("ASoC: simple-card: add simple_parse_node()") was reverted, and this is remake version. Parse dai/tdm/clk are common for both CPU/Codec node. This patch creates simple_parse_node() for it and share the code. Reported-by: "kernelci.org bot" Fixes: 25c4a9b614f101bb9f3 ("ASoC: simple-card: Fix breakage on kontron-sl28-var3-ads2") Fixes: 59c35c44a9cf89a83a9 ("ASoC: simple-card: add simple_parse_node()") Signed-off-by: Kuninori Morimoto Tested-by: Michael Walle Link: https://lore.kernel.org/r/87h7jaax2k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 107 ++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a1373be4558f..57ab89be1b4b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -93,12 +93,11 @@ static void simple_parse_convert(struct device *dev, } static void simple_parse_mclk_fs(struct device_node *top, - struct device_node *cpu, - struct device_node *codec, + struct device_node *np, struct simple_dai_props *props, char *prefix) { - struct device_node *node = of_get_parent(cpu); + struct device_node *node = of_get_parent(np); char prop[128]; snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX); @@ -106,12 +105,50 @@ static void simple_parse_mclk_fs(struct device_node *top, snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(node, prop, &props->mclk_fs); - of_property_read_u32(cpu, prop, &props->mclk_fs); - of_property_read_u32(codec, prop, &props->mclk_fs); + of_property_read_u32(np, prop, &props->mclk_fs); of_node_put(node); } +static int simple_parse_node(struct asoc_simple_priv *priv, + struct device_node *np, + struct link_info *li, + char *prefix, + int *cpu) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct snd_soc_dai_link_component *dlc; + struct asoc_simple_dai *dai; + int ret; + + if (cpu) { + dlc = asoc_link_to_cpu(dai_link, 0); + dai = simple_props_to_dai_cpu(dai_props, 0); + } else { + dlc = asoc_link_to_codec(dai_link, 0); + dai = simple_props_to_dai_codec(dai_props, 0); + } + + simple_parse_mclk_fs(top, np, dai_props, prefix); + + ret = asoc_simple_parse_dai(np, dlc, cpu); + if (ret) + return ret; + + ret = asoc_simple_parse_clk(dev, np, dai, dlc); + if (ret) + return ret; + + ret = asoc_simple_parse_tdm(np, dai); + if (ret) + return ret; + + return 0; +} + static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *np, struct device_node *codec, @@ -121,10 +158,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *dai; - struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); - struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; @@ -132,13 +165,13 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dev_dbg(dev, "link_of DPCM (%pOF)\n", np); - li->link++; - /* For single DAI link & old style of DT node */ if (is_top) prefix = PREFIX; if (li->cpu) { + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); int is_single_links = 0; /* Codec is dummy */ @@ -147,13 +180,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = simple_props_to_dai_cpu(dai_props, 0); - - ret = asoc_simple_parse_dai(np, cpus, &is_single_links); - if (ret) - goto out_put_node; - - ret = asoc_simple_parse_clk(dev, np, dai, cpus); + ret = simple_parse_node(priv, np, li, prefix, &is_single_links); if (ret < 0) goto out_put_node; @@ -166,6 +193,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, asoc_simple_canonicalize_cpu(cpus, is_single_links); asoc_simple_canonicalize_platform(platforms, cpus); } else { + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_codec_conf *cconf; /* CPU is dummy */ @@ -174,14 +202,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = simple_props_to_dai_codec(dai_props, 0); cconf = simple_props_to_codec_conf(dai_props, 0); - ret = asoc_simple_parse_dai(np, codecs, NULL); - if (ret < 0) - goto out_put_node; - - ret = asoc_simple_parse_clk(dev, np, dai, codecs); + ret = simple_parse_node(priv, np, li, prefix, NULL); if (ret < 0) goto out_put_node; @@ -201,11 +224,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, } simple_parse_convert(dev, np, &dai_props->adata); - simple_parse_mclk_fs(top, np, codec, dai_props, prefix); - - ret = asoc_simple_parse_tdm(np, dai); - if (ret) - goto out_put_node; ret = asoc_simple_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -218,6 +236,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->init = asoc_simple_dai_init; out_put_node: + li->link++; + of_node_put(node); return ret; } @@ -230,13 +250,9 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); - struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); - struct device_node *top = dev->of_node; struct device_node *cpu = NULL; struct device_node *node = NULL; struct device_node *plat = NULL; @@ -246,7 +262,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, cpu = np; node = of_get_parent(np); - li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); @@ -262,13 +277,11 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); - - ret = asoc_simple_parse_dai(cpu, cpus, &single_cpu); + ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_dai(codec, codecs, NULL); + ret = simple_parse_node(priv, codec, li, prefix, NULL); if (ret < 0) goto dai_link_of_err; @@ -276,22 +289,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_tdm(cpu, cpu_dai); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_tdm(codec, codec_dai); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, cpus); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_clk(dev, codec, codec_dai, codecs); - if (ret < 0) - goto dai_link_of_err; - ret = asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", cpus->dai_name, @@ -309,6 +306,8 @@ dai_link_of_err: of_node_put(plat); of_node_put(node); + li->link++; + return ret; } -- cgit v1.2.3 From 6ad76b573bb63ef229cf60386cc38c6e7c7625d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 May 2021 10:17:47 +0900 Subject: ASoC: simple-card: add simple_link_init() Original commit 434392271afcff350fe ("ASoC: simple-card: add simple_link_init()") are rejected, and this is remake version of it. This patch adds simple_link_init() and share dai_link setting code. Reported-by: "kernelci.org bot" Fixes: 25c4a9b614f101bb9f3 ("ASoC: simple-card: Fix breakage on kontron-sl28-var3-ads2") Fixes: 434392271afcff350fe ("ASoC: simple-card: add simple_link_init()") Signed-off-by: Kuninori Morimoto Tested-by: Michael Walle Link: https://lore.kernel.org/r/87fsyuax1g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 61 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 57ab89be1b4b..0015f534d42d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -149,6 +149,27 @@ static int simple_parse_node(struct asoc_simple_priv *priv, return 0; } +static int simple_link_init(struct asoc_simple_priv *priv, + struct device_node *node, + struct device_node *codec, + struct link_info *li, + char *prefix, char *name) +{ + struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + int ret; + + ret = asoc_simple_parse_daifmt(dev, node, codec, + prefix, &dai_link->dai_fmt); + if (ret < 0) + return 0; + + dai_link->init = asoc_simple_dai_init; + dai_link->ops = &simple_ops; + + return asoc_simple_set_dailink_name(dev, dai_link, name); +} + static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *np, struct device_node *codec, @@ -161,6 +182,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; + char dai_name[64]; int ret; dev_dbg(dev, "link_of DPCM (%pOF)\n", np); @@ -184,11 +206,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "fe.%s", - cpus->dai_name); - if (ret < 0) - goto out_put_node; + snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name); asoc_simple_canonicalize_cpu(cpus, is_single_links); asoc_simple_canonicalize_platform(platforms, cpus); @@ -208,11 +226,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "be.%s", - codecs->dai_name); - if (ret < 0) - goto out_put_node; + snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name); /* check "prefix" from top node */ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, @@ -225,15 +239,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, simple_parse_convert(dev, np, &dai_props->adata); - ret = asoc_simple_parse_daifmt(dev, node, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - goto out_put_node; - snd_soc_dai_link_set_capabilities(dai_link); - dai_link->ops = &simple_ops; - dai_link->init = asoc_simple_dai_init; + ret = simple_link_init(priv, node, codec, li, prefix, dai_name); out_put_node: li->link++; @@ -256,6 +264,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct device_node *cpu = NULL; struct device_node *node = NULL; struct device_node *plat = NULL; + char dai_name[64]; char prop[128]; char *prefix = ""; int ret, single_cpu = 0; @@ -272,11 +281,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - ret = asoc_simple_parse_daifmt(dev, node, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - goto dai_link_of_err; - ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu); if (ret < 0) goto dai_link_of_err; @@ -289,19 +293,14 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "%s-%s", - cpus->dai_name, - codecs->dai_name); - if (ret < 0) - goto dai_link_of_err; - - dai_link->ops = &simple_ops; - dai_link->init = asoc_simple_dai_init; + snprintf(dai_name, sizeof(dai_name), + "%s-%s", cpus->dai_name, codecs->dai_name); asoc_simple_canonicalize_cpu(cpus, single_cpu); asoc_simple_canonicalize_platform(platforms, cpus); + ret = simple_link_init(priv, node, codec, li, prefix, dai_name); + dai_link_of_err: of_node_put(plat); of_node_put(node); -- cgit v1.2.3 From 28c268d3acdd4cbcd2ac320b85609e77f84e74a7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 May 2021 17:01:45 +0200 Subject: ASoC: Intel: bytcr_rt5640: Add quirk for the Glavey TM800A550L tablet Add a quirk for the Glavey TM800A550L tablet, this BYTCR tablet has no CHAN package in its ACPI tables and uses SSP0-AIF1 rather then SSP0-AIF2 which is the default for BYTCR devices. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210508150146.28403-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index df2f5d55e8ff..b42fa292d408 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -574,6 +574,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { /* Glavey TM800A550L */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), -- cgit v1.2.3 From f0353e1f53f92f7b3da91e6669f5d58ee222ebe8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 May 2021 17:01:46 +0200 Subject: ASoC: Intel: bytcr_rt5640: Add quirk for the Lenovo Miix 3-830 tablet The Lenovo Miix 3-830 tablet has only 1 speaker, has an internal analog mic on IN1 and uses JD2 for jack-detect, add a quirk to automatically apply these settings on Lenovo Miix 3-830 tablets. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210508150146.28403-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b42fa292d408..22dbd9d93c1e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -663,6 +663,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MONO_SPEAKER | BYT_RT5640_MCLK_EN), }, + { /* Lenovo Miix 3-830 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 3-830"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Linx Linx7 tablet */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LINX"), -- cgit v1.2.3 From f8090ffc91ffd788a73d4e6b5ca3107c94d9ec27 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 May 2021 10:17:57 +0900 Subject: ASoC: audio-graph: tidyup graph_dai_link_of_dpcm() Use local variable at local area only. Signed-off-by: Kuninori Morimoto Tested-by: Michael Walle Link: https://lore.kernel.org/r/87eeeeax16.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2c8a2fcb7922..0159a4576e9c 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -276,24 +276,19 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; - struct device_node *port; - struct device_node *ports; - struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); - struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); char dai_name[64]; int ret; - port = of_get_parent(ep); - ports = of_get_parent(port); - dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); if (li->cpu) { + struct snd_soc_card *card = simple_priv_to_card(priv); + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + /* Codec is dummy */ /* FE settings */ @@ -302,7 +297,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret) - goto out_put_node; + return ret; snprintf(dai_name, sizeof(dai_name), "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); @@ -319,7 +314,10 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (card->component_chaining && !soc_component_is_pcm(cpus)) dai_link->no_pcm = 1; } else { - struct snd_soc_codec_conf *cconf; + struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct device_node *port; + struct device_node *ports; /* CPU is dummy */ @@ -327,22 +325,25 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - cconf = simple_props_to_codec_conf(dai_props, 0); - ret = graph_parse_node(priv, codec_ep, li, 0); if (ret < 0) - goto out_put_node; + return ret; snprintf(dai_name, sizeof(dai_name), "be.%pOFP.%s", codecs->of_node, codecs->dai_name); /* check "prefix" from top node */ + port = of_get_parent(ep); + ports = of_get_parent(port); snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); if (of_node_name_eq(ports, "ports")) snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix"); + + of_node_put(ports); + of_node_put(port); } graph_parse_convert(dev, ep, &dai_props->adata); @@ -351,11 +352,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); -out_put_node: li->link++; - of_node_put(ports); - of_node_put(port); return ret; } -- cgit v1.2.3 From 582f3503f96543f3afbaaaa085755fd167a0f71e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 May 2021 10:18:48 +0900 Subject: ASoC: audio-graph: tidyup graph_parse_node() audio-graph is using cpus->dai_name / codecs->dai_name for dailink->name. In graph_parse_node(), xxx->dai_name is got by snd_soc_get_dai_name(), but it might be removed soon by asoc_simple_canonicalize_cpu(). The order should be *1) call snd_soc_get_dai_name() 2) create dailink name *3) call asoc_simple_canonicalize_cpu() * are implemented in graph_parse_node(). This patch remove 3) from graph_parse_node() Reported-by: "kernelci.org bot" Fixes: 8859f809c7d5813 ("ASoC: audio-graph: add graph_parse_node()") Fixes: e51237b8d305225 ("ASoC: audio-graph: add graph_link_init()") Signed-off-by: Kuninori Morimoto Tested-by: Michael Walle Link: https://lore.kernel.org/r/87cztyawzr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0159a4576e9c..5e71382467e8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -209,7 +209,7 @@ static void graph_parse_mclk_fs(struct device_node *top, static int graph_parse_node(struct asoc_simple_priv *priv, struct device_node *ep, struct link_info *li, - int is_cpu) + int *cpu) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -217,9 +217,9 @@ static int graph_parse_node(struct asoc_simple_priv *priv, struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct snd_soc_dai_link_component *dlc; struct asoc_simple_dai *dai; - int ret, single = 0; + int ret; - if (is_cpu) { + if (cpu) { dlc = asoc_link_to_cpu(dai_link, 0); dai = simple_props_to_dai_cpu(dai_props, 0); } else { @@ -229,7 +229,7 @@ static int graph_parse_node(struct asoc_simple_priv *priv, graph_parse_mclk_fs(top, ep, dai_props); - ret = asoc_simple_parse_dai(ep, dlc, &single); + ret = asoc_simple_parse_dai(ep, dlc, cpu); if (ret < 0) return ret; @@ -241,9 +241,6 @@ static int graph_parse_node(struct asoc_simple_priv *priv, if (ret < 0) return ret; - if (is_cpu) - asoc_simple_canonicalize_cpu(dlc, single); - return 0; } @@ -288,6 +285,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + int is_single_links = 0; /* Codec is dummy */ @@ -295,7 +293,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - ret = graph_parse_node(priv, cpu_ep, li, 1); + ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret) return ret; @@ -313,6 +311,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, */ if (card->component_chaining && !soc_component_is_pcm(cpus)) dai_link->no_pcm = 1; + + asoc_simple_canonicalize_cpu(cpus, is_single_links); } else { struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); @@ -325,7 +325,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - ret = graph_parse_node(priv, codec_ep, li, 0); + ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) return ret; @@ -367,20 +367,23 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); char dai_name[64]; - int ret; + int ret, is_single_links = 0; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); - ret = graph_parse_node(priv, cpu_ep, li, 1); + ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret < 0) return ret; - ret = graph_parse_node(priv, codec_ep, li, 0); + ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) return ret; snprintf(dai_name, sizeof(dai_name), "%s-%s", cpus->dai_name, codecs->dai_name); + + asoc_simple_canonicalize_cpu(cpus, is_single_links); + ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); if (ret < 0) return ret; -- cgit v1.2.3 From 0fad605fb0bdc00d8ad78696300ff2fbdee6e048 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 11 May 2021 14:28:55 +0100 Subject: ASoC: cs42l42: Regmap must use_single_read/write cs42l42 does not support standard burst transfers so the use_single_read and use_single_write flags must be set in the regmap config. Because of this bug, the patch: commit 0a0eb567e1d4 ("ASoC: cs42l42: Minor error paths fixups") broke cs42l42 probe() because without the use_single_* flags it causes regmap to issue a burst read. However, the missing use_single_* could cause problems anyway because the regmap cache can attempt burst transfers if these flags are not set. Fixes: 2c394ca79604 ("ASoC: Add support for CS42L42 codec") Signed-off-by: Richard Fitzgerald Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210511132855.27159-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index bf982e145e94..77473c226f9e 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -399,6 +399,9 @@ static const struct regmap_config cs42l42_regmap = { .reg_defaults = cs42l42_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, }; static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); -- cgit v1.2.3 From 2ee4c8a268764e751ee44dfffa76c813cfc27aee Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 11 May 2021 16:00:03 +0100 Subject: MAINTAINERS: Add Krzysztof as PCI host/endpoint controllers reviewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Krzysztof has been carrying out PCI patches review for a long time and he has been instrumental in driving PCI host/endpoint controller drivers improvements. Make his role official. Link: https://lore.kernel.org/r/20210511150003.1592-1-lorenzo.pieralisi@arm.com Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Cc: Kishon Vijay Abraham I Cc: Krzysztof Wilczyński --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..9755bf97658d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14110,6 +14110,7 @@ F: drivers/pci/controller/pci-v3-semi.c PCI ENDPOINT SUBSYSTEM M: Kishon Vijay Abraham I M: Lorenzo Pieralisi +R: Krzysztof Wilczyński L: linux-pci@vger.kernel.org S: Supported F: Documentation/PCI/endpoint/* @@ -14158,6 +14159,7 @@ F: drivers/pci/controller/pci-xgene-msi.c PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS M: Lorenzo Pieralisi R: Rob Herring +R: Krzysztof Wilczyński L: linux-pci@vger.kernel.org S: Supported Q: http://patchwork.ozlabs.org/project/linux-pci/list/ -- cgit v1.2.3 From 965a7d72e798eb7af0aa67210e37cf7ecd1c9cad Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Tue, 11 May 2021 20:02:42 +0200 Subject: mac80211: assure all fragments are encrypted Do not mix plaintext and encrypted fragments in protected Wi-Fi networks. This fixes CVE-2020-26147. Previously, an attacker was able to first forward a legitimate encrypted fragment towards a victim, followed by a plaintext fragment. The encrypted and plaintext fragment would then be reassembled. For further details see Section 6.3 and Appendix D in the paper "Fragment and Forge: Breaking Wi-Fi Through Frame Aggregation and Fragmentation". Because of this change there are now two equivalent conditions in the code to determine if a received fragment requires sequential PNs, so we also move this test to a separate function to make the code easier to maintain. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.30c4394bb835.I5acfdb552cc1d20c339c262315950b3eac491397@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 62047e93e217..65fc674e27cc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2194,6 +2194,16 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } +static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc) +{ + return rx->key && + (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || + rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && + ieee80211_has_protected(fc); +} + static ieee80211_rx_result debug_noinline ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) { @@ -2238,12 +2248,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) /* This is the first fragment of a new frame. */ entry = ieee80211_reassemble_add(rx->sdata, frag, seq, rx->seqno_idx, &(rx->skb)); - if (rx->key && - (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || - rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || - rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || - rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && - ieee80211_has_protected(fc)) { + if (requires_sequential_pn(rx, fc)) { int queue = rx->security_idx; /* Store CCMP/GCMP PN so that we can verify that the @@ -2285,11 +2290,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; int queue; - if (!rx->key || - (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP && - rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 && - rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP && - rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256)) + if (!requires_sequential_pn(rx, fc)) return RX_DROP_UNUSABLE; memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { -- cgit v1.2.3 From 94034c40ab4a3fcf581fbc7f8fdf4e29943c4a24 Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Tue, 11 May 2021 20:02:43 +0200 Subject: mac80211: prevent mixed key and fragment cache attacks Simultaneously prevent mixed key attacks (CVE-2020-24587) and fragment cache attacks (CVE-2020-24586). This is accomplished by assigning a unique color to every key (per interface) and using this to track which key was used to decrypt a fragment. When reassembling frames, it is now checked whether all fragments were decrypted using the same key. To assure that fragment cache attacks are also prevented, the ID that is assigned to keys is unique even over (re)associations and (re)connects. This means fragments separated by a (re)association or (re)connect will not be reassembled. Because mac80211 now also prevents the reassembly of mixed encrypted and plaintext fragments, all cache attacks are prevented. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.3f8290e59823.I622a67769ed39257327a362cfc09c812320eb979@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/key.c | 7 +++++++ net/mac80211/key.h | 2 ++ net/mac80211/rx.c | 6 ++++++ 4 files changed, 16 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8fcbaa1eedf3..874ffe7819e5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -97,6 +97,7 @@ struct ieee80211_fragment_entry { u8 rx_queue; bool check_sequential_pn; /* needed for CCMP/GCMP */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ + unsigned int key_color; }; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 56c068cb49c4..f695fc80088b 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -799,6 +799,7 @@ int ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { + static atomic_t key_color = ATOMIC_INIT(0); struct ieee80211_key *old_key; int idx = key->conf.keyidx; bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; @@ -850,6 +851,12 @@ int ieee80211_key_link(struct ieee80211_key *key, key->sdata = sdata; key->sta = sta; + /* + * Assign a unique ID to every key so we can easily prevent mixed + * key and fragment cache attacks. + */ + key->color = atomic_inc_return(&key_color); + increment_tailroom_need_count(sdata); ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 7ad72e9b4991..1e326c89d721 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -128,6 +128,8 @@ struct ieee80211_key { } debugfs; #endif + unsigned int color; + /* * key config, must be last because it contains key * material as variable length member diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 65fc674e27cc..531232b91bc4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2255,6 +2255,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) * next fragment has a sequential PN value. */ entry->check_sequential_pn = true; + entry->key_color = rx->key->color; memcpy(entry->last_pn, rx->key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN); @@ -2292,6 +2293,11 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (!requires_sequential_pn(rx, fc)) return RX_DROP_UNUSABLE; + + /* Prevent mixed key and fragment cache attacks */ + if (entry->key_color != rx->key->color) + return RX_DROP_UNUSABLE; + memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; -- cgit v1.2.3 From a1d5ff5651ea592c67054233b14b30bf4452999c Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Tue, 11 May 2021 20:02:44 +0200 Subject: mac80211: properly handle A-MSDUs that start with an RFC 1042 header Properly parse A-MSDUs whose first 6 bytes happen to equal a rfc1042 header. This can occur in practice when the destination MAC address equals AA:AA:03:00:00:00. More importantly, this simplifies the next patch to mitigate A-MSDU injection attacks. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.0b2b886492f0.I23dd5d685fe16d3b0ec8106e8f01b59f499dffed@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++-- net/mac80211/rx.c | 2 +- net/wireless/util.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5224f885a99a..58c2cd417e89 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5760,7 +5760,7 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); */ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, const u8 *addr, enum nl80211_iftype iftype, - u8 data_offset); + u8 data_offset, bool is_amsdu); /** * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 @@ -5772,7 +5772,7 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, enum nl80211_iftype iftype) { - return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype, 0); + return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype, 0, false); } /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 531232b91bc4..f14d32a5001d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2682,7 +2682,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset) if (ieee80211_data_to_8023_exthdr(skb, ðhdr, rx->sdata->vif.addr, rx->sdata->vif.type, - data_offset)) + data_offset, true)) return RX_DROP_UNUSABLE; ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, diff --git a/net/wireless/util.c b/net/wireless/util.c index 382c5262d997..39966a873e40 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -542,7 +542,7 @@ EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, const u8 *addr, enum nl80211_iftype iftype, - u8 data_offset) + u8 data_offset, bool is_amsdu) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct { @@ -629,7 +629,7 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); tmp.h_proto = payload.proto; - if (likely((ether_addr_equal(payload.hdr, rfc1042_header) && + if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && tmp.h_proto != htons(ETH_P_AARP) && tmp.h_proto != htons(ETH_P_IPX)) || ether_addr_equal(payload.hdr, bridge_tunnel_header))) -- cgit v1.2.3 From 2b8a1fee3488c602aca8bea004a087e60806a5cf Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Tue, 11 May 2021 20:02:45 +0200 Subject: cfg80211: mitigate A-MSDU aggregation attacks Mitigate A-MSDU injection attacks (CVE-2020-24588) by detecting if the destination address of a subframe equals an RFC1042 (i.e., LLC/SNAP) header, and if so dropping the complete A-MSDU frame. This mitigates known attacks, although new (unknown) aggregation-based attacks may remain possible. This defense works because in A-MSDU aggregation injection attacks, a normal encrypted Wi-Fi frame is turned into an A-MSDU frame. This means the first 6 bytes of the first A-MSDU subframe correspond to an RFC1042 header. In other words, the destination MAC address of the first A-MSDU subframe contains the start of an RFC1042 header during an aggregation attack. We can detect this and thereby prevent this specific attack. For details, see Section 7.2 of "Fragment and Forge: Breaking Wi-Fi Through Frame Aggregation and Fragmentation". Note that for kernel 4.9 and above this patch depends on "mac80211: properly handle A-MSDUs that start with a rfc1042 header". Otherwise this patch has no impact and attacks will remain possible. Cc: stable@vger.kernel.org Signed-off-by: Mathy Vanhoef Link: https://lore.kernel.org/r/20210511200110.25d93176ddaf.I9e265b597f2cd23eb44573f35b625947b386a9de@changeid Signed-off-by: Johannes Berg --- net/wireless/util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/util.c b/net/wireless/util.c index 39966a873e40..7ec021a610ae 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -771,6 +771,9 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, remaining = skb->len - offset; if (subframe_len > remaining) goto purge; + /* mitigate A-MSDU aggregation injection attacks */ + if (ether_addr_equal(eth.h_dest, rfc1042_header)) + goto purge; offset += sizeof(struct ethhdr); last = remaining <= subframe_len + padding; -- cgit v1.2.3 From 270032a2a9c4535799736142e1e7c413ca7b836e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 May 2021 20:02:46 +0200 Subject: mac80211: drop A-MSDUs on old ciphers With old ciphers (WEP and TKIP) we shouldn't be using A-MSDUs since A-MSDUs are only supported if we know that they are, and the only practical way for that is HT support which doesn't support old ciphers. However, we would normally accept them anyway. Since we check the MMIC before deaggregating A-MSDUs, and the A-MSDU bit in the QoS header is not protected in TKIP (or WEP), this enables attacks similar to CVE-2020-24588. To prevent that, drop A-MSDUs completely with old ciphers. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210511200110.076543300172.I548e6e71f1ee9cad4b9a37bf212ae7db723587aa@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f14d32a5001d..8a72d48ad6e0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include @@ -2739,6 +2739,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(hdr->addr1)) return RX_DROP_UNUSABLE; + if (rx->key) { + /* + * We should not receive A-MSDUs on pre-HT connections, + * and HT connections cannot use old ciphers. Thus drop + * them, as in those cases we couldn't even have SPP + * A-MSDUs or such. + */ + switch (rx->key->conf.cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + return RX_DROP_UNUSABLE; + default: + break; + } + } + return __ieee80211_rx_h_amsdu(rx, 0); } -- cgit v1.2.3 From 3a11ce08c45b50d69c891d71760b7c5b92074709 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 May 2021 20:02:47 +0200 Subject: mac80211: add fragment cache to sta_info Prior patches protected against fragmentation cache attacks by coloring keys, but this shows that it can lead to issues when multiple stations use the same sequence number. Add a fragment cache to struct sta_info (in addition to the one in the interface) to separate fragments for different stations properly. This then automatically clear most of the fragment cache when a station disconnects (or reassociates) from an AP, or when client interfaces disconnect from the network, etc. On the way, also fix the comment there since this brings us in line with the recommendation in 802.11-2016 ("An AP should support ..."). Additionally, remove a useless condition (since there's no problem purging an already empty list). Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210511200110.fc35046b0d52.I1ef101e3784d13e8f6600d83de7ec9a3a45bcd52@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 26 ++++---------------------- net/mac80211/iface.c | 11 +++-------- net/mac80211/rx.c | 41 ++++++++++++++++++++++++++++++----------- net/mac80211/sta_info.c | 6 +++++- net/mac80211/sta_info.h | 32 +++++++++++++++++++++++++++++++- 5 files changed, 73 insertions(+), 43 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 874ffe7819e5..4c714375bad0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -50,12 +50,6 @@ struct ieee80211_local; #define IEEE80211_ENCRYPT_HEADROOM 8 #define IEEE80211_ENCRYPT_TAILROOM 18 -/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent - * reception of at least three fragmented frames. This limit can be increased - * by changing this define, at the cost of slower frame reassembly and - * increased memory use (about 2 kB of RAM per entry). */ -#define IEEE80211_FRAGMENT_MAX 4 - /* power level hasn't been configured (or set to automatic) */ #define IEEE80211_UNSET_POWER_LEVEL INT_MIN @@ -88,19 +82,6 @@ extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS]; #define IEEE80211_MAX_NAN_INSTANCE_ID 255 -struct ieee80211_fragment_entry { - struct sk_buff_head skb_list; - unsigned long first_frag_time; - u16 seq; - u16 extra_len; - u16 last_frag; - u8 rx_queue; - bool check_sequential_pn; /* needed for CCMP/GCMP */ - u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ - unsigned int key_color; -}; - - struct ieee80211_bss { u32 device_ts_beacon, device_ts_presp; @@ -903,9 +884,7 @@ struct ieee80211_sub_if_data { char name[IFNAMSIZ]; - /* Fragment table for host-based reassembly */ - struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; - unsigned int fragment_next; + struct ieee80211_fragment_cache frags; /* TID bitmap for NoAck policy */ u16 noack_map; @@ -2321,4 +2300,7 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, #define debug_noinline #endif +void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache); +void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache); + #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7032a2b59249..2e2f73a4aa73 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include #include @@ -677,16 +677,12 @@ static void ieee80211_set_multicast_list(struct net_device *dev) */ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) { - int i; - /* free extra data */ ieee80211_free_keys(sdata, false); ieee80211_debugfs_remove_netdev(sdata); - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - __skb_queue_purge(&sdata->fragments[i].skb_list); - sdata->fragment_next = 0; + ieee80211_destroy_frag_cache(&sdata->frags); if (ieee80211_vif_is_mesh(&sdata->vif)) ieee80211_mesh_teardown_sdata(sdata); @@ -1930,8 +1926,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata->wdev.wiphy = local->hw.wiphy; sdata->local = local; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - skb_queue_head_init(&sdata->fragments[i].skb_list); + ieee80211_init_frag_cache(&sdata->frags); INIT_LIST_HEAD(&sdata->key_list); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8a72d48ad6e0..7212a1bebd0c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2123,19 +2123,34 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return result; } +void ieee80211_init_frag_cache(struct ieee80211_fragment_cache *cache) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cache->entries); i++) + skb_queue_head_init(&cache->entries[i].skb_list); +} + +void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cache->entries); i++) + __skb_queue_purge(&cache->entries[i].skb_list); +} + static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, +ieee80211_reassemble_add(struct ieee80211_fragment_cache *cache, unsigned int frag, unsigned int seq, int rx_queue, struct sk_buff **skb) { struct ieee80211_fragment_entry *entry; - entry = &sdata->fragments[sdata->fragment_next++]; - if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) - sdata->fragment_next = 0; + entry = &cache->entries[cache->next++]; + if (cache->next >= IEEE80211_FRAGMENT_MAX) + cache->next = 0; - if (!skb_queue_empty(&entry->skb_list)) - __skb_queue_purge(&entry->skb_list); + __skb_queue_purge(&entry->skb_list); __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ *skb = NULL; @@ -2150,14 +2165,14 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, } static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, +ieee80211_reassemble_find(struct ieee80211_fragment_cache *cache, unsigned int frag, unsigned int seq, int rx_queue, struct ieee80211_hdr *hdr) { struct ieee80211_fragment_entry *entry; int i, idx; - idx = sdata->fragment_next; + idx = cache->next; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { struct ieee80211_hdr *f_hdr; struct sk_buff *f_skb; @@ -2166,7 +2181,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, if (idx < 0) idx = IEEE80211_FRAGMENT_MAX - 1; - entry = &sdata->fragments[idx]; + entry = &cache->entries[idx]; if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || entry->rx_queue != rx_queue || entry->last_frag + 1 != frag) @@ -2207,6 +2222,7 @@ static bool requires_sequential_pn(struct ieee80211_rx_data *rx, __le16 fc) static ieee80211_rx_result debug_noinline ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) { + struct ieee80211_fragment_cache *cache = &rx->sdata->frags; struct ieee80211_hdr *hdr; u16 sc; __le16 fc; @@ -2228,6 +2244,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) goto out_no_led; } + if (rx->sta) + cache = &rx->sta->frags; + if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) goto out; @@ -2246,7 +2265,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (frag == 0) { /* This is the first fragment of a new frame. */ - entry = ieee80211_reassemble_add(rx->sdata, frag, seq, + entry = ieee80211_reassemble_add(cache, frag, seq, rx->seqno_idx, &(rx->skb)); if (requires_sequential_pn(rx, fc)) { int queue = rx->security_idx; @@ -2274,7 +2293,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) /* This is a fragment for a frame that should already be pending in * fragment cache. Add this fragment to the end of the pending entry. */ - entry = ieee80211_reassemble_find(rx->sdata, frag, seq, + entry = ieee80211_reassemble_find(cache, frag, seq, rx->seqno_idx, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ec6973ee88ef..f2fb69da9b6e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -4,7 +4,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include @@ -392,6 +392,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u64_stats_init(&sta->rx_stats.syncp); + ieee80211_init_frag_cache(&sta->frags); + sta->sta_state = IEEE80211_STA_NONE; /* Mark TID as unreserved */ @@ -1102,6 +1104,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta) ieee80211_sta_debugfs_remove(sta); + ieee80211_destroy_frag_cache(&sta->frags); + cleanup_single_sta(sta); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 78b9d0c7cc58..5c56d29a619e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -3,7 +3,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright(c) 2020 Intel Corporation + * Copyright(c) 2020-2021 Intel Corporation */ #ifndef STA_INFO_H @@ -438,6 +438,33 @@ struct ieee80211_sta_rx_stats { u64 msdu[IEEE80211_NUM_TIDS + 1]; }; +/* + * IEEE 802.11-2016 (10.6 "Defragmentation") recommends support for "concurrent + * reception of at least one MSDU per access category per associated STA" + * on APs, or "at least one MSDU per access category" on other interface types. + * + * This limit can be increased by changing this define, at the cost of slower + * frame reassembly and increased memory use while fragments are pending. + */ +#define IEEE80211_FRAGMENT_MAX 4 + +struct ieee80211_fragment_entry { + struct sk_buff_head skb_list; + unsigned long first_frag_time; + u16 seq; + u16 extra_len; + u16 last_frag; + u8 rx_queue; + bool check_sequential_pn; /* needed for CCMP/GCMP */ + u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ + unsigned int key_color; +}; + +struct ieee80211_fragment_cache { + struct ieee80211_fragment_entry entries[IEEE80211_FRAGMENT_MAX]; + unsigned int next; +}; + /* * The bandwidth threshold below which the per-station CoDel parameters will be * scaled to be more lenient (to prevent starvation of slow stations). This @@ -531,6 +558,7 @@ struct ieee80211_sta_rx_stats { * @status_stats.last_ack_signal: last ACK signal * @status_stats.ack_signal_filled: last ACK signal validity * @status_stats.avg_ack_signal: average ACK signal + * @frags: fragment cache */ struct sta_info { /* General information, mostly static */ @@ -639,6 +667,8 @@ struct sta_info { struct cfg80211_chan_def tdls_chandef; + struct ieee80211_fragment_cache frags; + /* keep last! */ struct ieee80211_sta sta; }; -- cgit v1.2.3 From bf30ca922a0c0176007e074b0acc77ed345e9990 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 May 2021 20:02:48 +0200 Subject: mac80211: check defrag PN against current frame As pointed out by Mathy Vanhoef, we implement the RX PN check on fragmented frames incorrectly - we check against the last received PN prior to the new frame, rather than to the one in this frame itself. Prior patches addressed the security issue here, but in order to be able to reason better about the code, fix it to really compare against the current frame's PN, not the last stored one. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210511200110.bfbc340ff071.Id0b690e581da7d03d76df90bb0e3fd55930bc8a0@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 11 +++++++++-- net/mac80211/rx.c | 5 ++--- net/mac80211/wpa.c | 13 +++++++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4c714375bad0..214404a558fb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -223,8 +223,15 @@ struct ieee80211_rx_data { */ int security_idx; - u32 tkip_iv32; - u16 tkip_iv16; + union { + struct { + u32 iv32; + u16 iv16; + } tkip; + struct { + u8 pn[IEEE80211_CCMP_PN_LEN]; + } ccm_gcm; + }; }; struct ieee80211_csa_settings { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7212a1bebd0c..b619c47e1d12 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2308,7 +2308,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (entry->check_sequential_pn) { int i; u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; - int queue; if (!requires_sequential_pn(rx, fc)) return RX_DROP_UNUSABLE; @@ -2323,8 +2322,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (pn[i]) break; } - queue = rx->security_idx; - rpn = rx->key->u.ccmp.rx_pn[queue]; + + rpn = rx->ccm_gcm.pn; if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN)) return RX_DROP_UNUSABLE; memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 91bf32af55e9..bca47fad5a16 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -3,6 +3,7 @@ * Copyright 2002-2004, Instant802 Networks, Inc. * Copyright 2008, Jouni Malinen * Copyright (C) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2020-2021 Intel Corporation */ #include @@ -167,8 +168,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) update_iv: /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; - rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; + rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip.iv32; + rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip.iv16; return RX_CONTINUE; @@ -294,8 +295,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->sta.addr, hdr->addr1, hwaccel, rx->security_idx, - &rx->tkip_iv32, - &rx->tkip_iv16); + &rx->tkip.iv32, + &rx->tkip.iv16); if (res != TKIP_DECRYPT_OK) return RX_DROP_UNUSABLE; @@ -553,6 +554,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, } memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); + if (unlikely(ieee80211_is_frag(hdr))) + memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN); } /* Remove CCMP header and MIC */ @@ -781,6 +784,8 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) } memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN); + if (unlikely(ieee80211_is_frag(hdr))) + memcpy(rx->ccm_gcm.pn, pn, IEEE80211_CCMP_PN_LEN); } /* Remove GCMP header and MIC */ -- cgit v1.2.3 From 7e44a0b597f04e67eee8cdcbe7ee706c6f5de38b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 May 2021 20:02:49 +0200 Subject: mac80211: prevent attacks on TKIP/WEP as well Similar to the issues fixed in previous patches, TKIP and WEP should be protected even if for TKIP we have the Michael MIC protecting it, and WEP is broken anyway. However, this also somewhat protects potential other algorithms that drivers might implement. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20210511200110.430e8c202313.Ia37e4e5b6b3eaab1a5ae050e015f6c92859dbe27@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 12 ++++++++++++ net/mac80211/sta_info.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b619c47e1d12..4454ec47283f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2274,6 +2274,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) * next fragment has a sequential PN value. */ entry->check_sequential_pn = true; + entry->is_protected = true; entry->key_color = rx->key->color; memcpy(entry->last_pn, rx->key->u.ccmp.rx_pn[queue], @@ -2286,6 +2287,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) sizeof(rx->key->u.gcmp.rx_pn[queue])); BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); + } else if (rx->key && ieee80211_has_protected(fc)) { + entry->is_protected = true; + entry->key_color = rx->key->color; } return RX_QUEUED; } @@ -2327,6 +2331,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN)) return RX_DROP_UNUSABLE; memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN); + } else if (entry->is_protected && + (!rx->key || !ieee80211_has_protected(fc) || + rx->key->color != entry->key_color)) { + /* Drop this as a mixed key or fragment cache attack, even + * if for TKIP Michael MIC should protect us, and WEP is a + * lost cause anyway. + */ + return RX_DROP_UNUSABLE; } skb_pull(rx->skb, ieee80211_hdrlen(fc)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5c56d29a619e..0333072ebd98 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -455,7 +455,8 @@ struct ieee80211_fragment_entry { u16 extra_len; u16 last_frag; u8 rx_queue; - bool check_sequential_pn; /* needed for CCMP/GCMP */ + u8 check_sequential_pn:1, /* needed for CCMP/GCMP */ + is_protected:1; u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ unsigned int key_color; }; -- cgit v1.2.3 From a8c4d76a8dd4fb9666fc8919a703d85fb8f44ed8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 May 2021 20:02:50 +0200 Subject: mac80211: do not accept/forward invalid EAPOL frames EAPOL frames are used for authentication and key management between the AP and each individual STA associated in the BSS. Those frames are not supposed to be sent by one associated STA to another associated STA (either unicast for broadcast/multicast). Similarly, in 802.11 they're supposed to be sent to the authenticator (AP) address. Since it is possible for unexpected EAPOL frames to result in misbehavior in supplicant implementations, it is better for the AP to not allow such cases to be forwarded to other clients either directly, or indirectly if the AP interface is part of a bridge. Accept EAPOL (control port) frames only if they're transmitted to the own address, or, due to interoperability concerns, to the PAE group address. Disable forwarding of EAPOL (or well, the configured control port protocol) frames back to wireless medium in all cases. Previously, these frames were accepted from fully authenticated and authorized stations and also from unauthenticated stations for one of the cases. Additionally, to avoid forwarding by the bridge, rewrite the PAE group address case to the local MAC address. Cc: stable@vger.kernel.org Co-developed-by: Jouni Malinen Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.cb327ed0cabe.Ib7dcffa2a31f0913d660de65ba3c8aca75b1d10f@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4454ec47283f..22a925899a9e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2531,13 +2531,13 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; /* - * Allow EAPOL frames to us/the PAE group address regardless - * of whether the frame was encrypted or not. + * Allow EAPOL frames to us/the PAE group address regardless of + * whether the frame was encrypted or not, and always disallow + * all other destination addresses for them. */ - if (ehdr->h_proto == rx->sdata->control_port_protocol && - (ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) || - ether_addr_equal(ehdr->h_dest, pae_group_addr))) - return true; + if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol)) + return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) || + ether_addr_equal(ehdr->h_dest, pae_group_addr); if (ieee80211_802_1x_port_control(rx) || ieee80211_drop_unencrypted(rx, fc)) @@ -2562,8 +2562,28 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, cfg80211_rx_control_port(dev, skb, noencrypt); dev_kfree_skb(skb); } else { + struct ethhdr *ehdr = (void *)skb_mac_header(skb); + memset(skb->cb, 0, sizeof(skb->cb)); + /* + * 802.1X over 802.11 requires that the authenticator address + * be used for EAPOL frames. However, 802.1X allows the use of + * the PAE group address instead. If the interface is part of + * a bridge and we pass the frame with the PAE group address, + * then the bridge will forward it to the network (even if the + * client was not associated yet), which isn't supposed to + * happen. + * To avoid that, rewrite the destination address to our own + * address, so that the authenticator (e.g. hostapd) will see + * the frame, but bridge won't forward it anywhere else. Note + * that due to earlier filtering, the only other address can + * be the PAE group address. + */ + if (unlikely(skb->protocol == sdata->control_port_protocol && + !ether_addr_equal(ehdr->h_dest, sdata->vif.addr))) + ether_addr_copy(ehdr->h_dest, sdata->vif.addr); + /* deliver to local stack */ if (rx->list) list_add_tail(&skb->list, rx->list); @@ -2603,6 +2623,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if ((sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && + ehdr->h_proto != rx->sdata->control_port_protocol && (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { if (is_multicast_ether_addr(ehdr->h_dest) && ieee80211_vif_get_num_mcast_if(sdata) != 0) { -- cgit v1.2.3 From 3edc6b0d6c061a70d8ca3c3c72eb1f58ce29bfb1 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:51 +0200 Subject: mac80211: extend protection against mixed key and fragment cache attacks For some chips/drivers, e.g., QCA6174 with ath10k, the decryption is done by the hardware, and the Protected bit in the Frame Control field is cleared in the lower level driver before the frame is passed to mac80211. In such cases, the condition for ieee80211_has_protected() is not met in ieee80211_rx_h_defragment() of mac80211 and the new security validation steps are not executed. Extend mac80211 to cover the case where the Protected bit has been cleared, but the frame is indicated as having been decrypted by the hardware. This extends protection against mixed key and fragment cache attack for additional drivers/chips. This fixes CVE-2020-24586 and CVE-2020-24587 for such cases. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.037aa5ca0390.I7bb888e2965a0db02a67075fcb5deb50eb7408aa@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 22a925899a9e..1bb43edd47b6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2229,6 +2229,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); hdr = (struct ieee80211_hdr *)rx->skb->data; fc = hdr->frame_control; @@ -2287,7 +2288,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) sizeof(rx->key->u.gcmp.rx_pn[queue])); BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); - } else if (rx->key && ieee80211_has_protected(fc)) { + } else if (rx->key && + (ieee80211_has_protected(fc) || + (status->flag & RX_FLAG_DECRYPTED))) { entry->is_protected = true; entry->key_color = rx->key->color; } @@ -2332,13 +2335,19 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN); } else if (entry->is_protected && - (!rx->key || !ieee80211_has_protected(fc) || + (!rx->key || + (!ieee80211_has_protected(fc) && + !(status->flag & RX_FLAG_DECRYPTED)) || rx->key->color != entry->key_color)) { /* Drop this as a mixed key or fragment cache attack, even * if for TKIP Michael MIC should protect us, and WEP is a * lost cause anyway. */ return RX_DROP_UNUSABLE; + } else if (entry->is_protected && rx->key && + entry->key_color != rx->key->color && + (status->flag & RX_FLAG_DECRYPTED)) { + return RX_DROP_UNUSABLE; } skb_pull(rx->skb, ieee80211_hdrlen(fc)); -- cgit v1.2.3 From a1166b2653db2f3de7338b9fb8a0f6e924b904ee Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:52 +0200 Subject: ath10k: add CCMP PN replay protection for fragmented frames for PCIe PN replay check for not fragmented frames is finished in the firmware, but this was not done for fragmented frames when ath10k is used with QCA6174/QCA6377 PCIe. mac80211 has the function ieee80211_rx_h_defragment() for PN replay check for fragmented frames, but this does not get checked with QCA6174 due to the ieee80211_has_protected() condition not matching the cleared Protected bit case. Validate the PN of received fragmented frames within ath10k when CCMP is used and drop the fragment if the PN is not correct (incremented by exactly one from the previous fragment). This applies only for QCA6174/QCA6377 PCIe. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.9ba2664866a4.I756e47b67e210dba69966d989c4711ffc02dc6bc@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt.h | 1 + drivers/net/wireless/ath/ath10k/htt_rx.c | 99 ++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 956157946106..dbc8aef82a65 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -845,6 +845,7 @@ enum htt_security_types { #define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2 #define ATH10K_TXRX_NUM_EXT_TIDS 19 +#define ATH10K_TXRX_NON_QOS_TID 16 enum htt_security_flags { #define HTT_SECURITY_TYPE_MASK 0x7F diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 1a08156d5011..f1e5bce8b14f 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1746,16 +1746,87 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); } +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr; + u64 pn = 0; + u8 *ehdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control); + + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) { + pn = ehdr[0]; + pn |= (u64)ehdr[1] << 8; + pn |= (u64)ehdr[4] << 16; + pn |= (u64)ehdr[5] << 24; + pn |= (u64)ehdr[6] << 32; + pn |= (u64)ehdr[7] << 40; + } + return pn; +} + +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, + struct sk_buff *skb, + u16 peer_id, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ath10k_peer *peer; + union htt_rx_pn_t *last_pn, new_pn = {0}; + struct ieee80211_hdr *hdr; + bool more_frags; + u8 tid, frag_number; + u32 seq; + + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n"); + return false; + } + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = ieee80211_get_tid(hdr); + else + tid = ATH10K_TXRX_NON_QOS_TID; + + last_pn = &peer->frag_tids_last_pn[tid]; + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype); + more_frags = ieee80211_has_morefrags(hdr->frame_control); + frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + if (frag_number == 0) { + last_pn->pn48 = new_pn.pn48; + peer->frag_tids_seq[tid] = seq; + } else { + if (seq != peer->frag_tids_seq[tid]) + return false; + + if (new_pn.pn48 != last_pn->pn48 + 1) + return false; + + last_pn->pn48 = new_pn.pn48; + } + + return true; +} + static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *status, bool fill_crypt_header, u8 *rx_hdr, - enum ath10k_pkt_rx_err *err) + enum ath10k_pkt_rx_err *err, + u16 peer_id, + bool frag) { struct sk_buff *first; struct sk_buff *last; - struct sk_buff *msdu; + struct sk_buff *msdu, *temp; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum htt_rx_mpdu_encrypt_type enctype; @@ -1768,6 +1839,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, bool is_decrypted; bool is_mgmt; u32 attention; + bool frag_pn_check = true; if (skb_queue_empty(amsdu)) return; @@ -1866,6 +1938,24 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, } skb_queue_walk(amsdu, msdu) { + if (frag && !fill_crypt_header && is_decrypted && + enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) + frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar, + msdu, + peer_id, + 0, + enctype); + + if (!frag_pn_check) { + /* Discard the fragment with invalid PN */ + temp = msdu->prev; + __skb_unlink(msdu, amsdu); + dev_kfree_skb_any(msdu); + msdu = temp; + frag_pn_check = true; + continue; + } + ath10k_htt_rx_h_csum_offload(msdu); ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, is_decrypted); @@ -2071,7 +2161,8 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter); - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0, + false); msdus_to_queue = skb_queue_len(&amsdu); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); @@ -3027,7 +3118,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL, - NULL); + NULL, peer_id, frag); ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: -- cgit v1.2.3 From 65c415a144ad8132b6a6d97d4a1919ffc728e2d1 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:53 +0200 Subject: ath10k: drop fragments with multicast DA for PCIe Fragmentation is not used with multicast frames. Discard unexpected fragments with multicast DA. This fixes CVE-2020-26145. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.5a0bd289bda8.Idd6ebea20038fb1cfee6de924aa595e5647c9eae@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index f1e5bce8b14f..cb04848ed5cb 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1768,6 +1768,16 @@ static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, return pn; } +static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar, + struct sk_buff *skb, + u16 offset) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + return !is_multicast_ether_addr(hdr->addr1); +} + static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, struct sk_buff *skb, u16 peer_id, @@ -1839,7 +1849,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, bool is_decrypted; bool is_mgmt; u32 attention; - bool frag_pn_check = true; + bool frag_pn_check = true, multicast_check = true; if (skb_queue_empty(amsdu)) return; @@ -1946,13 +1956,20 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, 0, enctype); - if (!frag_pn_check) { - /* Discard the fragment with invalid PN */ + if (frag) + multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar, + msdu, + 0); + + if (!frag_pn_check || !multicast_check) { + /* Discard the fragment with invalid PN or multicast DA + */ temp = msdu->prev; __skb_unlink(msdu, amsdu); dev_kfree_skb_any(msdu); msdu = temp; frag_pn_check = true; + multicast_check = true; continue; } -- cgit v1.2.3 From 40e7462dad6f3d06efdb17d26539e61ab6e34db1 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:54 +0200 Subject: ath10k: drop fragments with multicast DA for SDIO Fragmentation is not used with multicast frames. Discard unexpected fragments with multicast DA. This fixes CVE-2020-26145. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00049 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.9ca6ca7945a9.I1e18b514590af17c155bda86699bc3a971a8dcf4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cb04848ed5cb..b1d93ff5215a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2617,6 +2617,13 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len); rx_desc_info = __le32_to_cpu(rx_desc->info); + hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len); + + if (is_multicast_ether_addr(hdr->addr1)) { + /* Discard the fragment with multicast DA */ + goto err; + } + if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) { spin_unlock_bh(&ar->data_lock); return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb, @@ -2624,8 +2631,6 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, HTT_RX_NON_TKIP_MIC); } - hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len); - if (ieee80211_has_retry(hdr->frame_control)) goto err; -- cgit v1.2.3 From 079a108feba474b4b32bd3471db03e11f2f83b81 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:55 +0200 Subject: ath10k: drop MPDU which has discard flag set by firmware for SDIO When the discard flag is set by the firmware for an MPDU, it should be dropped. This allows a mitigation for CVE-2020-24588 to be implemented in the firmware. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00049 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.11968c725b5c.Idd166365ebea2771c0c0a38c78b5060750f90e17@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 5 +++++ drivers/net/wireless/ath/ath10k/rx_desc.h | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b1d93ff5215a..12451ab66a19 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2312,6 +2312,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, fw_desc = &rx->fw_desc; rx_desc_len = fw_desc->len; + if (fw_desc->u.bits.discard) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt discard mpdu\n"); + goto err; + } + /* I have not yet seen any case where num_mpdu_ranges > 1. * qcacld does not seem handle that case either, so we introduce the * same limitiation here as well. diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index f2b6bf8f0d60..705b6295e466 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -1282,7 +1282,19 @@ struct fw_rx_desc_base { #define FW_RX_DESC_UDP (1 << 6) struct fw_rx_desc_hl { - u8 info0; + union { + struct { + u8 discard:1, + forward:1, + any_err:1, + dup_err:1, + reserved:1, + inspect:1, + extension:2; + } bits; + u8 info0; + } u; + u8 version; u8 len; u8 flags; -- cgit v1.2.3 From 0dc267b13f3a7e8424a898815dd357211b737330 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 11 May 2021 20:02:56 +0200 Subject: ath10k: Fix TKIP Michael MIC verification for PCIe TKIP Michael MIC was not verified properly for PCIe cases since the validation steps in ieee80211_rx_h_michael_mic_verify() in mac80211 did not get fully executed due to unexpected flag values in ieee80211_rx_status. Fix this by setting the flags property to meet mac80211 expectations for performing Michael MIC validation there. This fixes CVE-2020-26141. It does the same as ath10k_htt_rx_proc_rx_ind_hl() for SDIO which passed MIC verification case. This applies only to QCA6174/QCA9377 PCIe. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Cc: stable@vger.kernel.org Signed-off-by: Wen Gong Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.c3f1d42c6746.I795593fcaae941c471425b8c7d5f7bb185d29142@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 12451ab66a19..87196f9bbdea 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1974,6 +1974,11 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, } ath10k_htt_rx_h_csum_offload(msdu); + + if (frag && !fill_crypt_header && + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + status->flag &= ~RX_FLAG_MMIC_STRIPPED; + ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, is_decrypted); @@ -1991,6 +1996,11 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, hdr = (void *)msdu->data; hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + + if (frag && !fill_crypt_header && + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + status->flag &= ~RX_FLAG_IV_STRIPPED & + ~RX_FLAG_MMIC_STRIPPED; } } -- cgit v1.2.3 From 62a8ff67eba52dae9b107e1fb8827054ed00a265 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Tue, 11 May 2021 20:02:57 +0200 Subject: ath10k: Validate first subframe of A-MSDU before processing the list In certain scenarios a normal MSDU can be received as an A-MSDU when the A-MSDU present bit of a QoS header gets flipped during reception. Since this bit is unauthenticated, the hardware crypto engine can pass the frame to the driver without any error indication. This could result in processing unintended subframes collected in the A-MSDU list. Hence, validate A-MSDU list by checking if the first frame has a valid subframe header. Comparing the non-aggregated MSDU and an A-MSDU, the fields of the first subframe DA matches the LLC/SNAP header fields of a normal MSDU. In order to avoid processing such frames, add a validation to filter such A-MSDU frames where the first subframe header DA matches with the LLC/SNAP header pattern. Tested-on: QCA9984 hw1.0 PCI 10.4-3.10-00047 Cc: stable@vger.kernel.org Signed-off-by: Sriram R Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.e6f5eb7b9847.I38a77ae26096862527a5eab73caebd7346af8b66@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 61 +++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 87196f9bbdea..7ffb5d5b2a70 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2108,14 +2108,62 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, ath10k_unchain_msdu(amsdu, unchain_cnt); } +static bool ath10k_htt_rx_validate_amsdu(struct ath10k *ar, + struct sk_buff_head *amsdu) +{ + u8 *subframe_hdr; + struct sk_buff *first; + bool is_first, is_last; + struct htt_rx_desc *rxd; + struct ieee80211_hdr *hdr; + size_t hdr_len, crypto_len; + enum htt_rx_mpdu_encrypt_type enctype; + int bytes_aligned = ar->hw_params.decap_align_bytes; + + first = skb_peek(amsdu); + + rxd = (void *)first->data - sizeof(*rxd); + hdr = (void *)rxd->rx_hdr_status; + + is_first = !!(rxd->msdu_end.common.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); + is_last = !!(rxd->msdu_end.common.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); + + /* Return in case of non-aggregated msdu */ + if (is_first && is_last) + return true; + + /* First msdu flag is not set for the first msdu of the list */ + if (!is_first) + return false; + + enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), + RX_MPDU_START_INFO0_ENCRYPT_TYPE); + + hdr_len = ieee80211_hdrlen(hdr->frame_control); + crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); + + subframe_hdr = (u8 *)hdr + round_up(hdr_len, bytes_aligned) + + crypto_len; + + /* Validate if the amsdu has a proper first subframe. + * There are chances a single msdu can be received as amsdu when + * the unauthenticated amsdu flag of a QoS header + * gets flipped in non-SPP AMSDU's, in such cases the first + * subframe has llc/snap header in place of a valid da. + * return false if the da matches rfc1042 pattern + */ + if (ether_addr_equal(subframe_hdr, rfc1042_header)) + return false; + + return true; +} + static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *rx_status) { - /* FIXME: It might be a good idea to do some fuzzy-testing to drop - * invalid/dangerous frames. - */ - if (!rx_status->freq) { ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n"); return false; @@ -2126,6 +2174,11 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, return false; } + if (!ath10k_htt_rx_validate_amsdu(ar, amsdu)) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid amsdu received\n"); + return false; + } + return true; } -- cgit v1.2.3 From c3944a5621026c176001493d48ee66ff94e1a39a Mon Sep 17 00:00:00 2001 From: Sriram R Date: Tue, 11 May 2021 20:02:58 +0200 Subject: ath11k: Clear the fragment cache during key install Currently the fragment cache setup during peer assoc is cleared only during peer delete. In case a key reinstallation happens with the same peer, the same fragment cache with old fragments added before key installation could be clubbed with fragments received after. This might be exploited to mix fragments of different data resulting in a proper unintended reassembled packet to be passed up the stack. Hence flush the fragment cache on every key installation to prevent potential attacks (CVE-2020-24587). Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 Cc: stable@vger.kernel.org Signed-off-by: Sriram R Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.218dc777836f.I9af6fc76215a35936c4152552018afb5079c5d8c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath11k/dp_rx.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath11k/dp_rx.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 1d9aa1bb6b6e..3382f8bfcb48 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -852,6 +852,24 @@ static void ath11k_dp_rx_frags_cleanup(struct dp_rx_tid *rx_tid, bool rel_link_d __skb_queue_purge(&rx_tid->rx_frags); } +void ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer) +{ + struct dp_rx_tid *rx_tid; + int i; + + lockdep_assert_held(&ar->ab->base_lock); + + for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { + rx_tid = &peer->rx_tid[i]; + + spin_unlock_bh(&ar->ab->base_lock); + del_timer_sync(&rx_tid->frag_timer); + spin_lock_bh(&ar->ab->base_lock); + + ath11k_dp_rx_frags_cleanup(rx_tid, true); + } +} + void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer) { struct dp_rx_tid *rx_tid; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index bf399312b5ff..623da3bf9dc8 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -49,6 +49,7 @@ int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key); +void ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer); void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer); void ath11k_peer_rx_tid_delete(struct ath11k *ar, struct ath11k_peer *peer, u8 tid); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4df425dd31a2..9d0ff150ec30 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2779,6 +2779,12 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, */ spin_lock_bh(&ab->base_lock); peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr); + + /* flush the fragments cache during key (re)install to + * ensure all frags in the new frag list belong to the same key. + */ + if (peer && cmd == SET_KEY) + ath11k_peer_frags_flush(ar, peer); spin_unlock_bh(&ab->base_lock); if (!peer) { -- cgit v1.2.3 From 210f563b097997ce917e82feab356b298bfd12b0 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Tue, 11 May 2021 20:02:59 +0200 Subject: ath11k: Drop multicast fragments Fragmentation is used only with unicast frames. Drop multicast fragments to avoid any undesired behavior. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 Cc: stable@vger.kernel.org Signed-off-by: Sriram R Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20210511200110.1d53bfd20a8b.Ibb63283051bb5e2c45951932c6e1f351d5a73dc3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath11k/dp_rx.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 3382f8bfcb48..603d2f93ac18 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -260,6 +260,16 @@ static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); } +static bool ath11k_dp_rx_h_attn_is_mcbc(struct ath11k_base *ab, + struct hal_rx_desc *desc) +{ + struct rx_attention *attn = ath11k_dp_rx_get_attention(ab, desc); + + return ath11k_dp_rx_h_msdu_end_first_msdu(ab, desc) && + (!!FIELD_GET(RX_ATTENTION_INFO1_MCAST_BCAST, + __le32_to_cpu(attn->info1))); +} + static void ath11k_dp_service_mon_ring(struct timer_list *t) { struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); @@ -3468,6 +3478,7 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, u8 tid; int ret = 0; bool more_frags; + bool is_mcbc; rx_desc = (struct hal_rx_desc *)msdu->data; peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); @@ -3475,6 +3486,11 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, seqno = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, msdu); more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(ar->ab, msdu); + is_mcbc = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); + + /* Multicast/Broadcast fragments are not expected */ + if (is_mcbc) + return -EINVAL; if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(ar->ab, rx_desc) || !ath11k_dp_rx_h_mpdu_start_fc_valid(ar->ab, rx_desc) || -- cgit v1.2.3 From b24abcff918a5cbf44b0c982bd3477a93e8e4911 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 11 May 2021 22:35:16 +0200 Subject: bpf, kconfig: Add consolidated menu entry for bpf with core options Right now, all core BPF related options are scattered in different Kconfig locations mainly due to historic reasons. Moving forward, lets add a proper subsystem entry under ... General setup ---> BPF subsystem ---> ... in order to have all knobs in a single location and thus ease BPF related configuration. Networking related bits such as sockmap are out of scope for the general setup and therefore better suited to remain in net/Kconfig. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/f23f58765a4d59244ebd8037da7b6a6b2fb58446.1620765074.git.daniel@iogearbox.net --- init/Kconfig | 41 +--------------------------- kernel/bpf/Kconfig | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/Kconfig | 27 ------------------- 3 files changed, 79 insertions(+), 67 deletions(-) create mode 100644 kernel/bpf/Kconfig diff --git a/init/Kconfig b/init/Kconfig index ca559ccdaa32..2282a6842dc6 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -439,6 +439,7 @@ config AUDITSYSCALL source "kernel/irq/Kconfig" source "kernel/time/Kconfig" +source "kernel/bpf/Kconfig" source "kernel/Kconfig.preempt" menu "CPU/Task time and stats accounting" @@ -1705,46 +1706,6 @@ config KALLSYMS_BASE_RELATIVE # syscall, maps, verifier -config BPF_LSM - bool "LSM Instrumentation with BPF" - depends on BPF_EVENTS - depends on BPF_SYSCALL - depends on SECURITY - depends on BPF_JIT - help - Enables instrumentation of the security hooks with eBPF programs for - implementing dynamic MAC and Audit Policies. - - If you are unsure how to answer this question, answer N. - -config BPF_SYSCALL - bool "Enable bpf() system call" - select BPF - select IRQ_WORK - select TASKS_TRACE_RCU - select BINARY_PRINTF - select NET_SOCK_MSG if INET - default n - help - Enable the bpf() system call that allows to manipulate eBPF - programs and maps via file descriptors. - -config ARCH_WANT_DEFAULT_BPF_JIT - bool - -config BPF_JIT_ALWAYS_ON - bool "Permanently enable BPF JIT and remove BPF interpreter" - depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT - help - Enables BPF JIT and removes BPF interpreter to avoid - speculative execution of BPF instructions by the interpreter - -config BPF_JIT_DEFAULT_ON - def_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON - depends on HAVE_EBPF_JIT && BPF_JIT - -source "kernel/bpf/preload/Kconfig" - config USERFAULTFD bool "Enable userfaultfd() system call" depends on MMU diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig new file mode 100644 index 000000000000..b4edaefc6255 --- /dev/null +++ b/kernel/bpf/Kconfig @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# BPF interpreter that, for example, classic socket filters depend on. +config BPF + bool + +# Used by archs to tell that they support BPF JIT compiler plus which +# flavour. Only one of the two can be selected for a specific arch since +# eBPF JIT supersedes the cBPF JIT. + +# Classic BPF JIT (cBPF) +config HAVE_CBPF_JIT + bool + +# Extended BPF JIT (eBPF) +config HAVE_EBPF_JIT + bool + +# Used by archs to tell that they want the BPF JIT compiler enabled by +# default for kernels that were compiled with BPF JIT support. +config ARCH_WANT_DEFAULT_BPF_JIT + bool + +menu "BPF subsystem" + +config BPF_SYSCALL + bool "Enable bpf() system call" + select BPF + select IRQ_WORK + select TASKS_TRACE_RCU + select BINARY_PRINTF + select NET_SOCK_MSG if INET + default n + help + Enable the bpf() system call that allows to manipulate BPF programs + and maps via file descriptors. + +config BPF_JIT + bool "Enable BPF Just In Time compiler" + depends on HAVE_CBPF_JIT || HAVE_EBPF_JIT + depends on MODULES + help + BPF programs are normally handled by a BPF interpreter. This option + allows the kernel to generate native code when a program is loaded + into the kernel. This will significantly speed-up processing of BPF + programs. + + Note, an admin should enable this feature changing: + /proc/sys/net/core/bpf_jit_enable + /proc/sys/net/core/bpf_jit_harden (optional) + /proc/sys/net/core/bpf_jit_kallsyms (optional) + +config BPF_JIT_ALWAYS_ON + bool "Permanently enable BPF JIT and remove BPF interpreter" + depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT + help + Enables BPF JIT and removes BPF interpreter to avoid speculative + execution of BPF instructions by the interpreter. + +config BPF_JIT_DEFAULT_ON + def_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON + depends on HAVE_EBPF_JIT && BPF_JIT + +source "kernel/bpf/preload/Kconfig" + +config BPF_LSM + bool "Enable BPF LSM Instrumentation" + depends on BPF_EVENTS + depends on BPF_SYSCALL + depends on SECURITY + depends on BPF_JIT + help + Enables instrumentation of the security hooks with BPF programs for + implementing dynamic MAC and Audit Policies. + + If you are unsure how to answer this question, answer N. + +endmenu # "BPF subsystem" diff --git a/net/Kconfig b/net/Kconfig index f5ee7c65e6b4..c7392c449b25 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -302,21 +302,6 @@ config BQL select DQL default y -config BPF_JIT - bool "enable BPF Just In Time compiler" - depends on HAVE_CBPF_JIT || HAVE_EBPF_JIT - depends on MODULES - help - Berkeley Packet Filter filtering capabilities are normally handled - by an interpreter. This option allows kernel to generate a native - code when filter is loaded in memory. This should speedup - packet sniffing (libpcap/tcpdump). - - Note, admin should enable this feature changing: - /proc/sys/net/core/bpf_jit_enable - /proc/sys/net/core/bpf_jit_harden (optional) - /proc/sys/net/core/bpf_jit_kallsyms (optional) - config BPF_STREAM_PARSER bool "enable BPF STREAM_PARSER" depends on INET @@ -470,15 +455,3 @@ config ETHTOOL_NETLINK e.g. notification messages. endif # if NET - -# Used by archs to tell that they support BPF JIT compiler plus which flavour. -# Only one of the two can be selected for a specific arch since eBPF JIT supersedes -# the cBPF JIT. - -# Classic BPF JIT (cBPF) -config HAVE_CBPF_JIT - bool - -# Extended BPF JIT (eBPF) -config HAVE_EBPF_JIT - bool -- cgit v1.2.3 From 08389d888287c3823f80b0216766b71e17f0aba5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 11 May 2021 22:35:17 +0200 Subject: bpf: Add kconfig knob for disabling unpriv bpf by default Add a kconfig knob which allows for unprivileged bpf to be disabled by default. If set, the knob sets /proc/sys/kernel/unprivileged_bpf_disabled to value of 2. This still allows a transition of 2 -> {0,1} through an admin. Similarly, this also still keeps 1 -> {1} behavior intact, so that once set to permanently disabled, it cannot be undone aside from a reboot. We've also added extra2 with max of 2 for the procfs handler, so that an admin still has a chance to toggle between 0 <-> 2. Either way, as an additional alternative, applications can make use of CAP_BPF that we added a while ago. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/74ec548079189e4e4dffaeb42b8987bb3c852eee.1620765074.git.daniel@iogearbox.net --- Documentation/admin-guide/sysctl/kernel.rst | 17 ++++++++++++++--- kernel/bpf/Kconfig | 10 ++++++++++ kernel/bpf/syscall.c | 3 ++- kernel/sysctl.c | 29 ++++++++++++++++++++++++----- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..24ab20d7a50a 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -1457,11 +1457,22 @@ unprivileged_bpf_disabled ========================= Writing 1 to this entry will disable unprivileged calls to ``bpf()``; -once disabled, calling ``bpf()`` without ``CAP_SYS_ADMIN`` will return -``-EPERM``. +once disabled, calling ``bpf()`` without ``CAP_SYS_ADMIN`` or ``CAP_BPF`` +will return ``-EPERM``. Once set to 1, this can't be cleared from the +running kernel anymore. -Once set, this can't be cleared. +Writing 2 to this entry will also disable unprivileged calls to ``bpf()``, +however, an admin can still change this setting later on, if needed, by +writing 0 or 1 to this entry. +If ``BPF_UNPRIV_DEFAULT_OFF`` is enabled in the kernel config, then this +entry will default to 2 instead of 0. + += ============================================================= +0 Unprivileged calls to ``bpf()`` are enabled +1 Unprivileged calls to ``bpf()`` are disabled without recovery +2 Unprivileged calls to ``bpf()`` are disabled += ============================================================= watchdog ======== diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index b4edaefc6255..26b591e23f16 100644 --- a/kernel/bpf/Kconfig +++ b/kernel/bpf/Kconfig @@ -61,6 +61,16 @@ config BPF_JIT_DEFAULT_ON def_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON depends on HAVE_EBPF_JIT && BPF_JIT +config BPF_UNPRIV_DEFAULT_OFF + bool "Disable unprivileged BPF by default" + depends on BPF_SYSCALL + help + Disables unprivileged BPF by default by setting the corresponding + /proc/sys/kernel/unprivileged_bpf_disabled knob to 2. An admin can + still reenable it by setting it to 0 later on, or permanently + disable it by setting it to 1 (from which no other transition to + 0 is possible anymore). + source "kernel/bpf/preload/Kconfig" config BPF_LSM diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 941ca06d9dfa..ea04b0deb5ce 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -50,7 +50,8 @@ static DEFINE_SPINLOCK(map_idr_lock); static DEFINE_IDR(link_idr); static DEFINE_SPINLOCK(link_idr_lock); -int sysctl_unprivileged_bpf_disabled __read_mostly; +int sysctl_unprivileged_bpf_disabled __read_mostly = + IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0; static const struct bpf_map_ops * const bpf_map_types[] = { #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index f91d327273c1..6df7c81f7cdd 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -225,7 +225,27 @@ static int bpf_stats_handler(struct ctl_table *table, int write, mutex_unlock(&bpf_stats_enabled_mutex); return ret; } -#endif + +static int bpf_unpriv_handler(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int ret, unpriv_enable = *(int *)table->data; + bool locked_state = unpriv_enable == 1; + struct ctl_table tmp = *table; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + tmp.data = &unpriv_enable; + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + if (write && !ret) { + if (locked_state && unpriv_enable != 1) + return -EPERM; + *(int *)table->data = unpriv_enable; + } + return ret; +} +#endif /* CONFIG_BPF_SYSCALL && CONFIG_SYSCTL */ /* * /proc/sys support @@ -2600,10 +2620,9 @@ static struct ctl_table kern_table[] = { .data = &sysctl_unprivileged_bpf_disabled, .maxlen = sizeof(sysctl_unprivileged_bpf_disabled), .mode = 0644, - /* only handle a transition from default "0" to "1" */ - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ONE, - .extra2 = SYSCTL_ONE, + .proc_handler = bpf_unpriv_handler, + .extra1 = SYSCTL_ZERO, + .extra2 = &two, }, { .procname = "bpf_stats_enabled", -- cgit v1.2.3 From 35e3815fa8102fab4dee75f3547472c66581125d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 29 Apr 2021 13:47:12 +0200 Subject: bpf: Add deny list of btf ids check for tracing programs The recursion check in __bpf_prog_enter and __bpf_prog_exit leaves some (not inlined) functions unprotected: In __bpf_prog_enter: - migrate_disable is called before prog->active is checked In __bpf_prog_exit: - migrate_enable,rcu_read_unlock_strict are called after prog->active is decreased When attaching trampoline to them we get panic like: traps: PANIC: double fault, error_code: 0x0 double fault: 0000 [#1] SMP PTI RIP: 0010:__bpf_prog_enter+0x4/0x50 ... Call Trace: bpf_trampoline_6442466513_0+0x18/0x1000 migrate_disable+0x5/0x50 __bpf_prog_enter+0x9/0x50 bpf_trampoline_6442466513_0+0x18/0x1000 migrate_disable+0x5/0x50 __bpf_prog_enter+0x9/0x50 bpf_trampoline_6442466513_0+0x18/0x1000 migrate_disable+0x5/0x50 __bpf_prog_enter+0x9/0x50 bpf_trampoline_6442466513_0+0x18/0x1000 migrate_disable+0x5/0x50 ... Fixing this by adding deny list of btf ids for tracing programs and checking btf id during program verification. Adding above functions to this list. Suggested-by: Alexei Starovoitov Signed-off-by: Jiri Olsa Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20210429114712.43783-1-jolsa@kernel.org --- kernel/bpf/verifier.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9352a1b7de2d..c58598ef4b5b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -13196,6 +13196,17 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, return 0; } +BTF_SET_START(btf_id_deny) +BTF_ID_UNUSED +#ifdef CONFIG_SMP +BTF_ID(func, migrate_disable) +BTF_ID(func, migrate_enable) +#endif +#if !defined CONFIG_PREEMPT_RCU && !defined CONFIG_TINY_RCU +BTF_ID(func, rcu_read_unlock_strict) +#endif +BTF_SET_END(btf_id_deny) + static int check_attach_btf_id(struct bpf_verifier_env *env) { struct bpf_prog *prog = env->prog; @@ -13255,6 +13266,9 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) ret = bpf_lsm_verify_prog(&env->log, prog); if (ret < 0) return ret; + } else if (prog->type == BPF_PROG_TYPE_TRACING && + btf_id_set_contains(&btf_id_deny, btf_id)) { + return -EINVAL; } key = bpf_trampoline_compute_key(tgt_prog, prog->aux->attach_btf, btf_id); -- cgit v1.2.3 From e2d5b2bb769fa5f500760caba76436ba3a10a895 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Tue, 11 May 2021 10:10:54 +0200 Subject: bpf: Fix nested bpf_bprintf_prepare with more per-cpu buffers The bpf_seq_printf, bpf_trace_printk and bpf_snprintf helpers share one per-cpu buffer that they use to store temporary data (arguments to bprintf). They "get" that buffer with try_get_fmt_tmp_buf and "put" it by the end of their scope with bpf_bprintf_cleanup. If one of these helpers gets called within the scope of one of these helpers, for example: a first bpf program gets called, uses bpf_trace_printk which calls raw_spin_lock_irqsave which is traced by another bpf program that calls bpf_snprintf, then the second "get" fails. Essentially, these helpers are not re-entrant. They would return -EBUSY and print a warning message once. This patch triples the number of bprintf buffers to allow three levels of nesting. This is very similar to what was done for tracepoints in "9594dc3c7e7 bpf: fix nested bpf tracepoints with per-cpu data" Fixes: d9c9e4db186a ("bpf: Factorize bpf_trace_printk and bpf_seq_printf") Reported-by: syzbot+63122d0bc347f18c1884@syzkaller.appspotmail.com Signed-off-by: Florent Revest Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20210511081054.2125874-1-revest@chromium.org --- kernel/bpf/helpers.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 544773970dbc..ef658a9ea5c9 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -696,34 +696,35 @@ static int bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype, */ #define MAX_PRINTF_BUF_LEN 512 -struct bpf_printf_buf { - char tmp_buf[MAX_PRINTF_BUF_LEN]; +/* Support executing three nested bprintf helper calls on a given CPU */ +struct bpf_bprintf_buffers { + char tmp_bufs[3][MAX_PRINTF_BUF_LEN]; }; -static DEFINE_PER_CPU(struct bpf_printf_buf, bpf_printf_buf); -static DEFINE_PER_CPU(int, bpf_printf_buf_used); +static DEFINE_PER_CPU(struct bpf_bprintf_buffers, bpf_bprintf_bufs); +static DEFINE_PER_CPU(int, bpf_bprintf_nest_level); static int try_get_fmt_tmp_buf(char **tmp_buf) { - struct bpf_printf_buf *bufs; - int used; + struct bpf_bprintf_buffers *bufs; + int nest_level; preempt_disable(); - used = this_cpu_inc_return(bpf_printf_buf_used); - if (WARN_ON_ONCE(used > 1)) { - this_cpu_dec(bpf_printf_buf_used); + nest_level = this_cpu_inc_return(bpf_bprintf_nest_level); + if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(bufs->tmp_bufs))) { + this_cpu_dec(bpf_bprintf_nest_level); preempt_enable(); return -EBUSY; } - bufs = this_cpu_ptr(&bpf_printf_buf); - *tmp_buf = bufs->tmp_buf; + bufs = this_cpu_ptr(&bpf_bprintf_bufs); + *tmp_buf = bufs->tmp_bufs[nest_level - 1]; return 0; } void bpf_bprintf_cleanup(void) { - if (this_cpu_read(bpf_printf_buf_used)) { - this_cpu_dec(bpf_printf_buf_used); + if (this_cpu_read(bpf_bprintf_nest_level)) { + this_cpu_dec(bpf_bprintf_nest_level); preempt_enable(); } } -- cgit v1.2.3 From 67e7ec0bd4535fc6e6d3f5d174f80e10a8a80c6e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 8 May 2021 12:22:12 -0300 Subject: libbpf: Provide GELF_ST_VISIBILITY() define for older libelf Where that macro isn't available. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/YJaspEh0qZr4LYOc@kernel.org --- tools/lib/bpf/libbpf_internal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index ee426226928f..acbcf6c7bdf8 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -41,6 +41,11 @@ #define ELF_C_READ_MMAP ELF_C_READ #endif +/* Older libelf all end up in this expression, for both 32 and 64 bit */ +#ifndef GELF_ST_VISIBILITY +#define GELF_ST_VISIBILITY(o) ((o) & 0x03) +#endif + #define BTF_INFO_ENC(kind, kind_flag, vlen) \ ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) #define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type) -- cgit v1.2.3 From 096eccdef0b32f47e9354231ddc3aaaf9527d51c Mon Sep 17 00:00:00 2001 From: Jussi Maki Date: Wed, 5 May 2021 08:59:25 +0000 Subject: selftests/bpf: Rewrite test_tc_redirect.sh as prog_tests/tc_redirect.c As discussed in [0], this ports test_tc_redirect.sh to the test_progs framework and removes the old test. This makes it more in line with rest of the tests and makes it possible to run this test case with vmtest.sh and under the bpf CI. The upcoming skb_change_head() helper fix in [0] is depending on it and extending the test case to redirect a packet from L3 device to veth. [0] https://lore.kernel.org/bpf/20210427135550.807355-1-joamaki@gmail.com Signed-off-by: Jussi Maki Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20210505085925.783985-1-joamaki@gmail.com --- tools/testing/selftests/bpf/network_helpers.c | 2 +- tools/testing/selftests/bpf/network_helpers.h | 1 + .../testing/selftests/bpf/prog_tests/tc_redirect.c | 589 +++++++++++++++++++++ tools/testing/selftests/bpf/progs/test_tc_neigh.c | 33 +- .../selftests/bpf/progs/test_tc_neigh_fib.c | 9 +- tools/testing/selftests/bpf/progs/test_tc_peer.c | 33 +- tools/testing/selftests/bpf/test_tc_redirect.sh | 216 -------- 7 files changed, 617 insertions(+), 266 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/tc_redirect.c delete mode 100755 tools/testing/selftests/bpf/test_tc_redirect.sh diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c index 12ee40284da0..2060bc122c53 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -40,7 +40,7 @@ struct ipv6_packet pkt_v6 = { .tcp.doff = 5, }; -static int settimeo(int fd, int timeout_ms) +int settimeo(int fd, int timeout_ms) { struct timeval timeout = { .tv_sec = 3 }; diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 7205f8afdba1..5e0d51c07b63 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -33,6 +33,7 @@ struct ipv6_packet { } __packed; extern struct ipv6_packet pkt_v6; +int settimeo(int fd, int timeout_ms); int start_server(int family, int type, const char *addr, __u16 port, int timeout_ms); int connect_to_fd(int server_fd, int timeout_ms); diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c new file mode 100644 index 000000000000..95ef9fcd31d8 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +/* + * This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link + * between src and dst. The netns fwd has veth links to each src and dst. The + * client is in src and server in dst. The test installs a TC BPF program to each + * host facing veth in fwd which calls into i) bpf_redirect_neigh() to perform the + * neigh addr population and redirect or ii) bpf_redirect_peer() for namespace + * switch from ingress side; it also installs a checker prog on the egress side + * to drop unexpected traffic. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_progs.h" +#include "network_helpers.h" +#include "test_tc_neigh_fib.skel.h" +#include "test_tc_neigh.skel.h" +#include "test_tc_peer.skel.h" + +#define NS_SRC "ns_src" +#define NS_FWD "ns_fwd" +#define NS_DST "ns_dst" + +#define IP4_SRC "172.16.1.100" +#define IP4_DST "172.16.2.100" +#define IP4_PORT 9004 + +#define IP6_SRC "::1:dead:beef:cafe" +#define IP6_DST "::2:dead:beef:cafe" +#define IP6_PORT 9006 + +#define IP4_SLL "169.254.0.1" +#define IP4_DLL "169.254.0.2" +#define IP4_NET "169.254.0.0" + +#define IFADDR_STR_LEN 18 +#define PING_ARGS "-c 3 -w 10 -q" + +#define SRC_PROG_PIN_FILE "/sys/fs/bpf/test_tc_src" +#define DST_PROG_PIN_FILE "/sys/fs/bpf/test_tc_dst" +#define CHK_PROG_PIN_FILE "/sys/fs/bpf/test_tc_chk" + +#define TIMEOUT_MILLIS 10000 + +#define MAX_PROC_MODS 128 +#define MAX_PROC_VALUE_LEN 16 + +#define log_err(MSG, ...) \ + fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \ + __FILE__, __LINE__, strerror(errno), ##__VA_ARGS__) + +struct proc_mod { + char path[PATH_MAX]; + char oldval[MAX_PROC_VALUE_LEN]; + int oldlen; +}; + +static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST, NULL}; +static int root_netns_fd = -1; +static int num_proc_mods; +static struct proc_mod proc_mods[MAX_PROC_MODS]; + +/** + * modify_proc() - Modify entry in /proc + * + * Modifies an entry in /proc and saves the original value for later + * restoration with restore_proc(). + */ +static int modify_proc(const char *path, const char *newval) +{ + struct proc_mod *mod; + FILE *f; + + if (num_proc_mods + 1 > MAX_PROC_MODS) + return -1; + + f = fopen(path, "r+"); + if (!f) + return -1; + + mod = &proc_mods[num_proc_mods]; + num_proc_mods++; + + strncpy(mod->path, path, PATH_MAX); + + if (!fread(mod->oldval, 1, MAX_PROC_VALUE_LEN, f)) { + log_err("reading from %s failed", path); + goto fail; + } + rewind(f); + if (fwrite(newval, strlen(newval), 1, f) != 1) { + log_err("writing to %s failed", path); + goto fail; + } + + fclose(f); + return 0; + +fail: + fclose(f); + num_proc_mods--; + return -1; +} + +/** + * restore_proc() - Restore all /proc modifications + */ +static void restore_proc(void) +{ + int i; + + for (i = 0; i < num_proc_mods; i++) { + struct proc_mod *mod = &proc_mods[i]; + FILE *f; + + f = fopen(mod->path, "w"); + if (!f) { + log_err("fopen of %s failed", mod->path); + continue; + } + + if (fwrite(mod->oldval, mod->oldlen, 1, f) != 1) + log_err("fwrite to %s failed", mod->path); + + fclose(f); + } + num_proc_mods = 0; +} + +/** + * setns_by_name() - Set networks namespace by name + */ +static int setns_by_name(const char *name) +{ + int nsfd; + char nspath[PATH_MAX]; + int err; + + snprintf(nspath, sizeof(nspath), "%s/%s", "/var/run/netns", name); + nsfd = open(nspath, O_RDONLY | O_CLOEXEC); + if (nsfd < 0) + return nsfd; + + err = setns(nsfd, CLONE_NEWNET); + close(nsfd); + + return err; +} + +/** + * setns_root() - Set network namespace to original (root) namespace + * + * Not expected to ever fail, so error not returned, but failure logged + * and test marked as failed. + */ +static void setns_root(void) +{ + ASSERT_OK(setns(root_netns_fd, CLONE_NEWNET), "setns root"); +} + +static int netns_setup_namespaces(const char *verb) +{ + const char * const *ns = namespaces; + char cmd[128]; + + while (*ns) { + snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb, *ns); + if (!ASSERT_OK(system(cmd), cmd)) + return -1; + ns++; + } + return 0; +} + +struct netns_setup_result { + int ifindex_veth_src_fwd; + int ifindex_veth_dst_fwd; +}; + +static int get_ifaddr(const char *name, char *ifaddr) +{ + char path[PATH_MAX]; + FILE *f; + int ret; + + snprintf(path, PATH_MAX, "/sys/class/net/%s/address", name); + f = fopen(path, "r"); + if (!ASSERT_OK_PTR(f, path)) + return -1; + + ret = fread(ifaddr, 1, IFADDR_STR_LEN, f); + if (!ASSERT_EQ(ret, IFADDR_STR_LEN, "fread ifaddr")) { + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int get_ifindex(const char *name) +{ + char path[PATH_MAX]; + char buf[32]; + FILE *f; + int ret; + + snprintf(path, PATH_MAX, "/sys/class/net/%s/ifindex", name); + f = fopen(path, "r"); + if (!ASSERT_OK_PTR(f, path)) + return -1; + + ret = fread(buf, 1, sizeof(buf), f); + if (!ASSERT_GT(ret, 0, "fread ifindex")) { + fclose(f); + return -1; + } + fclose(f); + return atoi(buf); +} + +#define SYS(fmt, ...) \ + ({ \ + char cmd[1024]; \ + snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ + if (!ASSERT_OK(system(cmd), cmd)) \ + goto fail; \ + }) + +static int netns_setup_links_and_routes(struct netns_setup_result *result) +{ + char veth_src_fwd_addr[IFADDR_STR_LEN+1] = {}; + char veth_dst_fwd_addr[IFADDR_STR_LEN+1] = {}; + + SYS("ip link add veth_src type veth peer name veth_src_fwd"); + SYS("ip link add veth_dst type veth peer name veth_dst_fwd"); + if (get_ifaddr("veth_src_fwd", veth_src_fwd_addr)) + goto fail; + if (get_ifaddr("veth_dst_fwd", veth_dst_fwd_addr)) + goto fail; + + result->ifindex_veth_src_fwd = get_ifindex("veth_src_fwd"); + if (result->ifindex_veth_src_fwd < 0) + goto fail; + result->ifindex_veth_dst_fwd = get_ifindex("veth_dst_fwd"); + if (result->ifindex_veth_dst_fwd < 0) + goto fail; + + SYS("ip link set veth_src netns " NS_SRC); + SYS("ip link set veth_src_fwd netns " NS_FWD); + SYS("ip link set veth_dst_fwd netns " NS_FWD); + SYS("ip link set veth_dst netns " NS_DST); + + /** setup in 'src' namespace */ + if (!ASSERT_OK(setns_by_name(NS_SRC), "setns src")) + goto fail; + + SYS("ip addr add " IP4_SRC "/32 dev veth_src"); + SYS("ip addr add " IP6_SRC "/128 dev veth_src nodad"); + SYS("ip link set dev veth_src up"); + + SYS("ip route add " IP4_DST "/32 dev veth_src scope global"); + SYS("ip route add " IP4_NET "/16 dev veth_src scope global"); + SYS("ip route add " IP6_DST "/128 dev veth_src scope global"); + + SYS("ip neigh add " IP4_DST " dev veth_src lladdr %s", + veth_src_fwd_addr); + SYS("ip neigh add " IP6_DST " dev veth_src lladdr %s", + veth_src_fwd_addr); + + /** setup in 'fwd' namespace */ + if (!ASSERT_OK(setns_by_name(NS_FWD), "setns fwd")) + goto fail; + + /* The fwd netns automatically gets a v6 LL address / routes, but also + * needs v4 one in order to start ARP probing. IP4_NET route is added + * to the endpoints so that the ARP processing will reply. + */ + SYS("ip addr add " IP4_SLL "/32 dev veth_src_fwd"); + SYS("ip addr add " IP4_DLL "/32 dev veth_dst_fwd"); + SYS("ip link set dev veth_src_fwd up"); + SYS("ip link set dev veth_dst_fwd up"); + + SYS("ip route add " IP4_SRC "/32 dev veth_src_fwd scope global"); + SYS("ip route add " IP6_SRC "/128 dev veth_src_fwd scope global"); + SYS("ip route add " IP4_DST "/32 dev veth_dst_fwd scope global"); + SYS("ip route add " IP6_DST "/128 dev veth_dst_fwd scope global"); + + /** setup in 'dst' namespace */ + if (!ASSERT_OK(setns_by_name(NS_DST), "setns dst")) + goto fail; + + SYS("ip addr add " IP4_DST "/32 dev veth_dst"); + SYS("ip addr add " IP6_DST "/128 dev veth_dst nodad"); + SYS("ip link set dev veth_dst up"); + + SYS("ip route add " IP4_SRC "/32 dev veth_dst scope global"); + SYS("ip route add " IP4_NET "/16 dev veth_dst scope global"); + SYS("ip route add " IP6_SRC "/128 dev veth_dst scope global"); + + SYS("ip neigh add " IP4_SRC " dev veth_dst lladdr %s", + veth_dst_fwd_addr); + SYS("ip neigh add " IP6_SRC " dev veth_dst lladdr %s", + veth_dst_fwd_addr); + + setns_root(); + return 0; +fail: + setns_root(); + return -1; +} + +static int netns_load_bpf(void) +{ + if (!ASSERT_OK(setns_by_name(NS_FWD), "setns fwd")) + return -1; + + SYS("tc qdisc add dev veth_src_fwd clsact"); + SYS("tc filter add dev veth_src_fwd ingress bpf da object-pinned " + SRC_PROG_PIN_FILE); + SYS("tc filter add dev veth_src_fwd egress bpf da object-pinned " + CHK_PROG_PIN_FILE); + + SYS("tc qdisc add dev veth_dst_fwd clsact"); + SYS("tc filter add dev veth_dst_fwd ingress bpf da object-pinned " + DST_PROG_PIN_FILE); + SYS("tc filter add dev veth_dst_fwd egress bpf da object-pinned " + CHK_PROG_PIN_FILE); + + setns_root(); + return -1; +fail: + setns_root(); + return -1; +} + +static int netns_unload_bpf(void) +{ + if (!ASSERT_OK(setns_by_name(NS_FWD), "setns fwd")) + goto fail; + SYS("tc qdisc delete dev veth_src_fwd clsact"); + SYS("tc qdisc delete dev veth_dst_fwd clsact"); + + setns_root(); + return 0; +fail: + setns_root(); + return -1; +} + + +static void test_tcp(int family, const char *addr, __u16 port) +{ + int listen_fd = -1, accept_fd = -1, client_fd = -1; + char buf[] = "testing testing"; + int n; + + if (!ASSERT_OK(setns_by_name(NS_DST), "setns dst")) + return; + + listen_fd = start_server(family, SOCK_STREAM, addr, port, 0); + if (!ASSERT_GE(listen_fd, 0, "listen")) + goto done; + + if (!ASSERT_OK(setns_by_name(NS_SRC), "setns src")) + goto done; + + client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS); + if (!ASSERT_GE(client_fd, 0, "connect_to_fd")) + goto done; + + accept_fd = accept(listen_fd, NULL, NULL); + if (!ASSERT_GE(accept_fd, 0, "accept")) + goto done; + + if (!ASSERT_OK(settimeo(accept_fd, TIMEOUT_MILLIS), "settimeo")) + goto done; + + n = write(client_fd, buf, sizeof(buf)); + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) + goto done; + + n = read(accept_fd, buf, sizeof(buf)); + ASSERT_EQ(n, sizeof(buf), "recv from server"); + +done: + setns_root(); + if (listen_fd >= 0) + close(listen_fd); + if (accept_fd >= 0) + close(accept_fd); + if (client_fd >= 0) + close(client_fd); +} + +static int test_ping(int family, const char *addr) +{ + const char *ping = family == AF_INET6 ? "ping6" : "ping"; + + SYS("ip netns exec " NS_SRC " %s " PING_ARGS " %s", ping, addr); + return 0; +fail: + return -1; +} + +static void test_connectivity(void) +{ + test_tcp(AF_INET, IP4_DST, IP4_PORT); + test_ping(AF_INET, IP4_DST); + test_tcp(AF_INET6, IP6_DST, IP6_PORT); + test_ping(AF_INET6, IP6_DST); +} + +static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result) +{ + struct test_tc_neigh_fib *skel; + int err; + + skel = test_tc_neigh_fib__open(); + if (!ASSERT_OK_PTR(skel, "test_tc_neigh_fib__open")) + return; + + if (!ASSERT_OK(test_tc_neigh_fib__load(skel), "test_tc_neigh_fib__load")) { + test_tc_neigh_fib__destroy(skel); + return; + } + + err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) + goto done; + + if (netns_load_bpf()) + goto done; + + /* bpf_fib_lookup() checks if forwarding is enabled */ + if (!ASSERT_OK(setns_by_name(NS_FWD), "setns fwd")) + goto done; + + err = modify_proc("/proc/sys/net/ipv4/ip_forward", "1"); + if (!ASSERT_OK(err, "set ipv4.ip_forward")) + goto done; + + err = modify_proc("/proc/sys/net/ipv6/conf/all/forwarding", "1"); + if (!ASSERT_OK(err, "set ipv6.forwarding")) + goto done; + setns_root(); + + test_connectivity(); +done: + bpf_program__unpin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + test_tc_neigh_fib__destroy(skel); + netns_unload_bpf(); + setns_root(); + restore_proc(); +} + +static void test_tc_redirect_neigh(struct netns_setup_result *setup_result) +{ + struct test_tc_neigh *skel; + int err; + + skel = test_tc_neigh__open(); + if (!ASSERT_OK_PTR(skel, "test_tc_neigh__open")) + return; + + skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; + skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; + + err = test_tc_neigh__load(skel); + if (!ASSERT_OK(err, "test_tc_neigh__load")) { + test_tc_neigh__destroy(skel); + return; + } + + err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) + goto done; + + if (netns_load_bpf()) + goto done; + + test_connectivity(); + +done: + bpf_program__unpin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + test_tc_neigh__destroy(skel); + netns_unload_bpf(); + setns_root(); +} + +static void test_tc_redirect_peer(struct netns_setup_result *setup_result) +{ + struct test_tc_peer *skel; + int err; + + skel = test_tc_peer__open(); + if (!ASSERT_OK_PTR(skel, "test_tc_peer__open")) + return; + + skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd; + skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd; + + err = test_tc_peer__load(skel); + if (!ASSERT_OK(err, "test_tc_peer__load")) { + test_tc_peer__destroy(skel); + return; + } + + err = bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " SRC_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " CHK_PROG_PIN_FILE)) + goto done; + + err = bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + if (!ASSERT_OK(err, "pin " DST_PROG_PIN_FILE)) + goto done; + + if (netns_load_bpf()) + goto done; + + test_connectivity(); + +done: + bpf_program__unpin(skel->progs.tc_src, SRC_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_chk, CHK_PROG_PIN_FILE); + bpf_program__unpin(skel->progs.tc_dst, DST_PROG_PIN_FILE); + test_tc_peer__destroy(skel); + netns_unload_bpf(); + setns_root(); +} + +void test_tc_redirect(void) +{ + struct netns_setup_result setup_result; + + root_netns_fd = open("/proc/self/ns/net", O_RDONLY); + if (!ASSERT_GE(root_netns_fd, 0, "open /proc/self/ns/net")) + return; + + if (netns_setup_namespaces("add")) + goto done; + + if (netns_setup_links_and_routes(&setup_result)) + goto done; + + if (test__start_subtest("tc_redirect_peer")) + test_tc_redirect_peer(&setup_result); + + if (test__start_subtest("tc_redirect_neigh")) + test_tc_redirect_neigh(&setup_result); + + if (test__start_subtest("tc_redirect_neigh_fib")) + test_tc_redirect_neigh_fib(&setup_result); + +done: + close(root_netns_fd); + netns_setup_namespaces("delete"); +} diff --git a/tools/testing/selftests/bpf/progs/test_tc_neigh.c b/tools/testing/selftests/bpf/progs/test_tc_neigh.c index b985ac4e7a81..90f64a85998f 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_neigh.c +++ b/tools/testing/selftests/bpf/progs/test_tc_neigh.c @@ -33,17 +33,8 @@ a.s6_addr32[3] == b.s6_addr32[3]) #endif -enum { - dev_src, - dev_dst, -}; - -struct bpf_map_def SEC("maps") ifindex_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 2, -}; +static volatile const __u32 IFINDEX_SRC; +static volatile const __u32 IFINDEX_DST; static __always_inline bool is_remote_ep_v4(struct __sk_buff *skb, __be32 addr) @@ -79,14 +70,8 @@ static __always_inline bool is_remote_ep_v6(struct __sk_buff *skb, return v6_equal(ip6h->daddr, addr); } -static __always_inline int get_dev_ifindex(int which) -{ - int *ifindex = bpf_map_lookup_elem(&ifindex_map, &which); - - return ifindex ? *ifindex : 0; -} - -SEC("chk_egress") int tc_chk(struct __sk_buff *skb) +SEC("classifier/chk_egress") +int tc_chk(struct __sk_buff *skb) { void *data_end = ctx_ptr(skb->data_end); void *data = ctx_ptr(skb->data); @@ -98,7 +83,8 @@ SEC("chk_egress") int tc_chk(struct __sk_buff *skb) return !raw[0] && !raw[1] && !raw[2] ? TC_ACT_SHOT : TC_ACT_OK; } -SEC("dst_ingress") int tc_dst(struct __sk_buff *skb) +SEC("classifier/dst_ingress") +int tc_dst(struct __sk_buff *skb) { __u8 zero[ETH_ALEN * 2]; bool redirect = false; @@ -119,10 +105,11 @@ SEC("dst_ingress") int tc_dst(struct __sk_buff *skb) if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0) return TC_ACT_SHOT; - return bpf_redirect_neigh(get_dev_ifindex(dev_src), NULL, 0, 0); + return bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0); } -SEC("src_ingress") int tc_src(struct __sk_buff *skb) +SEC("classifier/src_ingress") +int tc_src(struct __sk_buff *skb) { __u8 zero[ETH_ALEN * 2]; bool redirect = false; @@ -143,7 +130,7 @@ SEC("src_ingress") int tc_src(struct __sk_buff *skb) if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0) return TC_ACT_SHOT; - return bpf_redirect_neigh(get_dev_ifindex(dev_dst), NULL, 0, 0); + return bpf_redirect_neigh(IFINDEX_DST, NULL, 0, 0); } char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_tc_neigh_fib.c b/tools/testing/selftests/bpf/progs/test_tc_neigh_fib.c index d82ed3457030..f7ab69cf018e 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_neigh_fib.c +++ b/tools/testing/selftests/bpf/progs/test_tc_neigh_fib.c @@ -75,7 +75,8 @@ static __always_inline int fill_fib_params_v6(struct __sk_buff *skb, return 0; } -SEC("chk_egress") int tc_chk(struct __sk_buff *skb) +SEC("classifier/chk_egress") +int tc_chk(struct __sk_buff *skb) { void *data_end = ctx_ptr(skb->data_end); void *data = ctx_ptr(skb->data); @@ -142,12 +143,14 @@ static __always_inline int tc_redir(struct __sk_buff *skb) /* these are identical, but keep them separate for compatibility with the * section names expected by test_tc_redirect.sh */ -SEC("dst_ingress") int tc_dst(struct __sk_buff *skb) +SEC("classifier/dst_ingress") +int tc_dst(struct __sk_buff *skb) { return tc_redir(skb); } -SEC("src_ingress") int tc_src(struct __sk_buff *skb) +SEC("classifier/src_ingress") +int tc_src(struct __sk_buff *skb) { return tc_redir(skb); } diff --git a/tools/testing/selftests/bpf/progs/test_tc_peer.c b/tools/testing/selftests/bpf/progs/test_tc_peer.c index fc84a7685aa2..72c72950c3bb 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_peer.c +++ b/tools/testing/selftests/bpf/progs/test_tc_peer.c @@ -8,38 +8,25 @@ #include -enum { - dev_src, - dev_dst, -}; +static volatile const __u32 IFINDEX_SRC; +static volatile const __u32 IFINDEX_DST; -struct bpf_map_def SEC("maps") ifindex_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 2, -}; - -static __always_inline int get_dev_ifindex(int which) -{ - int *ifindex = bpf_map_lookup_elem(&ifindex_map, &which); - - return ifindex ? *ifindex : 0; -} - -SEC("chk_egress") int tc_chk(struct __sk_buff *skb) +SEC("classifier/chk_egress") +int tc_chk(struct __sk_buff *skb) { return TC_ACT_SHOT; } -SEC("dst_ingress") int tc_dst(struct __sk_buff *skb) +SEC("classifier/dst_ingress") +int tc_dst(struct __sk_buff *skb) { - return bpf_redirect_peer(get_dev_ifindex(dev_src), 0); + return bpf_redirect_peer(IFINDEX_SRC, 0); } -SEC("src_ingress") int tc_src(struct __sk_buff *skb) +SEC("classifier/src_ingress") +int tc_src(struct __sk_buff *skb) { - return bpf_redirect_peer(get_dev_ifindex(dev_dst), 0); + return bpf_redirect_peer(IFINDEX_DST, 0); } char __license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_tc_redirect.sh b/tools/testing/selftests/bpf/test_tc_redirect.sh deleted file mode 100755 index 8868aa1ca902..000000000000 --- a/tools/testing/selftests/bpf/test_tc_redirect.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 -# -# This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link -# between src and dst. The netns fwd has veth links to each src and dst. The -# client is in src and server in dst. The test installs a TC BPF program to each -# host facing veth in fwd which calls into i) bpf_redirect_neigh() to perform the -# neigh addr population and redirect or ii) bpf_redirect_peer() for namespace -# switch from ingress side; it also installs a checker prog on the egress side -# to drop unexpected traffic. - -if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root" - echo "FAIL" - exit 1 -fi - -# check that needed tools are present -command -v nc >/dev/null 2>&1 || \ - { echo >&2 "nc is not available"; exit 1; } -command -v dd >/dev/null 2>&1 || \ - { echo >&2 "dd is not available"; exit 1; } -command -v timeout >/dev/null 2>&1 || \ - { echo >&2 "timeout is not available"; exit 1; } -command -v ping >/dev/null 2>&1 || \ - { echo >&2 "ping is not available"; exit 1; } -if command -v ping6 >/dev/null 2>&1; then PING6=ping6; else PING6=ping; fi -command -v perl >/dev/null 2>&1 || \ - { echo >&2 "perl is not available"; exit 1; } -command -v jq >/dev/null 2>&1 || \ - { echo >&2 "jq is not available"; exit 1; } -command -v bpftool >/dev/null 2>&1 || \ - { echo >&2 "bpftool is not available"; exit 1; } - -readonly GREEN='\033[0;92m' -readonly RED='\033[0;31m' -readonly NC='\033[0m' # No Color - -readonly PING_ARG="-c 3 -w 10 -q" - -readonly TIMEOUT=10 - -readonly NS_SRC="ns-src-$(mktemp -u XXXXXX)" -readonly NS_FWD="ns-fwd-$(mktemp -u XXXXXX)" -readonly NS_DST="ns-dst-$(mktemp -u XXXXXX)" - -readonly IP4_SRC="172.16.1.100" -readonly IP4_DST="172.16.2.100" - -readonly IP6_SRC="::1:dead:beef:cafe" -readonly IP6_DST="::2:dead:beef:cafe" - -readonly IP4_SLL="169.254.0.1" -readonly IP4_DLL="169.254.0.2" -readonly IP4_NET="169.254.0.0" - -netns_cleanup() -{ - ip netns del ${NS_SRC} - ip netns del ${NS_FWD} - ip netns del ${NS_DST} -} - -netns_setup() -{ - ip netns add "${NS_SRC}" - ip netns add "${NS_FWD}" - ip netns add "${NS_DST}" - - ip link add veth_src type veth peer name veth_src_fwd - ip link add veth_dst type veth peer name veth_dst_fwd - - ip link set veth_src netns ${NS_SRC} - ip link set veth_src_fwd netns ${NS_FWD} - - ip link set veth_dst netns ${NS_DST} - ip link set veth_dst_fwd netns ${NS_FWD} - - ip -netns ${NS_SRC} addr add ${IP4_SRC}/32 dev veth_src - ip -netns ${NS_DST} addr add ${IP4_DST}/32 dev veth_dst - - # The fwd netns automatically get a v6 LL address / routes, but also - # needs v4 one in order to start ARP probing. IP4_NET route is added - # to the endpoints so that the ARP processing will reply. - - ip -netns ${NS_FWD} addr add ${IP4_SLL}/32 dev veth_src_fwd - ip -netns ${NS_FWD} addr add ${IP4_DLL}/32 dev veth_dst_fwd - - ip -netns ${NS_SRC} addr add ${IP6_SRC}/128 dev veth_src nodad - ip -netns ${NS_DST} addr add ${IP6_DST}/128 dev veth_dst nodad - - ip -netns ${NS_SRC} link set dev veth_src up - ip -netns ${NS_FWD} link set dev veth_src_fwd up - - ip -netns ${NS_DST} link set dev veth_dst up - ip -netns ${NS_FWD} link set dev veth_dst_fwd up - - ip -netns ${NS_SRC} route add ${IP4_DST}/32 dev veth_src scope global - ip -netns ${NS_SRC} route add ${IP4_NET}/16 dev veth_src scope global - ip -netns ${NS_FWD} route add ${IP4_SRC}/32 dev veth_src_fwd scope global - - ip -netns ${NS_SRC} route add ${IP6_DST}/128 dev veth_src scope global - ip -netns ${NS_FWD} route add ${IP6_SRC}/128 dev veth_src_fwd scope global - - ip -netns ${NS_DST} route add ${IP4_SRC}/32 dev veth_dst scope global - ip -netns ${NS_DST} route add ${IP4_NET}/16 dev veth_dst scope global - ip -netns ${NS_FWD} route add ${IP4_DST}/32 dev veth_dst_fwd scope global - - ip -netns ${NS_DST} route add ${IP6_SRC}/128 dev veth_dst scope global - ip -netns ${NS_FWD} route add ${IP6_DST}/128 dev veth_dst_fwd scope global - - fmac_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/address) - fmac_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/address) - - ip -netns ${NS_SRC} neigh add ${IP4_DST} dev veth_src lladdr $fmac_src - ip -netns ${NS_DST} neigh add ${IP4_SRC} dev veth_dst lladdr $fmac_dst - - ip -netns ${NS_SRC} neigh add ${IP6_DST} dev veth_src lladdr $fmac_src - ip -netns ${NS_DST} neigh add ${IP6_SRC} dev veth_dst lladdr $fmac_dst -} - -netns_test_connectivity() -{ - set +e - - ip netns exec ${NS_DST} bash -c "nc -4 -l -p 9004 &" - ip netns exec ${NS_DST} bash -c "nc -6 -l -p 9006 &" - - TEST="TCPv4 connectivity test" - ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP4_DST}/9004" - if [ $? -ne 0 ]; then - echo -e "${TEST}: ${RED}FAIL${NC}" - exit 1 - fi - echo -e "${TEST}: ${GREEN}PASS${NC}" - - TEST="TCPv6 connectivity test" - ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero bs=1000 count=100 > /dev/tcp/${IP6_DST}/9006" - if [ $? -ne 0 ]; then - echo -e "${TEST}: ${RED}FAIL${NC}" - exit 1 - fi - echo -e "${TEST}: ${GREEN}PASS${NC}" - - TEST="ICMPv4 connectivity test" - ip netns exec ${NS_SRC} ping $PING_ARG ${IP4_DST} - if [ $? -ne 0 ]; then - echo -e "${TEST}: ${RED}FAIL${NC}" - exit 1 - fi - echo -e "${TEST}: ${GREEN}PASS${NC}" - - TEST="ICMPv6 connectivity test" - ip netns exec ${NS_SRC} $PING6 $PING_ARG ${IP6_DST} - if [ $? -ne 0 ]; then - echo -e "${TEST}: ${RED}FAIL${NC}" - exit 1 - fi - echo -e "${TEST}: ${GREEN}PASS${NC}" - - set -e -} - -hex_mem_str() -{ - perl -e 'print join(" ", unpack("(H2)8", pack("L", @ARGV)))' $1 -} - -netns_setup_bpf() -{ - local obj=$1 - local use_forwarding=${2:-0} - - ip netns exec ${NS_FWD} tc qdisc add dev veth_src_fwd clsact - ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd ingress bpf da obj $obj sec src_ingress - ip netns exec ${NS_FWD} tc filter add dev veth_src_fwd egress bpf da obj $obj sec chk_egress - - ip netns exec ${NS_FWD} tc qdisc add dev veth_dst_fwd clsact - ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd ingress bpf da obj $obj sec dst_ingress - ip netns exec ${NS_FWD} tc filter add dev veth_dst_fwd egress bpf da obj $obj sec chk_egress - - if [ "$use_forwarding" -eq "1" ]; then - # bpf_fib_lookup() checks if forwarding is enabled - ip netns exec ${NS_FWD} sysctl -w net.ipv4.ip_forward=1 - ip netns exec ${NS_FWD} sysctl -w net.ipv6.conf.veth_dst_fwd.forwarding=1 - ip netns exec ${NS_FWD} sysctl -w net.ipv6.conf.veth_src_fwd.forwarding=1 - return 0 - fi - - veth_src=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_src_fwd/ifindex) - veth_dst=$(ip netns exec ${NS_FWD} cat /sys/class/net/veth_dst_fwd/ifindex) - - progs=$(ip netns exec ${NS_FWD} bpftool net --json | jq -r '.[] | .tc | map(.id) | .[]') - for prog in $progs; do - map=$(bpftool prog show id $prog --json | jq -r '.map_ids | .? | .[]') - if [ ! -z "$map" ]; then - bpftool map update id $map key hex $(hex_mem_str 0) value hex $(hex_mem_str $veth_src) - bpftool map update id $map key hex $(hex_mem_str 1) value hex $(hex_mem_str $veth_dst) - fi - done -} - -trap netns_cleanup EXIT -set -e - -netns_setup -netns_setup_bpf test_tc_neigh.o -netns_test_connectivity -netns_cleanup -netns_setup -netns_setup_bpf test_tc_neigh_fib.o 1 -netns_test_connectivity -netns_cleanup -netns_setup -netns_setup_bpf test_tc_peer.o -netns_test_connectivity -- cgit v1.2.3 From 569c484f9995f489f2b80dd134269fe07d2b900d Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 7 May 2021 17:50:11 -0700 Subject: bpf: Limit static tcp-cc functions in the .BTF_ids list to x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the discussion in [0]. It was pointed out that static functions in ppc64 is prefixed with ".". For example, the 'readelf -s vmlinux.ppc': 89326: c000000001383280 24 NOTYPE LOCAL DEFAULT 31 cubictcp_init 89327: c000000000c97c50 168 FUNC LOCAL DEFAULT 2 .cubictcp_init The one with FUNC type is ".cubictcp_init" instead of "cubictcp_init". The "." seems to be done by arch/powerpc/include/asm/ppc_asm.h. This caused that pahole cannot generate the BTF for these tcp-cc kernel functions because pahole only captures the FUNC type and "cubictcp_init" is not. It then failed the kernel compilation in ppc64. This behavior is only reported in ppc64 so far. I tried arm64, s390, and sparc64 and did not observe this "." prefix and NOTYPE behavior. Since the kfunc call is only supported in the x86_64 and x86_32 JIT, this patch limits those tcp-cc functions to x86 only to avoid unnecessary compilation issue in other ARCHs. In the future, we can examine if it is better to change all those functions from static to extern. [0] https://lore.kernel.org/bpf/4e051459-8532-7b61-c815-f3435767f8a0@kernel.org/ Fixes: e78aea8b2170 ("bpf: tcp: Put some tcp cong functions in allowlist for bpf-tcp-cc") Signed-off-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann Cc: Michal Suchánek Cc: Jiri Slaby Cc: Jiri Olsa Link: https://lore.kernel.org/bpf/20210508005011.3863757-1-kafai@fb.com --- net/ipv4/bpf_tcp_ca.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index dff4f0eb96b0..9e41eff4a685 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -185,6 +185,7 @@ BTF_ID(func, tcp_reno_cong_avoid) BTF_ID(func, tcp_reno_undo_cwnd) BTF_ID(func, tcp_slow_start) BTF_ID(func, tcp_cong_avoid_ai) +#ifdef CONFIG_X86 #ifdef CONFIG_DYNAMIC_FTRACE #if IS_BUILTIN(CONFIG_TCP_CONG_CUBIC) BTF_ID(func, cubictcp_init) @@ -213,6 +214,7 @@ BTF_ID(func, bbr_min_tso_segs) BTF_ID(func, bbr_set_state) #endif #endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_X86 */ BTF_SET_END(bpf_tcp_ca_kfunc_ids) static bool bpf_tcp_ca_check_kfunc_call(u32 kfunc_btf_id) -- cgit v1.2.3 From 576f9eacc680d2b1f37e8010cff62f7b227ea769 Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Mon, 10 May 2021 14:55:09 +0800 Subject: net: stmmac: Fix MAC WoL not working if PHY does not support WoL Both get and set WoL will check device_can_wakeup(), if MAC supports PMT, it will set device wakeup capability. After commit 1d8e5b0f3f2c ("net: stmmac: Support WOL with phy"), device wakeup capability will be overwrite in stmmac_init_phy() according to phy's Wol feature. If phy doesn't support WoL, then MAC will lose wakeup capability. To fix this issue, only overwrite device wakeup capability when MAC doesn't support PMT. For STMMAC now driver checks MAC's WoL capability if MAC supports PMT, if not support, driver will check PHY's WoL capability. Fixes: 1d8e5b0f3f2c ("net: stmmac: Support WOL with phy") Reviewed-by: Jisheng Zhang Signed-off-by: Joakim Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 345b4c6d1fd4..fea3bf07ae89 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1196,7 +1196,6 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) */ static int stmmac_init_phy(struct net_device *dev) { - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; struct stmmac_priv *priv = netdev_priv(dev); struct device_node *node; int ret; @@ -1222,8 +1221,12 @@ static int stmmac_init_phy(struct net_device *dev) ret = phylink_connect_phy(priv->phylink, phydev); } - phylink_ethtool_get_wol(priv->phylink, &wol); - device_set_wakeup_capable(priv->device, !!wol.supported); + if (!priv->plat->pmt) { + struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + + phylink_ethtool_get_wol(priv->phylink, &wol); + device_set_wakeup_capable(priv->device, !!wol.supported); + } return ret; } -- cgit v1.2.3 From 29249eac5225429b898f278230a6ca2baa1ae154 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 11 May 2021 19:13:51 +0200 Subject: mptcp: fix data stream corruption Maxim reported several issues when forcing a TCP transparent proxy to use the MPTCP protocol for the inbound connections. He also provided a clean reproducer. The problem boils down to 'mptcp_frag_can_collapse_to()' assuming that only MPTCP will use the given page_frag. If others - e.g. the plain TCP protocol - allocate page fragments, we can end-up re-using already allocated memory for mptcp_data_frag. Fix the issue ensuring that the to-be-expanded data fragment is located at the current page frag end. v1 -> v2: - added missing fixes tag (Mat) Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/178 Reported-and-tested-by: Maxim Galaganov Fixes: 18b683bff89d ("mptcp: queue data for mptcp level retransmission") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller --- net/mptcp/protocol.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 29a2d690d8d5..2d21a4793d9d 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -879,12 +879,18 @@ static bool mptcp_skb_can_collapse_to(u64 write_seq, !mpext->frozen; } +/* we can append data to the given data frag if: + * - there is space available in the backing page_frag + * - the data frag tail matches the current page_frag free offset + * - the data frag end sequence number matches the current write seq + */ static bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk, const struct page_frag *pfrag, const struct mptcp_data_frag *df) { return df && pfrag->page == df->page && pfrag->size - pfrag->offset > 0 && + pfrag->offset == (df->offset + df->data_len) && df->data_seq + df->data_len == msk->write_seq; } -- cgit v1.2.3 From bcbda3fc616272686208f9c4d5f6dccb65360bd8 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 11 May 2021 11:11:32 -0700 Subject: ionic: fix ptp support config breakage When IONIC=y and PTP_1588_CLOCK=m were set in the .config file the driver link failed with undefined references. We add the dependancy depends on PTP_1588_CLOCK || !PTP_1588_CLOCK to clear this up. If PTP_1588_CLOCK=m, the depends limits IONIC to =m (or disabled). If PTP_1588_CLOCK is disabled, IONIC can be any of y/m/n. Fixes: 61db421da31b ("ionic: link in the new hw timestamp code") Reported-by: kernel test robot Cc: Jakub Kicinski Cc: Randy Dunlap Cc: Allen Hubbe Signed-off-by: Shannon Nelson Acked-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/pensando/Kconfig b/drivers/net/ethernet/pensando/Kconfig index 5f8b0bb3af6e..202973a82712 100644 --- a/drivers/net/ethernet/pensando/Kconfig +++ b/drivers/net/ethernet/pensando/Kconfig @@ -20,6 +20,7 @@ if NET_VENDOR_PENSANDO config IONIC tristate "Pensando Ethernet IONIC Support" depends on 64BIT && PCI + depends on PTP_1588_CLOCK || !PTP_1588_CLOCK select NET_DEVLINK select DIMLIB help -- cgit v1.2.3 From 440c3247cba3d9433ac435d371dd7927d68772a7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 11 May 2021 14:42:04 -0500 Subject: net: ipa: memory region array is variable size IPA configuration data includes an array of memory region descriptors. That was a fixed-size array at one time, but at some point we started defining it such that it was only as big as required for a given platform. The actual number of entries in the array is recorded in the configuration data along with the array. A loop in ipa_mem_config() still assumes the array has entries for all defined memory region IDs. As a result, this loop can go past the end of the actual array and attempt to write "canary" values based on nonsensical data. Fix this, by stashing the number of entries in the array, and using that rather than IPA_MEM_COUNT in the initialization loop found in ipa_mem_config(). The only remaining use of IPA_MEM_COUNT is in a validation check to ensure configuration data doesn't have too many entries. That's fine for now. Fixes: 3128aae8c439a ("net: ipa: redefine struct ipa_mem_data") Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa.h | 2 ++ drivers/net/ipa/ipa_mem.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ipa/ipa.h b/drivers/net/ipa/ipa.h index e7ff376cb5b7..744406832a77 100644 --- a/drivers/net/ipa/ipa.h +++ b/drivers/net/ipa/ipa.h @@ -58,6 +58,7 @@ enum ipa_flag { * @mem_virt: Virtual address of IPA-local memory space * @mem_offset: Offset from @mem_virt used for access to IPA memory * @mem_size: Total size (bytes) of memory at @mem_virt + * @mem_count: Number of entries in the mem array * @mem: Array of IPA-local memory region descriptors * @imem_iova: I/O virtual address of IPA region in IMEM * @imem_size: Size of IMEM region @@ -103,6 +104,7 @@ struct ipa { void *mem_virt; u32 mem_offset; u32 mem_size; + u32 mem_count; const struct ipa_mem *mem; unsigned long imem_iova; diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c index c5c3b1b7e67d..1624125e7459 100644 --- a/drivers/net/ipa/ipa_mem.c +++ b/drivers/net/ipa/ipa_mem.c @@ -180,7 +180,7 @@ int ipa_mem_config(struct ipa *ipa) * for the region, write "canary" values in the space prior to * the region's base address. */ - for (mem_id = 0; mem_id < IPA_MEM_COUNT; mem_id++) { + for (mem_id = 0; mem_id < ipa->mem_count; mem_id++) { const struct ipa_mem *mem = &ipa->mem[mem_id]; u16 canary_count; __le32 *canary; @@ -487,6 +487,7 @@ int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data) ipa->mem_size = resource_size(res); /* The ipa->mem[] array is indexed by enum ipa_mem_id values */ + ipa->mem_count = mem_data->local_count; ipa->mem = mem_data->local; ret = ipa_imem_init(ipa, mem_data->imem_addr, mem_data->imem_size); -- cgit v1.2.3 From 2b17c400aeb44daf041627722581ade527bb3c1d Mon Sep 17 00:00:00 2001 From: Norbert Slusarek Date: Wed, 12 May 2021 00:43:54 +0200 Subject: can: isotp: prevent race between isotp_bind() and isotp_setsockopt() A race condition was found in isotp_setsockopt() which allows to change socket options after the socket was bound. For the specific case of SF_BROADCAST support, this might lead to possible use-after-free because can_rx_unregister() is not called. Checking for the flag under the socket lock in isotp_bind() and taking the lock in isotp_setsockopt() fixes the issue. Fixes: 921ca574cd38 ("can: isotp: add SF_BROADCAST support for functional addressing") Link: https://lore.kernel.org/r/trinity-e6ae9efa-9afb-4326-84c0-f3609b9b8168-1620773528307@3c-app-gmx-bs06 Reported-by: Norbert Slusarek Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Norbert Slusarek Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- net/can/isotp.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/net/can/isotp.c b/net/can/isotp.c index 9f94ad3caee9..253b24417c8e 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1062,27 +1062,31 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (len < ISOTP_MIN_NAMELEN) return -EINVAL; + if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) + return -EADDRNOTAVAIL; + + if (!addr->can_ifindex) + return -ENODEV; + + lock_sock(sk); + /* do not register frame reception for functional addressing */ if (so->opt.flags & CAN_ISOTP_SF_BROADCAST) do_rx_reg = 0; /* do not validate rx address for functional addressing */ if (do_rx_reg) { - if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) - return -EADDRNOTAVAIL; + if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) { + err = -EADDRNOTAVAIL; + goto out; + } - if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) - return -EADDRNOTAVAIL; + if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + err = -EADDRNOTAVAIL; + goto out; + } } - if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) - return -EADDRNOTAVAIL; - - if (!addr->can_ifindex) - return -ENODEV; - - lock_sock(sk); - if (so->bound && addr->can_ifindex == so->ifindex && addr->can_addr.tp.rx_id == so->rxid && addr->can_addr.tp.tx_id == so->txid) @@ -1164,16 +1168,13 @@ static int isotp_getname(struct socket *sock, struct sockaddr *uaddr, int peer) return ISOTP_MIN_NAMELEN; } -static int isotp_setsockopt(struct socket *sock, int level, int optname, +static int isotp_setsockopt_locked(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen) { struct sock *sk = sock->sk; struct isotp_sock *so = isotp_sk(sk); int ret = 0; - if (level != SOL_CAN_ISOTP) - return -EINVAL; - if (so->bound) return -EISCONN; @@ -1248,6 +1249,22 @@ static int isotp_setsockopt(struct socket *sock, int level, int optname, return ret; } +static int isotp_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + +{ + struct sock *sk = sock->sk; + int ret; + + if (level != SOL_CAN_ISOTP) + return -EINVAL; + + lock_sock(sk); + ret = isotp_setsockopt_locked(sock, level, optname, optval, optlen); + release_sock(sk); + return ret; +} + static int isotp_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { -- cgit v1.2.3 From c6c82e0cd8125d30f2f1b29205c7e1a2f1a6785b Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 11 May 2021 21:56:29 +0200 Subject: vfio-ccw: Check initialized flag in cp_init() We have a really nice flag in the channel_program struct that indicates if it had been initialized by cp_init(), and use it as a guard in the other cp accessor routines, but not for a duplicate call into cp_init(). The possibility of this occurring is low, because that flow is protected by the private->io_mutex and FSM CP_PROCESSING state. But then why bother checking it in (for example) cp_prefetch() then? Let's just be consistent and check for that in cp_init() too. Fixes: 71189f263f8a3 ("vfio-ccw: make it safe to access channel programs") Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Acked-by: Matthew Rosato Message-Id: <20210511195631.3995081-2-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- drivers/s390/cio/vfio_ccw_cp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index b9febc581b1f..8d1b2771c1aa 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -638,6 +638,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 1); int ret; + /* this is an error in the caller */ + if (cp->initialized) + return -EBUSY; + /* * We only support prefetching the channel program. We assume all channel * programs executed by supported guests likewise support prefetching. -- cgit v1.2.3 From 6c02ac4c9211edabe17bda437ac97e578756f31b Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 11 May 2021 21:56:30 +0200 Subject: vfio-ccw: Reset FSM state to IDLE inside FSM When an I/O request is made, the fsm_io_request() routine moves the FSM state from IDLE to CP_PROCESSING, and then fsm_io_helper() moves it to CP_PENDING if the START SUBCHANNEL received a cc0. Yet, the error case to go from CP_PROCESSING back to IDLE is done after the FSM call returns. Let's move this up into the FSM proper, to provide some better symmetry when unwinding in this case. Signed-off-by: Eric Farman Reviewed-by: Cornelia Huck Acked-by: Matthew Rosato Message-Id: <20210511195631.3995081-3-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- drivers/s390/cio/vfio_ccw_fsm.c | 1 + drivers/s390/cio/vfio_ccw_ops.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index 23e61aa638e4..e435a9cd92da 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -318,6 +318,7 @@ static void fsm_io_request(struct vfio_ccw_private *private, } err_out: + private->state = VFIO_CCW_STATE_IDLE; trace_vfio_ccw_fsm_io_request(scsw->cmd.fctl, schid, io_region->ret_code, errstr); } diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index 491a64c61fff..c57d2a7f0919 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -279,8 +279,6 @@ static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private, } vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ); - if (region->ret_code != 0) - private->state = VFIO_CCW_STATE_IDLE; ret = (region->ret_code != 0) ? region->ret_code : count; out_unlock: -- cgit v1.2.3 From 2af7a834a435460d546f0cf0a8b8e4d259f1d910 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Tue, 11 May 2021 21:56:31 +0200 Subject: vfio-ccw: Serialize FSM IDLE state with I/O completion Today, the stacked call to vfio_ccw_sch_io_todo() does three things: 1) Update a solicited IRB with CP information, and release the CP if the interrupt was the end of a START operation. 2) Copy the IRB data into the io_region, under the protection of the io_mutex 3) Reset the vfio-ccw FSM state to IDLE to acknowledge that vfio-ccw can accept more work. The trouble is that step 3 is (A) invoked for both solicited and unsolicited interrupts, and (B) sitting after the mutex for step 2. This second piece becomes a problem if it processes an interrupt for a CLEAR SUBCHANNEL while another thread initiates a START, thus allowing the CP and FSM states to get out of sync. That is: CPU 1 CPU 2 fsm_do_clear() fsm_irq() fsm_io_request() vfio_ccw_sch_io_todo() fsm_io_helper() Since the FSM state and CP should be kept in sync, let's make a note when the CP is released, and rely on that as an indication that the FSM should also be reset at the end of this routine and open up the device for more work. Signed-off-by: Eric Farman Acked-by: Matthew Rosato Reviewed-by: Cornelia Huck Message-Id: <20210511195631.3995081-4-farman@linux.ibm.com> Signed-off-by: Cornelia Huck --- drivers/s390/cio/vfio_ccw_drv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 8c625b530035..9b61e9b131ad 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -86,6 +86,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) struct vfio_ccw_private *private; struct irb *irb; bool is_final; + bool cp_is_finished = false; private = container_of(work, struct vfio_ccw_private, io_work); irb = &private->irb; @@ -94,14 +95,21 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)); if (scsw_is_solicited(&irb->scsw)) { cp_update_scsw(&private->cp, &irb->scsw); - if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) + if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) { cp_free(&private->cp); + cp_is_finished = true; + } } mutex_lock(&private->io_mutex); memcpy(private->io_region->irb_area, irb, sizeof(*irb)); mutex_unlock(&private->io_mutex); - if (private->mdev && is_final) + /* + * Reset to IDLE only if processing of a channel program + * has finished. Do not overwrite a possible processing + * state if the final interrupt was for HSCH or CSCH. + */ + if (private->mdev && cp_is_finished) private->state = VFIO_CCW_STATE_IDLE; if (private->io_trigger) -- cgit v1.2.3 From 47c1131633ef6210add63b8b5704497023a3462a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 May 2021 08:09:08 +0900 Subject: ASoC: soc-dai.h: Align the word of comment for SND_SOC_DAIFMT_CBC_CFC Let's use "consumer" instead of "follower". Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/8735usc1gr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 1358a0ceb4d0..0bc29c4516e7 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -81,7 +81,7 @@ struct snd_compr_stream; #define SND_SOC_DAIFMT_CBP_CFP (1 << 12) /* codec clk provider & frame provider */ #define SND_SOC_DAIFMT_CBC_CFP (2 << 12) /* codec clk consumer & frame provider */ #define SND_SOC_DAIFMT_CBP_CFC (3 << 12) /* codec clk provider & frame consumer */ -#define SND_SOC_DAIFMT_CBC_CFC (4 << 12) /* codec clk consumer & frame follower */ +#define SND_SOC_DAIFMT_CBC_CFC (4 << 12) /* codec clk consumer & frame consumer */ /* previous definitions kept for backwards-compatibility, do not use in new contributions */ #define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP -- cgit v1.2.3 From e072b2671606c77538d6a4dd5dda80b508cb4816 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Wed, 12 May 2021 11:12:25 +0800 Subject: ASoC: sti-sas: add missing MODULE_DEVICE_TABLE This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot Signed-off-by: Zou Wei Link: https://lore.kernel.org/r/1620789145-14936-1-git-send-email-zou_wei@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index ffdf7e559515..82a24e330065 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -408,6 +408,7 @@ static const struct of_device_id sti_sas_dev_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, sti_sas_dev_match); static int sti_sas_driver_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 96f685974609d4c315669ef33d55dbc43996491e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 May 2021 18:57:14 +0100 Subject: ASoC: cs53l30: Add missing regmap use_single config This device requires single register transactions, this will definely cause problems with the new device ID parsing which uses regmap_bulk_read but might also show up in the cache sync sometimes. Add the missing flags to the regmap_config. Fixes: 4fc81bc88ad9 ("ASoC: cs53l30: Minor error paths fixups") Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210511175718.15416-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs53l30.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 3d67cbf9eaaa..abe0cc0bc03a 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -912,6 +912,9 @@ static struct regmap_config cs53l30_regmap = { .writeable_reg = cs53l30_writeable_register, .readable_reg = cs53l30_readable_register, .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, }; static int cs53l30_i2c_probe(struct i2c_client *client, -- cgit v1.2.3 From 27fb585169024440c1b358da35499fa578d803cd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 May 2021 18:57:15 +0100 Subject: ASoC: cs42l73: Add missing regmap use_single config This device requires single register transactions, this will definely cause problems with the new device ID parsing which uses regmap_bulk_read but might also show up in the cache sync sometimes. Add the missing flags to the regmap_config. Fixes: 26495252fe0d ("ASoC: cs42l73: Minor error paths fixups") Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210511175718.15416-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index c3f974ec78e5..e92bacaab53f 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1268,6 +1268,9 @@ static const struct regmap_config cs42l73_regmap = { .volatile_reg = cs42l73_volatile_register, .readable_reg = cs42l73_readable_register, .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, }; static int cs42l73_i2c_probe(struct i2c_client *i2c_client, -- cgit v1.2.3 From 2a682f821941e28fb9ceaa1dd03ccfaea0448101 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 May 2021 18:57:16 +0100 Subject: ASoC: cs35l34: Add missing regmap use_single config This device requires single register transactions, this will definely cause problems with the new device ID parsing which uses regmap_bulk_read but might also show up in the cache sync sometimes. Add the missing flags to the regmap_config. Fixes: 8cb9b001635c ("ASoC: cs35l34: Minor error paths fixups") Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210511175718.15416-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 110ee2d06358..3d3c3c34dfe2 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -800,6 +800,9 @@ static struct regmap_config cs35l34_regmap = { .readable_reg = cs35l34_readable_register, .precious_reg = cs35l34_precious_register, .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, }; static int cs35l34_handle_of_data(struct i2c_client *i2c_client, -- cgit v1.2.3 From b1078e9869531af4f968ba1b9edad51264943bb8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 May 2021 18:57:17 +0100 Subject: ASoC: cs35l32: Add missing regmap use_single config This device requires single register transactions, this will definely cause problems with the new device ID parsing which uses regmap_bulk_read but might also show up in the cache sync sometimes. Add the missing flags to the regmap_config. Fixes: 283160f1419d ("ASoC: cs35l32: Minor error paths fixups") Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210511175718.15416-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index f4067230ac42..88e79b9f52ed 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -261,6 +261,9 @@ static const struct regmap_config cs35l32_regmap = { .readable_reg = cs35l32_readable_register, .precious_reg = cs35l32_precious_register, .cache_type = REGCACHE_RBTREE, + + .use_single_read = true, + .use_single_write = true, }; static int cs35l32_handle_of_data(struct i2c_client *i2c_client, -- cgit v1.2.3 From 0e49a4de4564b3659a34b0b775d43b6b635b17fa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 11 May 2021 18:57:18 +0100 Subject: ASoC: cs42l52: Minor tidy up of error paths Fixup a needlessly initialised variable and an unchecked return value. Reported-by: Pierre-Louis Bossart Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210511175718.15416-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index c44a5cdb796e..7cdffdf6b8cf 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1175,7 +1175,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, struct cs42l56_platform_data *pdata = dev_get_platdata(&i2c_client->dev); int ret, i; - unsigned int devid = 0; + unsigned int devid; unsigned int alpha_rev, metal_rev; unsigned int reg; @@ -1245,6 +1245,11 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, } ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); + if (ret) { + dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret); + return ret; + } + devid = reg & CS42L56_CHIP_ID_MASK; if (devid != CS42L56_DEVID) { dev_err(&i2c_client->dev, -- cgit v1.2.3 From 3d681804efcb6e5d8089a433402e19179347d7ae Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 May 2021 15:58:24 +0800 Subject: regulator: cros-ec: Fix error code in dev_err message Show proper error code instead of 0. Signed-off-by: Axel Lin Link: https://lore.kernel.org/r/20210512075824.620580-1-axel.lin@ingics.com Signed-off-by: Mark Brown --- drivers/regulator/cros-ec-regulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c index eb3fc1db4edc..c4754f3cf233 100644 --- a/drivers/regulator/cros-ec-regulator.c +++ b/drivers/regulator/cros-ec-regulator.c @@ -225,8 +225,9 @@ static int cros_ec_regulator_probe(struct platform_device *pdev) drvdata->dev = devm_regulator_register(dev, &drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { + ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - return PTR_ERR(drvdata->dev); + return ret; } platform_set_drvdata(pdev, drvdata); -- cgit v1.2.3 From 7907cad7d07e0055789ec0c534452f19dfe1fc80 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 12 May 2021 17:35:34 +0800 Subject: spi: sprd: Add missing MODULE_DEVICE_TABLE MODULE_DEVICE_TABLE is used to extract the device information out of the driver and builds a table when being compiled. If using this macro, kernel can find the driver if available when the device is plugged in, and then loads that driver and initializes the device. Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20210512093534.243040-1-zhang.lyra@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-sprd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index b41a75749b49..28e70db9bbba 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -1068,6 +1068,7 @@ static const struct of_device_id sprd_spi_of_match[] = { { .compatible = "sprd,sc9860-spi", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, sprd_spi_of_match); static struct platform_driver sprd_spi_driver = { .driver = { -- cgit v1.2.3 From 6b69546912a57ff8c31061f98e56383cc0beffd3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 May 2021 17:09:12 +0300 Subject: spi: Assume GPIO CS active high in ACPI case Currently GPIO CS handling, when descriptors are in use, doesn't take into consideration that in ACPI case the default polarity is Active High and can't be altered. Instead we have to use the per-chip definition provided by SPISerialBus() resource. Fixes: 766c6b63aa04 ("spi: fix client driver breakages when using GPIO descriptors") Cc: Liguang Zhang Cc: Jay Fang Cc: Sven Van Asbroeck Signed-off-by: Andy Shevchenko Tested-by: Xin Hao Link: https://lore.kernel.org/r/20210511140912.30757-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a565e7d6bf3b..98048af04abf 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -820,15 +820,29 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio)) { if (!(spi->mode & SPI_NO_CS)) { - if (spi->cs_gpiod) - /* polarity handled by gpiolib */ - gpiod_set_value_cansleep(spi->cs_gpiod, activate); - else + if (spi->cs_gpiod) { + /* + * Historically ACPI has no means of the GPIO polarity and + * thus the SPISerialBus() resource defines it on the per-chip + * basis. In order to avoid a chain of negations, the GPIO + * polarity is considered being Active High. Even for the cases + * when _DSD() is involved (in the updated versions of ACPI) + * the GPIO CS polarity must be defined Active High to avoid + * ambiguity. That's why we use enable, that takes SPI_CS_HIGH + * into account. + */ + if (has_acpi_companion(&spi->dev)) + gpiod_set_value_cansleep(spi->cs_gpiod, !enable); + else + /* Polarity handled by GPIO library */ + gpiod_set_value_cansleep(spi->cs_gpiod, activate); + } else { /* * invert the enable line, as active low is * default for SPI. */ gpio_set_value_cansleep(spi->cs_gpio, !enable); + } } /* Some SPI masters need both GPIO CS & slave_select */ if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && -- cgit v1.2.3 From f8c8871f5eff3981eeb13421aca2c1cfda4a5204 Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Tue, 11 May 2021 17:13:33 -0400 Subject: regulator: fan53555: fix TCS4525 voltage calulation The TCS4525 has 128 voltage steps. With the calculation set to 127 the most significant bit is disregarded which leads to a miscalculation of the voltage by about 200mv. Fix the calculation to end deadlock on the rk3566-quartz64 which uses this as the cpu regulator. Fixes: 914df8faa7d6 ("regulator: fan53555: Add TCS4525 DCDC support") Signed-off-by: Peter Geis Link: https://lore.kernel.org/r/20210511211335.2935163-2-pgwipeout@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/fan53555.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index f3918f03aaf3..26f06f685b1b 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -55,7 +55,6 @@ #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define FAN53526_NVOLTAGES 128 -#define TCS4525_NVOLTAGES 127 /* Numbers of voltages */ #define TCS_VSEL_NSEL_MASK 0x7f #define TCS_VSEL0_MODE (1 << 7) @@ -376,7 +375,7 @@ static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di) /* Init voltage range and step */ di->vsel_min = 600000; di->vsel_step = 6250; - di->vsel_count = TCS4525_NVOLTAGES; + di->vsel_count = FAN53526_NVOLTAGES; return 0; } -- cgit v1.2.3 From ca0760e7d79e2bb9c342e6b3f925b1ef01c6303e Mon Sep 17 00:00:00 2001 From: Wei Ming Chen Date: Thu, 6 May 2021 20:30:51 +0800 Subject: Compiler Attributes: Add continue in comment Add "continue;" for switch/case block according to Doc[1] [1] https://www.kernel.org/doc/html/latest/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Wei Ming Chen Signed-off-by: Miguel Ojeda --- include/linux/compiler_attributes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h index c043b8d2b17b..183ddd5fd072 100644 --- a/include/linux/compiler_attributes.h +++ b/include/linux/compiler_attributes.h @@ -199,6 +199,7 @@ * must end with any of these keywords: * break; * fallthrough; + * continue; * goto