From: Sasha Levin Date: Fri, 26 Jan 2024 14:04:46 +0000 (-0500) Subject: Fixes for 5.10 X-Git-Tag: v6.1.76~120 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8faade6732d4d39ef8ab74037916343b2fa2aafd;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/dmaengine-fix-null-pointer-in-channel-unregistration.patch b/queue-5.10/dmaengine-fix-null-pointer-in-channel-unregistration.patch new file mode 100644 index 00000000000..3da70de1d6d --- /dev/null +++ b/queue-5.10/dmaengine-fix-null-pointer-in-channel-unregistration.patch @@ -0,0 +1,55 @@ +From 5fe2a657d52838ff9d15c741b90418759c69698a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Dec 2023 17:04:52 +0100 +Subject: dmaengine: fix NULL pointer in channel unregistration function + +From: Amelie Delaunay + +[ Upstream commit f5c24d94512f1b288262beda4d3dcb9629222fc7 ] + +__dma_async_device_channel_register() can fail. In case of failure, +chan->local is freed (with free_percpu()), and chan->local is nullified. +When dma_async_device_unregister() is called (because of managed API or +intentionally by DMA controller driver), channels are unconditionally +unregistered, leading to this NULL pointer: +[ 1.318693] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000d0 +[...] +[ 1.484499] Call trace: +[ 1.486930] device_del+0x40/0x394 +[ 1.490314] device_unregister+0x20/0x7c +[ 1.494220] __dma_async_device_channel_unregister+0x68/0xc0 + +Look at dma_async_device_register() function error path, channel device +unregistration is done only if chan->local is not NULL. + +Then add the same condition at the beginning of +__dma_async_device_channel_unregister() function, to avoid NULL pointer +issue whatever the API used to reach this function. + +Fixes: d2fb0a043838 ("dmaengine: break out channel registration") +Signed-off-by: Amelie Delaunay +Reviewed-by: Dave Jiang +Link: https://lore.kernel.org/r/20231213160452.2598073-1-amelie.delaunay@foss.st.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dmaengine.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index 4ec7bb58c195..9559ebd61f3b 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -1108,6 +1108,9 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_register); + static void __dma_async_device_channel_unregister(struct dma_device *device, + struct dma_chan *chan) + { ++ if (chan->local == NULL) ++ return; ++ + WARN_ONCE(!device->device_release && chan->client_count, + "%s called while %d clients hold a reference\n", + __func__, chan->client_count); +-- +2.43.0 + diff --git a/queue-5.10/iio-adc-ad7091r-allow-users-to-configure-device-even.patch b/queue-5.10/iio-adc-ad7091r-allow-users-to-configure-device-even.patch new file mode 100644 index 00000000000..eb762fac535 --- /dev/null +++ b/queue-5.10/iio-adc-ad7091r-allow-users-to-configure-device-even.patch @@ -0,0 +1,295 @@ +From 6c4a55b6120e770562168020493c34310ded1a9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 17:26:01 -0300 +Subject: iio: adc: ad7091r: Allow users to configure device events + +From: Marcelo Schmitt + +[ Upstream commit 020e71c7ffc25dfe29ed9be6c2d39af7bd7f661f ] + +AD7091R-5 devices are supported by the ad7091r-5 driver together with +the ad7091r-base driver. Those drivers declared iio events for notifying +user space when ADC readings fall bellow the thresholds of low limit +registers or above the values set in high limit registers. +However, to configure iio events and their thresholds, a set of callback +functions must be implemented and those were not present until now. +The consequence of trying to configure ad7091r-5 events without the +proper callback functions was a null pointer dereference in the kernel +because the pointers to the callback functions were not set. + +Implement event configuration callbacks allowing users to read/write +event thresholds and enable/disable event generation. + +Since the event spec structs are generic to AD7091R devices, also move +those from the ad7091r-5 driver the base driver so they can be reused +when support for ad7091r-2/-4/-8 be added. + +Fixes: ca69300173b6 ("iio: adc: Add support for AD7091R5 ADC") +Suggested-by: David Lechner +Signed-off-by: Marcelo Schmitt +Link: https://lore.kernel.org/r/59552d3548dabd56adc3107b7b4869afee2b0c3c.1703013352.git.marcelo.schmitt1@gmail.com +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/adc/ad7091r-base.c | 156 +++++++++++++++++++++++++++++++++ + drivers/iio/adc/ad7091r-base.h | 6 ++ + drivers/iio/adc/ad7091r5.c | 28 +----- + 3 files changed, 166 insertions(+), 24 deletions(-) + +diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c +index ad089c0ff953..9ddda08918db 100644 +--- a/drivers/iio/adc/ad7091r-base.c ++++ b/drivers/iio/adc/ad7091r-base.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -50,6 +51,27 @@ struct ad7091r_state { + struct mutex lock; /*lock to prevent concurent reads */ + }; + ++const struct iio_event_spec ad7091r_events[] = { ++ { ++ .type = IIO_EV_TYPE_THRESH, ++ .dir = IIO_EV_DIR_RISING, ++ .mask_separate = BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_ENABLE), ++ }, ++ { ++ .type = IIO_EV_TYPE_THRESH, ++ .dir = IIO_EV_DIR_FALLING, ++ .mask_separate = BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_ENABLE), ++ }, ++ { ++ .type = IIO_EV_TYPE_THRESH, ++ .dir = IIO_EV_DIR_EITHER, ++ .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), ++ }, ++}; ++EXPORT_SYMBOL_NS_GPL(ad7091r_events, IIO_AD7091R); ++ + static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode) + { + int ret, conf; +@@ -169,8 +191,142 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, + return ret; + } + ++static int ad7091r_read_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir) ++{ ++ struct ad7091r_state *st = iio_priv(indio_dev); ++ int val, ret; ++ ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ ret = regmap_read(st->map, ++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel), ++ &val); ++ if (ret) ++ return ret; ++ return val != AD7091R_HIGH_LIMIT; ++ case IIO_EV_DIR_FALLING: ++ ret = regmap_read(st->map, ++ AD7091R_REG_CH_LOW_LIMIT(chan->channel), ++ &val); ++ if (ret) ++ return ret; ++ return val != AD7091R_LOW_LIMIT; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ad7091r_write_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, int state) ++{ ++ struct ad7091r_state *st = iio_priv(indio_dev); ++ ++ if (state) { ++ return regmap_set_bits(st->map, AD7091R_REG_CONF, ++ AD7091R_REG_CONF_ALERT_EN); ++ } else { ++ /* ++ * Set thresholds either to 0 or to 2^12 - 1 as appropriate to ++ * prevent alerts and thus disable event generation. ++ */ ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ return regmap_write(st->map, ++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel), ++ AD7091R_HIGH_LIMIT); ++ case IIO_EV_DIR_FALLING: ++ return regmap_write(st->map, ++ AD7091R_REG_CH_LOW_LIMIT(chan->channel), ++ AD7091R_LOW_LIMIT); ++ default: ++ return -EINVAL; ++ } ++ } ++} ++ ++static int ad7091r_read_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, int *val, int *val2) ++{ ++ struct ad7091r_state *st = iio_priv(indio_dev); ++ int ret; ++ ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ ret = regmap_read(st->map, ++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel), ++ val); ++ if (ret) ++ return ret; ++ return IIO_VAL_INT; ++ case IIO_EV_DIR_FALLING: ++ ret = regmap_read(st->map, ++ AD7091R_REG_CH_LOW_LIMIT(chan->channel), ++ val); ++ if (ret) ++ return ret; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_INFO_HYSTERESIS: ++ ret = regmap_read(st->map, ++ AD7091R_REG_CH_HYSTERESIS(chan->channel), ++ val); ++ if (ret) ++ return ret; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int ad7091r_write_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, int val, int val2) ++{ ++ struct ad7091r_state *st = iio_priv(indio_dev); ++ ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ return regmap_write(st->map, ++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel), ++ val); ++ case IIO_EV_DIR_FALLING: ++ return regmap_write(st->map, ++ AD7091R_REG_CH_LOW_LIMIT(chan->channel), ++ val); ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_INFO_HYSTERESIS: ++ return regmap_write(st->map, ++ AD7091R_REG_CH_HYSTERESIS(chan->channel), ++ val); ++ default: ++ return -EINVAL; ++ } ++} ++ + static const struct iio_info ad7091r_info = { + .read_raw = ad7091r_read_raw, ++ .read_event_config = &ad7091r_read_event_config, ++ .write_event_config = &ad7091r_write_event_config, ++ .read_event_value = &ad7091r_read_event_value, ++ .write_event_value = &ad7091r_write_event_value, + }; + + static irqreturn_t ad7091r_event_handler(int irq, void *private) +diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h +index 509748aef9b1..7a78976a2f80 100644 +--- a/drivers/iio/adc/ad7091r-base.h ++++ b/drivers/iio/adc/ad7091r-base.h +@@ -8,6 +8,10 @@ + #ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__ + #define __DRIVERS_IIO_ADC_AD7091R_BASE_H__ + ++/* AD7091R_REG_CH_LIMIT */ ++#define AD7091R_HIGH_LIMIT 0xFFF ++#define AD7091R_LOW_LIMIT 0x0 ++ + struct device; + struct ad7091r_state; + +@@ -17,6 +21,8 @@ struct ad7091r_chip_info { + unsigned int vref_mV; + }; + ++extern const struct iio_event_spec ad7091r_events[3]; ++ + extern const struct regmap_config ad7091r_regmap_config; + + int ad7091r_probe(struct device *dev, const char *name, +diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c +index 9665679c3ea6..e60511460786 100644 +--- a/drivers/iio/adc/ad7091r5.c ++++ b/drivers/iio/adc/ad7091r5.c +@@ -12,26 +12,6 @@ + + #include "ad7091r-base.h" + +-static const struct iio_event_spec ad7091r5_events[] = { +- { +- .type = IIO_EV_TYPE_THRESH, +- .dir = IIO_EV_DIR_RISING, +- .mask_separate = BIT(IIO_EV_INFO_VALUE) | +- BIT(IIO_EV_INFO_ENABLE), +- }, +- { +- .type = IIO_EV_TYPE_THRESH, +- .dir = IIO_EV_DIR_FALLING, +- .mask_separate = BIT(IIO_EV_INFO_VALUE) | +- BIT(IIO_EV_INFO_ENABLE), +- }, +- { +- .type = IIO_EV_TYPE_THRESH, +- .dir = IIO_EV_DIR_EITHER, +- .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), +- }, +-}; +- + #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +@@ -44,10 +24,10 @@ static const struct iio_event_spec ad7091r5_events[] = { + .scan_type.realbits = bits, \ + } + static const struct iio_chan_spec ad7091r5_channels_irq[] = { +- AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), +- AD7091R_CHANNEL(1, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), +- AD7091R_CHANNEL(2, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), +- AD7091R_CHANNEL(3, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), ++ AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)), ++ AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)), ++ AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)), ++ AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)), + }; + + static const struct iio_chan_spec ad7091r5_channels_noirq[] = { +-- +2.43.0 + diff --git a/queue-5.10/iio-adc-ad7091r-enable-internal-vref-if-external-vre.patch b/queue-5.10/iio-adc-ad7091r-enable-internal-vref-if-external-vre.patch new file mode 100644 index 00000000000..c901a099c87 --- /dev/null +++ b/queue-5.10/iio-adc-ad7091r-enable-internal-vref-if-external-vre.patch @@ -0,0 +1,67 @@ +From 0c4e0cbd5462851c26964c6515deaa4f12823eea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 17:26:27 -0300 +Subject: iio: adc: ad7091r: Enable internal vref if external vref is not + supplied + +From: Marcelo Schmitt + +[ Upstream commit e71c5c89bcb165a02df35325aa13d1ee40112401 ] + +The ADC needs a voltage reference to work correctly. +Users can provide an external voltage reference or use the chip internal +reference to operate the ADC. +The availability of an in chip reference for the ADC saves the user from +having to supply an external voltage reference, which makes the external +reference an optional property as described in the device tree +documentation. +Though, to use the internal reference, it must be enabled by writing to +the configuration register. +Enable AD7091R internal voltage reference if no external vref is supplied. + +Fixes: 260442cc5be4 ("iio: adc: ad7091r5: Add scale and external VREF support") +Signed-off-by: Marcelo Schmitt +Link: https://lore.kernel.org/r/b865033fa6a4fc4bf2b4a98ec51a6144e0f64f77.1703013352.git.marcelo.schmitt1@gmail.com +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/adc/ad7091r-base.c | 7 +++++++ + drivers/iio/adc/ad7091r-base.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c +index 9ddda08918db..f345542e69a0 100644 +--- a/drivers/iio/adc/ad7091r-base.c ++++ b/drivers/iio/adc/ad7091r-base.c +@@ -405,7 +405,14 @@ int ad7091r_probe(struct device *dev, const char *name, + if (IS_ERR(st->vref)) { + if (PTR_ERR(st->vref) == -EPROBE_DEFER) + return -EPROBE_DEFER; ++ + st->vref = NULL; ++ /* Enable internal vref */ ++ ret = regmap_set_bits(st->map, AD7091R_REG_CONF, ++ AD7091R_REG_CONF_INT_VREF); ++ if (ret) ++ return dev_err_probe(st->dev, ret, ++ "Error on enable internal reference\n"); + } else { + ret = regulator_enable(st->vref); + if (ret) +diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h +index 7a78976a2f80..b9e1c8bf3440 100644 +--- a/drivers/iio/adc/ad7091r-base.h ++++ b/drivers/iio/adc/ad7091r-base.h +@@ -8,6 +8,8 @@ + #ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__ + #define __DRIVERS_IIO_ADC_AD7091R_BASE_H__ + ++#define AD7091R_REG_CONF_INT_VREF BIT(0) ++ + /* AD7091R_REG_CH_LIMIT */ + #define AD7091R_HIGH_LIMIT 0xFFF + #define AD7091R_LOW_LIMIT 0x0 +-- +2.43.0 + diff --git a/queue-5.10/iio-adc-ad7091r-set-alert-bit-in-config-register.patch b/queue-5.10/iio-adc-ad7091r-set-alert-bit-in-config-register.patch new file mode 100644 index 00000000000..f4bae9ef5f0 --- /dev/null +++ b/queue-5.10/iio-adc-ad7091r-set-alert-bit-in-config-register.patch @@ -0,0 +1,53 @@ +From 9b660eb0b6de395facd2eb3e0ff9f734e3d037fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 Dec 2023 14:46:37 -0300 +Subject: iio: adc: ad7091r: Set alert bit in config register + +From: Marcelo Schmitt + +[ Upstream commit 149694f5e79b0c7a36ceb76e7c0d590db8f151c1 ] + +The ad7091r-base driver sets up an interrupt handler for firing events +when inputs are either above or below a certain threshold. +However, for the interrupt signal to come from the device it must be +configured to enable the ALERT/BUSY/GPO pin to be used as ALERT, which +was not being done until now. +Enable interrupt signals on the ALERT/BUSY/GPO pin by setting the proper +bit in the configuration register. + +Signed-off-by: Marcelo Schmitt +Link: https://lore.kernel.org/r/e8da2ee98d6df88318b14baf3dc9630e20218418.1702746240.git.marcelo.schmitt1@gmail.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 020e71c7ffc2 ("iio: adc: ad7091r: Allow users to configure device events") +Signed-off-by: Sasha Levin +--- + drivers/iio/adc/ad7091r-base.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c +index 811f04448d8d..ad089c0ff953 100644 +--- a/drivers/iio/adc/ad7091r-base.c ++++ b/drivers/iio/adc/ad7091r-base.c +@@ -28,6 +28,7 @@ + #define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff) + + /* AD7091R_REG_CONF */ ++#define AD7091R_REG_CONF_ALERT_EN BIT(4) + #define AD7091R_REG_CONF_AUTO BIT(8) + #define AD7091R_REG_CONF_CMD BIT(10) + +@@ -232,6 +233,11 @@ int ad7091r_probe(struct device *dev, const char *name, + iio_dev->channels = chip_info->channels; + + if (irq) { ++ ret = regmap_update_bits(st->map, AD7091R_REG_CONF, ++ AD7091R_REG_CONF_ALERT_EN, BIT(4)); ++ if (ret) ++ return ret; ++ + ret = devm_request_threaded_irq(dev, irq, NULL, + ad7091r_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, iio_dev); +-- +2.43.0 + diff --git a/queue-5.10/pci-mediatek-clear-interrupt-status-before-dispatchi.patch b/queue-5.10/pci-mediatek-clear-interrupt-status-before-dispatchi.patch new file mode 100644 index 00000000000..c5e737dc382 --- /dev/null +++ b/queue-5.10/pci-mediatek-clear-interrupt-status-before-dispatchi.patch @@ -0,0 +1,65 @@ +From 1e8c1ccf867e4ec682f8419b123ba5b8d2db291f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Dec 2023 17:49:23 +0800 +Subject: PCI: mediatek: Clear interrupt status before dispatching handler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: qizhong cheng + +[ Upstream commit 4e11c29873a8a296a20f99b3e03095e65ebf897d ] + +We found a failure when using the iperf tool during WiFi performance +testing, where some MSIs were received while clearing the interrupt +status, and these MSIs cannot be serviced. + +The interrupt status can be cleared even if the MSI status remains pending. +As such, given the edge-triggered interrupt type, its status should be +cleared before being dispatched to the handler of the underling device. + +[kwilczynski: commit log, code comment wording] +Link: https://lore.kernel.org/linux-pci/20231211094923.31967-1-jianjun.wang@mediatek.com +Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") +Signed-off-by: qizhong cheng +Signed-off-by: Jianjun Wang +Signed-off-by: Krzysztof Wilczyński +[bhelgaas: rewrap comment] +Signed-off-by: Bjorn Helgaas +Reviewed-by: AngeloGioacchino Del Regno +Cc: +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c +index 23548b517e4b..ea91d63c8be1 100644 +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -620,14 +620,20 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc) + if (status & MSI_STATUS){ + unsigned long imsi_status; + ++ /* ++ * The interrupt status can be cleared even if the ++ * MSI status remains pending. As such, given the ++ * edge-triggered interrupt type, its status should ++ * be cleared before being dispatched to the ++ * handler of the underlying device. ++ */ ++ writel(MSI_STATUS, port->base + PCIE_INT_STATUS); + while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) { + for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) { + virq = irq_find_mapping(port->inner_domain, bit); + generic_handle_irq(virq); + } + } +- /* Clear MSI interrupt status */ +- writel(MSI_STATUS, port->base + PCIE_INT_STATUS); + } + } + +-- +2.43.0 + diff --git a/queue-5.10/serial-sc16is7xx-add-check-for-unsupported-spi-modes.patch b/queue-5.10/serial-sc16is7xx-add-check-for-unsupported-spi-modes.patch new file mode 100644 index 00000000000..1eeaf623b49 --- /dev/null +++ b/queue-5.10/serial-sc16is7xx-add-check-for-unsupported-spi-modes.patch @@ -0,0 +1,55 @@ +From 89830b9732103c0559741baaebb85f53bf1b0cc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Dec 2023 18:18:09 -0500 +Subject: serial: sc16is7xx: add check for unsupported SPI modes during probe + +From: Hugo Villeneuve + +[ Upstream commit 6d710b769c1f5f0d55c9ad9bb49b7dce009ec103 ] + +The original comment is confusing because it implies that variants other +than the SC16IS762 supports other SPI modes beside SPI_MODE_0. + +Extract from datasheet: + The SC16IS762 differs from the SC16IS752 in that it supports SPI clock + speeds up to 15 Mbit/s instead of the 4 Mbit/s supported by the + SC16IS752... In all other aspects, the SC16IS762 is functionally and + electrically the same as the SC16IS752. + +The same is also true of the SC16IS760 variant versus the SC16IS740 and +SC16IS750 variants. + +For all variants, only SPI mode 0 is supported. + +Change comment and abort probing if the specified SPI mode is not +SPI_MODE_0. + +Fixes: 2c837a8a8f9f ("sc16is7xx: spi interface is added") +Cc: +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231221231823.2327894-3-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/sc16is7xx.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index dfaca09de79b..31e0c5c3ddea 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -1450,7 +1450,10 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) + + /* Setup SPI bus */ + spi->bits_per_word = 8; +- /* only supports mode 0 on SC16IS762 */ ++ /* For all variants, only mode 0 is supported */ ++ if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0) ++ return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n"); ++ + spi->mode = spi->mode ? : SPI_MODE_0; + spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; + ret = spi_setup(spi); +-- +2.43.0 + diff --git a/queue-5.10/serial-sc16is7xx-set-safe-default-spi-clock-frequenc.patch b/queue-5.10/serial-sc16is7xx-set-safe-default-spi-clock-frequenc.patch new file mode 100644 index 00000000000..0916a074787 --- /dev/null +++ b/queue-5.10/serial-sc16is7xx-set-safe-default-spi-clock-frequenc.patch @@ -0,0 +1,50 @@ +From 45d0c9653b8cebf9ba4e690d7ff96168b9d3a7d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Dec 2023 18:18:10 -0500 +Subject: serial: sc16is7xx: set safe default SPI clock frequency + +From: Hugo Villeneuve + +[ Upstream commit 3ef79cd1412236d884ab0c46b4d1921380807b48 ] + +15 MHz is supported only by 76x variants. + +If the SPI clock frequency is not specified, use a safe default clock value +of 4 MHz that is supported by all variants. + +Also use HZ_PER_MHZ macro to improve readability. + +Fixes: 2c837a8a8f9f ("sc16is7xx: spi interface is added") +Cc: +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231221231823.2327894-4-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/sc16is7xx.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index fd9be81bcfd8..dfaca09de79b 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #define SC16IS7XX_NAME "sc16is7xx" +@@ -1451,7 +1452,7 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) + spi->bits_per_word = 8; + /* only supports mode 0 on SC16IS762 */ + spi->mode = spi->mode ? : SPI_MODE_0; +- spi->max_speed_hz = spi->max_speed_hz ? : 15000000; ++ spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ; + ret = spi_setup(spi); + if (ret) + return ret; +-- +2.43.0 + diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 00000000000..4d55e3b2953 --- /dev/null +++ b/queue-5.10/series @@ -0,0 +1,15 @@ +usb-cdns3-fixes-for-sparse-warnings.patch +usb-cdns3-fix-uvc-failure-work-since-sg-support-enab.patch +usb-cdns3-fix-incorrect-calculation-of-ep_buf_size-w.patch +usb-cdns3-fix-iso-transfer-error-when-mult-is-not-ze.patch +usb-cdns3-fix-uvc-fail-when-dma-cross-4k-boundery-si.patch +pci-mediatek-clear-interrupt-status-before-dispatchi.patch +units-change-from-l-to-ul.patch +units-add-the-hz-macros.patch +serial-sc16is7xx-set-safe-default-spi-clock-frequenc.patch +spi-introduce-spi_mode_x_mask-macro.patch +serial-sc16is7xx-add-check-for-unsupported-spi-modes.patch +iio-adc-ad7091r-set-alert-bit-in-config-register.patch +iio-adc-ad7091r-allow-users-to-configure-device-even.patch +iio-adc-ad7091r-enable-internal-vref-if-external-vre.patch +dmaengine-fix-null-pointer-in-channel-unregistration.patch diff --git a/queue-5.10/spi-introduce-spi_mode_x_mask-macro.patch b/queue-5.10/spi-introduce-spi_mode_x_mask-macro.patch new file mode 100644 index 00000000000..69248439d0c --- /dev/null +++ b/queue-5.10/spi-introduce-spi_mode_x_mask-macro.patch @@ -0,0 +1,46 @@ +From 3a309252807fbe50554efe7891c46d550058ff7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Oct 2020 10:57:23 +0100 +Subject: spi: introduce SPI_MODE_X_MASK macro + +From: Oleksij Rempel + +[ Upstream commit 029b42d8519cef70c4fb5fcaccd08f1053ed2bf0 ] + +Provide a macro to filter all SPI_MODE_0,1,2,3 mode in one run. + +The latest SPI framework will parse the devicetree in following call +sequence: of_register_spi_device() -> of_spi_parse_dt() +So, driver do not need to pars the devicetree and will get prepared +flags in the probe. + +On one hand it is good far most drivers. On other hand some drivers need to +filter flags provide by SPI framework and apply know to work flags. This drivers +may use SPI_MODE_X_MASK to filter MODE flags and set own, known flags: + spi->flags &= ~SPI_MODE_X_MASK; + spi->flags |= SPI_MODE_0; + +Signed-off-by: Oleksij Rempel +Link: https://lore.kernel.org/r/20201027095724.18654-2-o.rempel@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 6d710b769c1f ("serial: sc16is7xx: add check for unsupported SPI modes during probe") +Signed-off-by: Sasha Levin +--- + include/linux/spi/spi.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index e1d88630ff24..ab7747549d23 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -171,6 +171,7 @@ struct spi_device { + #define SPI_MODE_1 (0|SPI_CPHA) + #define SPI_MODE_2 (SPI_CPOL|0) + #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) ++#define SPI_MODE_X_MASK (SPI_CPOL|SPI_CPHA) + #define SPI_CS_HIGH 0x04 /* chipselect active high? */ + #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ + #define SPI_3WIRE 0x10 /* SI/SO signals shared */ +-- +2.43.0 + diff --git a/queue-5.10/units-add-the-hz-macros.patch b/queue-5.10/units-add-the-hz-macros.patch new file mode 100644 index 00000000000..5c8b01323dc --- /dev/null +++ b/queue-5.10/units-add-the-hz-macros.patch @@ -0,0 +1,57 @@ +From 619eef7ee7b5c9d9febe20a01842acd2d876d45b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Sep 2021 19:57:48 -0700 +Subject: units: add the HZ macros + +From: Daniel Lezcano + +[ Upstream commit e2c77032fcbe515194107994d12cd72ddb77b022 ] + +The macros for the unit conversion for frequency are duplicated in +different places. + +Provide these macros in the 'units' header, so they can be reused. + +Link: https://lkml.kernel.org/r/20210816114732.1834145-3-daniel.lezcano@linaro.org +Signed-off-by: Daniel Lezcano +Reviewed-by: Christian Eggers +Reviewed-by: Andy Shevchenko +Cc: Chanwoo Choi +Cc: Guenter Roeck +Cc: Jonathan Cameron +Cc: Jonathan Cameron +Cc: Kyungmin Park +Cc: Lars-Peter Clausen +Cc: Lukasz Luba +Cc: Maxime Coquelin +Cc: Miquel Raynal +Cc: MyungJoo Ham +Cc: Peter Meerwald +Cc: "Rafael J. Wysocki" +Cc: Zhang Rui +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: 3ef79cd14122 ("serial: sc16is7xx: set safe default SPI clock frequency") +Signed-off-by: Sasha Levin +--- + include/linux/units.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/include/linux/units.h b/include/linux/units.h +index 62149b5082e1..b61e3f6d5099 100644 +--- a/include/linux/units.h ++++ b/include/linux/units.h +@@ -20,6 +20,10 @@ + #define PICO 1000000000000ULL + #define FEMTO 1000000000000000ULL + ++#define HZ_PER_KHZ 1000UL ++#define KHZ_PER_MHZ 1000UL ++#define HZ_PER_MHZ 1000000UL ++ + #define MILLIWATT_PER_WATT 1000UL + #define MICROWATT_PER_MILLIWATT 1000UL + #define MICROWATT_PER_WATT 1000000UL +-- +2.43.0 + diff --git a/queue-5.10/units-change-from-l-to-ul.patch b/queue-5.10/units-change-from-l-to-ul.patch new file mode 100644 index 00000000000..28f73b7b25b --- /dev/null +++ b/queue-5.10/units-change-from-l-to-ul.patch @@ -0,0 +1,71 @@ +From 30cbe45e8be7b0b52c75e17cb018db67b6010ae8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Sep 2021 19:57:44 -0700 +Subject: units: change from 'L' to 'UL' + +From: Daniel Lezcano + +[ Upstream commit c9221919a2d2df5741ab074dfec5bdfc6f1e043b ] + +Patch series "Add Hz macros", v3. + +There are multiple definitions of the HZ_PER_MHZ or HZ_PER_KHZ in the +different drivers. Instead of duplicating this definition again and +again, add one in the units.h header to be reused in all the place the +redefiniton occurs. + +At the same time, change the type of the Watts, as they can not be +negative. + +This patch (of 10): + +The users of the macros are safe to be assigned with an unsigned instead +of signed as the variables using them are themselves unsigned. + +Link: https://lkml.kernel.org/r/20210816114732.1834145-1-daniel.lezcano@linaro.org +Link: https://lkml.kernel.org/r/20210816114732.1834145-2-daniel.lezcano@linaro.org +Signed-off-by: Daniel Lezcano +Cc: Andy Shevchenko +Cc: Jonathan Cameron +Cc: Christian Eggers +Cc: Lukasz Luba +Cc: MyungJoo Ham +Cc: Kyungmin Park +Cc: Lars-Peter Clausen +Cc: Peter Meerwald +Cc: Zhang Rui +Cc: Guenter Roeck +Cc: Miquel Raynal +Cc: Maxime Coquelin +Cc: "Rafael J. Wysocki" +Cc: Daniel Lezcano +Cc: Chanwoo Choi +Cc: Jonathan Cameron +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: 3ef79cd14122 ("serial: sc16is7xx: set safe default SPI clock frequency") +Signed-off-by: Sasha Levin +--- + include/linux/units.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/linux/units.h b/include/linux/units.h +index 3457179f7116..62149b5082e1 100644 +--- a/include/linux/units.h ++++ b/include/linux/units.h +@@ -20,9 +20,9 @@ + #define PICO 1000000000000ULL + #define FEMTO 1000000000000000ULL + +-#define MILLIWATT_PER_WATT 1000L +-#define MICROWATT_PER_MILLIWATT 1000L +-#define MICROWATT_PER_WATT 1000000L ++#define MILLIWATT_PER_WATT 1000UL ++#define MICROWATT_PER_MILLIWATT 1000UL ++#define MICROWATT_PER_WATT 1000000UL + + #define ABSOLUTE_ZERO_MILLICELSIUS -273150 + +-- +2.43.0 + diff --git a/queue-5.10/usb-cdns3-fix-incorrect-calculation-of-ep_buf_size-w.patch b/queue-5.10/usb-cdns3-fix-incorrect-calculation-of-ep_buf_size-w.patch new file mode 100644 index 00000000000..ff92ebcee14 --- /dev/null +++ b/queue-5.10/usb-cdns3-fix-incorrect-calculation-of-ep_buf_size-w.patch @@ -0,0 +1,55 @@ +From aead52baf21e5a4b42540c9de395cb055f177f97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Jul 2023 19:00:15 -0400 +Subject: usb: cdns3: fix incorrect calculation of ep_buf_size when more than + one config + +From: Frank Li + +[ Upstream commit 2627335a1329a0d39d8d277994678571c4f21800 ] + +Previously, the cdns3_gadget_check_config() function in the cdns3 driver +mistakenly calculated the ep_buf_size by considering only one +configuration's endpoint information because "claimed" will be clear after +call usb_gadget_check_config(). + +The fix involves checking the private flags EP_CLAIMED instead of relying +on the "claimed" flag. + +Fixes: dce49449e04f ("usb: cdns3: allocate TX FIFO size according to composite EP number") +Cc: stable +Reported-by: Ravi Gunasekaran +Signed-off-by: Frank Li +Acked-by: Peter Chen +Tested-by: Ravi Gunasekaran +Link: https://lore.kernel.org/r/20230707230015.494999-2-Frank.Li@nxp.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 92f02efa1d86 ("usb: cdns3: fix iso transfer error when mult is not zero") +Signed-off-by: Sasha Levin +--- + drivers/usb/cdns3/gadget.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c +index 575180a59ad4..ee64c4ab8dd2 100644 +--- a/drivers/usb/cdns3/gadget.c ++++ b/drivers/usb/cdns3/gadget.c +@@ -3030,12 +3030,14 @@ static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) + static int cdns3_gadget_check_config(struct usb_gadget *gadget) + { + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); ++ struct cdns3_endpoint *priv_ep; + struct usb_ep *ep; + int n_in = 0; + int total; + + list_for_each_entry(ep, &gadget->ep_list, ep_list) { +- if (ep->claimed && (ep->address & USB_DIR_IN)) ++ priv_ep = ep_to_cdns3_ep(ep); ++ if ((priv_ep->flags & EP_CLAIMED) && (ep->address & USB_DIR_IN)) + n_in++; + } + +-- +2.43.0 + diff --git a/queue-5.10/usb-cdns3-fix-iso-transfer-error-when-mult-is-not-ze.patch b/queue-5.10/usb-cdns3-fix-iso-transfer-error-when-mult-is-not-ze.patch new file mode 100644 index 00000000000..bf4b68e70ef --- /dev/null +++ b/queue-5.10/usb-cdns3-fix-iso-transfer-error-when-mult-is-not-ze.patch @@ -0,0 +1,180 @@ +From e23d833d5044217a5b2f6b2ca936279619fda4ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 Dec 2023 10:38:14 -0500 +Subject: usb: cdns3: fix iso transfer error when mult is not zero + +From: Frank Li + +[ Upstream commit 92f02efa1d86d7dcaef7f38a5fe3396c4e88a93c ] + +ISO basic transfer is + ITP(SOF) Package_0 Package_1 ... Package_n + +CDNS3 DMA start dma transfer from memmory to internal FIFO when get SOF, +controller will transfer data to usb bus from internal FIFO when get IN +token. + +According USB spec defination: + Maximum number of packets = (bMaxBurst + 1) * (Mult + 1) + +Internal memory should be the same as (bMaxBurst + 1) * (Mult + 1). DMA +don't fetch data advance when ISO transfer, so only reserve +(bMaxBurst + 1) * (Mult + 1) internal memory for ISO transfer. + +Need save Mult and bMaxBurst information and set it into EP_CFG register, +otherwise only 1 package is sent by controller, other package will be +lost. + +Cc: +Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231224153816.1664687-3-Frank.Li@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/cdns3/gadget.c | 59 +++++++++++++++++++++++--------------- + drivers/usb/cdns3/gadget.h | 3 ++ + 2 files changed, 39 insertions(+), 23 deletions(-) + +diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c +index ee64c4ab8dd2..118c9402bb60 100644 +--- a/drivers/usb/cdns3/gadget.c ++++ b/drivers/usb/cdns3/gadget.c +@@ -2063,11 +2063,10 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) + bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + u32 bEndpointAddress = priv_ep->num | priv_ep->dir; +- u32 max_packet_size = 0; +- u8 maxburst = 0; ++ u32 max_packet_size = priv_ep->wMaxPacketSize; ++ u8 maxburst = priv_ep->bMaxBurst; + u32 ep_cfg = 0; + u8 buffering; +- u8 mult = 0; + int ret; + + buffering = priv_dev->ep_buf_size - 1; +@@ -2089,8 +2088,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) + break; + default: + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC); +- mult = priv_dev->ep_iso_burst - 1; +- buffering = mult + 1; ++ buffering = (priv_ep->bMaxBurst + 1) * (priv_ep->mult + 1) - 1; + } + + switch (priv_dev->gadget.speed) { +@@ -2101,17 +2099,8 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) + max_packet_size = is_iso_ep ? 1024 : 512; + break; + case USB_SPEED_SUPER: +- /* It's limitation that driver assumes in driver. */ +- mult = 0; +- max_packet_size = 1024; +- if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) { +- maxburst = priv_dev->ep_iso_burst - 1; +- buffering = (mult + 1) * +- (maxburst + 1); +- +- if (priv_ep->interval > 1) +- buffering++; +- } else { ++ if (priv_ep->type != USB_ENDPOINT_XFER_ISOC) { ++ max_packet_size = 1024; + maxburst = priv_dev->ep_buf_size - 1; + } + break; +@@ -2140,7 +2129,6 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) + if (priv_dev->dev_ver < DEV_VER_V2) + priv_ep->trb_burst_size = 16; + +- mult = min_t(u8, mult, EP_CFG_MULT_MAX); + buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX); + maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX); + +@@ -2174,7 +2162,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) + } + + ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | +- EP_CFG_MULT(mult) | ++ EP_CFG_MULT(priv_ep->mult) | /* must match EP setting */ + EP_CFG_BUFFERING(buffering) | + EP_CFG_MAXBURST(maxburst); + +@@ -2264,6 +2252,13 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + priv_ep->type = usb_endpoint_type(desc); + priv_ep->flags |= EP_CLAIMED; + priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0; ++ priv_ep->wMaxPacketSize = usb_endpoint_maxp(desc); ++ priv_ep->mult = USB_EP_MAXP_MULT(priv_ep->wMaxPacketSize); ++ priv_ep->wMaxPacketSize &= USB_ENDPOINT_MAXP_MASK; ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && comp_desc) { ++ priv_ep->mult = USB_SS_MULT(comp_desc->bmAttributes) - 1; ++ priv_ep->bMaxBurst = comp_desc->bMaxBurst; ++ } + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return &priv_ep->endpoint; +@@ -3033,22 +3028,40 @@ static int cdns3_gadget_check_config(struct usb_gadget *gadget) + struct cdns3_endpoint *priv_ep; + struct usb_ep *ep; + int n_in = 0; ++ int iso = 0; ++ int out = 1; + int total; ++ int n; + + list_for_each_entry(ep, &gadget->ep_list, ep_list) { + priv_ep = ep_to_cdns3_ep(ep); +- if ((priv_ep->flags & EP_CLAIMED) && (ep->address & USB_DIR_IN)) +- n_in++; ++ if (!(priv_ep->flags & EP_CLAIMED)) ++ continue; ++ ++ n = (priv_ep->mult + 1) * (priv_ep->bMaxBurst + 1); ++ if (ep->address & USB_DIR_IN) { ++ /* ++ * ISO transfer: DMA start move data when get ISO, only transfer ++ * data as min(TD size, iso). No benefit for allocate bigger ++ * internal memory than 'iso'. ++ */ ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) ++ iso += n; ++ else ++ n_in++; ++ } else { ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) ++ out = max_t(int, out, n); ++ } + } + + /* 2KB are reserved for EP0, 1KB for out*/ +- total = 2 + n_in + 1; ++ total = 2 + n_in + out + iso; + + if (total > priv_dev->onchip_buffers) + return -ENOMEM; + +- priv_dev->ep_buf_size = priv_dev->ep_iso_burst = +- (priv_dev->onchip_buffers - 2) / (n_in + 1); ++ priv_dev->ep_buf_size = (priv_dev->onchip_buffers - 2 - iso) / (n_in + out); + + return 0; + } +diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h +index 32825477edd3..aeb2211228c1 100644 +--- a/drivers/usb/cdns3/gadget.h ++++ b/drivers/usb/cdns3/gadget.h +@@ -1167,6 +1167,9 @@ struct cdns3_endpoint { + u8 dir; + u8 num; + u8 type; ++ u8 mult; ++ u8 bMaxBurst; ++ u16 wMaxPacketSize; + int interval; + + int free_trbs; +-- +2.43.0 + diff --git a/queue-5.10/usb-cdns3-fix-uvc-fail-when-dma-cross-4k-boundery-si.patch b/queue-5.10/usb-cdns3-fix-uvc-fail-when-dma-cross-4k-boundery-si.patch new file mode 100644 index 00000000000..d1dd19bf202 --- /dev/null +++ b/queue-5.10/usb-cdns3-fix-uvc-fail-when-dma-cross-4k-boundery-si.patch @@ -0,0 +1,91 @@ +From 05aad0082bf48fcac8be321c53eb97c3815ad73b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 Dec 2023 10:38:15 -0500 +Subject: usb: cdns3: Fix uvc fail when DMA cross 4k boundery since sg enabled + +From: Frank Li + +[ Upstream commit 40c304109e866a7dc123661a5c8ca72f6b5e14e0 ] + +Supposed DMA cross 4k bounder problem should be fixed at DEV_VER_V2, but +still met problem when do ISO transfer if sg enabled. + +Data pattern likes below when sg enabled, package size is 1k and mult is 2 + [UVC Header(8B) ] [data(3k - 8)] ... + +The received data at offset 0xd000 will get 0xc000 data, len 0x70. Error +happen position as below pattern: + 0xd000: wrong + 0xe000: wrong + 0xf000: correct + 0x10000: wrong + 0x11000: wrong + 0x12000: correct + ... + +To avoid DMA cross 4k bounder at ISO transfer, reduce burst len according +to start DMA address's alignment. + +Cc: +Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231224153816.1664687-4-Frank.Li@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/cdns3/gadget.c | 32 +++++++++++++++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c +index 118c9402bb60..8a1f0a636848 100644 +--- a/drivers/usb/cdns3/gadget.c ++++ b/drivers/usb/cdns3/gadget.c +@@ -1119,6 +1119,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + u32 togle_pcs = 1; + int sg_iter = 0; + int num_trb_req; ++ int trb_burst; + int num_trb; + int address; + u32 control; +@@ -1241,7 +1242,36 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + total_tdl += DIV_ROUND_UP(length, + priv_ep->endpoint.maxpacket); + +- trb->length |= cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) | ++ trb_burst = priv_ep->trb_burst_size; ++ ++ /* ++ * Supposed DMA cross 4k bounder problem should be fixed at DEV_VER_V2, but still ++ * met problem when do ISO transfer if sg enabled. ++ * ++ * Data pattern likes below when sg enabled, package size is 1k and mult is 2 ++ * [UVC Header(8B) ] [data(3k - 8)] ... ++ * ++ * The received data at offset 0xd000 will get 0xc000 data, len 0x70. Error happen ++ * as below pattern: ++ * 0xd000: wrong ++ * 0xe000: wrong ++ * 0xf000: correct ++ * 0x10000: wrong ++ * 0x11000: wrong ++ * 0x12000: correct ++ * ... ++ * ++ * But it is still unclear about why error have not happen below 0xd000, it should ++ * cross 4k bounder. But anyway, the below code can fix this problem. ++ * ++ * To avoid DMA cross 4k bounder at ISO transfer, reduce burst len according to 16. ++ */ ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_dev->dev_ver <= DEV_VER_V2) ++ if (ALIGN_DOWN(trb->buffer, SZ_4K) != ++ ALIGN_DOWN(trb->buffer + length, SZ_4K)) ++ trb_burst = 16; ++ ++ trb->length |= cpu_to_le32(TRB_BURST_LEN(trb_burst) | + TRB_LEN(length)); + pcs = priv_ep->pcs ? TRB_CYCLE : 0; + +-- +2.43.0 + diff --git a/queue-5.10/usb-cdns3-fix-uvc-failure-work-since-sg-support-enab.patch b/queue-5.10/usb-cdns3-fix-uvc-failure-work-since-sg-support-enab.patch new file mode 100644 index 00000000000..a44a01d338b --- /dev/null +++ b/queue-5.10/usb-cdns3-fix-uvc-failure-work-since-sg-support-enab.patch @@ -0,0 +1,159 @@ +From a333a132b7738e81197e1a6a82b54b832bed1590 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 Dec 2023 10:38:13 -0500 +Subject: usb: cdns3: fix uvc failure work since sg support enabled + +From: Frank Li + +[ Upstream commit 1b8be5ecff26201bafb0a554c74e91571299fb94 ] + +When IP version >= DEV_VER_V2, gadget:sg_supported is true. So uvc gadget +function driver will use sg to equeue data, first is 8bytes header, the +second is 1016bytes data. + + cdns3_prepare_trb: ep2in: trb 0000000000ac755f, dma buf: 0xbf455000, size: 8, burst: 128 ctrl: 0x00000415 (C=1, T=0, ISP, CHAIN, Normal) + cdns3_prepare_trb: ep2in: trb 00000000a574e693, dma buf: 0xc0200fe0, size: 1016, burst: 128 ctrl: 0x00000405 (C=1, T=0, ISP, Normal) + +But cdns3_ep_run_transfer() can't correctly handle this case, which only +support one TRB for ISO transfer. + +The controller requires duplicate the TD for each SOF if priv_ep->interval +is not 1. DMA will read data from DDR to internal FIFO when get SOF. Send +data to bus when receive IN token. DMA always refill FIFO when get SOF +regardless host send IN token or not. If host send IN token later, some +frames data will be lost. + +Fixed it by below major steps: + +1. Calculate numembers of TRB base on sg_nums and priv_ep->interval. +2. Remove CHAIN flags for each end TRB of TD when duplicate TD. +3. The controller requires LINK TRB must be first TRB of TD. When check +there are not enough TRBs lefts, just fill LINK TRB for left TRBs. + +.... CHAIN_TRB DATA_TRB, CHAIN_TRB DATA_TRB, LINK_TRB ... LINK_TRB + ^End of TRB List + +Cc: +Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231224153816.1664687-2-Frank.Li@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/cdns3/gadget.c | 51 ++++++++++++++++++++++++++++++-------- + 1 file changed, 40 insertions(+), 11 deletions(-) + +diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c +index 82b6fd2bc890..575180a59ad4 100644 +--- a/drivers/usb/cdns3/gadget.c ++++ b/drivers/usb/cdns3/gadget.c +@@ -1118,6 +1118,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + dma_addr_t trb_dma; + u32 togle_pcs = 1; + int sg_iter = 0; ++ int num_trb_req; + int num_trb; + int address; + u32 control; +@@ -1126,15 +1127,13 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + struct scatterlist *s = NULL; + bool sg_supported = !!(request->num_mapped_sgs); + ++ num_trb_req = sg_supported ? request->num_mapped_sgs : 1; ++ ++ /* ISO transfer require each SOF have a TD, each TD include some TRBs */ + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) +- num_trb = priv_ep->interval; ++ num_trb = priv_ep->interval * num_trb_req; + else +- num_trb = sg_supported ? request->num_mapped_sgs : 1; +- +- if (num_trb > priv_ep->free_trbs) { +- priv_ep->flags |= EP_RING_FULL; +- return -ENOBUFS; +- } ++ num_trb = num_trb_req; + + priv_req = to_cdns3_request(request); + address = priv_ep->endpoint.desc->bEndpointAddress; +@@ -1183,14 +1182,31 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + + link_trb->control = cpu_to_le32(((priv_ep->pcs) ? TRB_CYCLE : 0) | + TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit); ++ ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) { ++ /* ++ * ISO require LINK TRB must be first one of TD. ++ * Fill LINK TRBs for left trb space to simply software process logic. ++ */ ++ while (priv_ep->enqueue) { ++ *trb = *link_trb; ++ trace_cdns3_prepare_trb(priv_ep, trb); ++ ++ cdns3_ep_inc_enq(priv_ep); ++ trb = priv_ep->trb_pool + priv_ep->enqueue; ++ priv_req->trb = trb; ++ } ++ } ++ } ++ ++ if (num_trb > priv_ep->free_trbs) { ++ priv_ep->flags |= EP_RING_FULL; ++ return -ENOBUFS; + } + + if (priv_dev->dev_ver <= DEV_VER_V2) + togle_pcs = cdns3_wa1_update_guard(priv_ep, trb); + +- if (sg_supported) +- s = request->sg; +- + /* set incorrect Cycle Bit for first trb*/ + control = priv_ep->pcs ? 0 : TRB_CYCLE; + trb->length = 0; +@@ -1208,6 +1224,9 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + do { + u32 length; + ++ if (!(sg_iter % num_trb_req) && sg_supported) ++ s = request->sg; ++ + /* fill TRB */ + control |= TRB_TYPE(TRB_NORMAL); + if (sg_supported) { +@@ -1249,7 +1268,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + if (sg_supported) { + trb->control |= cpu_to_le32(TRB_ISP); + /* Don't set chain bit for last TRB */ +- if (sg_iter < num_trb - 1) ++ if ((sg_iter % num_trb_req) < num_trb_req - 1) + trb->control |= cpu_to_le32(TRB_CHAIN); + + s = sg_next(s); +@@ -1507,6 +1526,12 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, + + /* The TRB was changed as link TRB, and the request was handled at ep_dequeue */ + while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) { ++ ++ /* ISO ep_traddr may stop at LINK TRB */ ++ if (priv_ep->dequeue == cdns3_get_dma_pos(priv_dev, priv_ep) && ++ priv_ep->type == USB_ENDPOINT_XFER_ISOC) ++ break; ++ + trace_cdns3_complete_trb(priv_ep, trb); + cdns3_ep_inc_deq(priv_ep); + trb = priv_ep->trb_pool + priv_ep->dequeue; +@@ -1539,6 +1564,10 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, + } + + if (request_handled) { ++ /* TRBs are duplicated by priv_ep->interval time for ISO IN */ ++ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_ep->dir) ++ request->actual /= priv_ep->interval; ++ + cdns3_gadget_giveback(priv_ep, priv_req, 0); + request_handled = false; + transfer_end = false; +-- +2.43.0 + diff --git a/queue-5.10/usb-cdns3-fixes-for-sparse-warnings.patch b/queue-5.10/usb-cdns3-fixes-for-sparse-warnings.patch new file mode 100644 index 00000000000..ca7a39fe88f --- /dev/null +++ b/queue-5.10/usb-cdns3-fixes-for-sparse-warnings.patch @@ -0,0 +1,85 @@ +From 2bd3a8a5cfa4b169ccf0085b39c468668cc18892 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Dec 2020 12:04:33 +0100 +Subject: usb: cdns3: Fixes for sparse warnings + +From: Pawel Laszczak + +[ Upstream commit fba8701baed76eac00b84b59f09f6a077f24c534 ] + +Patch fixes the following warnings: +cdns3-gadget.c:1203: sparse: warning: incorrect type + in assignment (different base types) +cdns3-gadget.c:1203: sparse: expected restricted __le32 [usertype] length +cdns3-gadget.c:1203: sparse: got unsigned long +cdns3-gadget.c:1250: sparse: warning: invalid assignment: |= +cdns3-gadget.c:1250: sparse: left side has type restricted __le32 +cdns3-gadget.c:1250: sparse: right side has type unsigned long +cdns3-gadget.c:1253: sparse: warning: invalid assignment: |= +cdns3-gadget.c:1253: sparse: left side has type restricted __le32 +cdns3-gadget.c:1253: sparse: right side has type unsigned long +cdns3-ep0.c:367: sparse: warning: restricted __le16 degrades to integer +cdns3-ep0.c:792: sparse: warning: symbol 'cdns3_gadget_ep0_ops' was not + declared. Should it be static? + +Reported-by: kernel test robot +Signed-off-by: Pawel Laszczak +Signed-off-by: Peter Chen +Stable-dep-of: 1b8be5ecff26 ("usb: cdns3: fix uvc failure work since sg support enabled") +Signed-off-by: Sasha Levin +--- + drivers/usb/cdns3/ep0.c | 4 ++-- + drivers/usb/cdns3/gadget.c | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c +index 30d3516c7f98..4241c513b9f6 100644 +--- a/drivers/usb/cdns3/ep0.c ++++ b/drivers/usb/cdns3/ep0.c +@@ -364,7 +364,7 @@ static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev, + if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT) + return -EINVAL; + +- if (!(ctrl->wIndex & ~USB_DIR_IN)) ++ if (!(le16_to_cpu(ctrl->wIndex) & ~USB_DIR_IN)) + return 0; + + index = cdns3_ep_addr_to_index(le16_to_cpu(ctrl->wIndex)); +@@ -790,7 +790,7 @@ int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) + return 0; + } + +-const struct usb_ep_ops cdns3_gadget_ep0_ops = { ++static const struct usb_ep_ops cdns3_gadget_ep0_ops = { + .enable = cdns3_gadget_ep0_enable, + .disable = cdns3_gadget_ep0_disable, + .alloc_request = cdns3_gadget_ep_alloc_request, +diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c +index 210c1d615082..82b6fd2bc890 100644 +--- a/drivers/usb/cdns3/gadget.c ++++ b/drivers/usb/cdns3/gadget.c +@@ -1200,7 +1200,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + td_size = DIV_ROUND_UP(request->length, + priv_ep->endpoint.maxpacket); + if (priv_dev->gadget.speed == USB_SPEED_SUPER) +- trb->length = TRB_TDL_SS_SIZE(td_size); ++ trb->length = cpu_to_le32(TRB_TDL_SS_SIZE(td_size)); + else + control |= TRB_TDL_HS_SIZE(td_size); + } +@@ -1247,10 +1247,10 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + priv_req->trb->control = cpu_to_le32(control); + + if (sg_supported) { +- trb->control |= TRB_ISP; ++ trb->control |= cpu_to_le32(TRB_ISP); + /* Don't set chain bit for last TRB */ + if (sg_iter < num_trb - 1) +- trb->control |= TRB_CHAIN; ++ trb->control |= cpu_to_le32(TRB_CHAIN); + + s = sg_next(s); + } +-- +2.43.0 +