Hello ,
My name is Mr. Phillip Davies, representing Ledcor Group.
I came across your website and was impressed by the quality of the products you offer, which we believe could meet the needs of our customers.
We would like to inquire if your company is able to export to Europe and the United States (US).
We look forward to your response.
Best regards,
Mr. Phillip Davies
Ledcor Group
Data read from a DbC device may be corrupted due to a race between
ongoing write and write request completion handler both queuing new
transfer blocks (TRBs) if there are remining data in the kfifo.
TRBs may be in incorrct order compared to the data in the kfifo.
Driver fails to keep lock between reading data from kfifo into a
dbc request buffer, and queuing the request to the transfer ring.
This allows completed request to re-queue itself in the middle of
an ongoing transfer loop, forcing itself between a kfifo read and
request TRB write of another request
cpu0 cpu1 (re-queue completed req2)
lock(port_lock)
dbc_start_tx()
kfifo_out(fifo, req1->buffer)
unlock(port_lock)
lock(port_lock)
dbc_write_complete(req2)
dbc_start_tx()
kfifo_out(fifo, req2->buffer)
unlock(port_lock)
lock(port_lock)
req2->trb = ring->enqueue;
ring->enqueue++
unlock(port_lock)
lock(port_lock)
req1->trb = ring->enqueue;
ring->enqueue++
unlock(port_lock)
In the above scenario a kfifo containing "12345678" would read "1234" to
req1 and "5678" to req2, but req2 is queued before req1 leading to
data being transmitted as "56781234"
Solve this by adding a flag that prevents starting a new tx if we
are already mid dbc_start_tx() during the unlocked part.
The already running dbc_do_start_tx() will make sure the newly completed
request gets re-queued as it is added to the request write_pool while
holding the lock.
Cc: stable(a)vger.kernel.org
Fixes: dfba2174dc42 ("usb: xhci: Add DbC support in xHCI driver")
Tested-by: Łukasz Bartosik <ukaszb(a)chromium.org>
Signed-off-by: Mathias Nyman <mathias.nyman(a)linux.intel.com>
---
drivers/usb/host/xhci-dbgcap.h | 1 +
drivers/usb/host/xhci-dbgtty.c | 17 ++++++++++++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 47ac72c2286d..5426c971d2d3 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -114,6 +114,7 @@ struct dbc_port {
unsigned int tx_boundary;
bool registered;
+ bool tx_running;
};
struct dbc_driver {
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index d894081d8d15..b7f95565524d 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -47,7 +47,7 @@ dbc_kfifo_to_req(struct dbc_port *port, char *packet)
return len;
}
-static int dbc_start_tx(struct dbc_port *port)
+static int dbc_do_start_tx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
{
@@ -57,6 +57,8 @@ static int dbc_start_tx(struct dbc_port *port)
bool do_tty_wake = false;
struct list_head *pool = &port->write_pool;
+ port->tx_running = true;
+
while (!list_empty(pool)) {
req = list_entry(pool->next, struct dbc_request, list_pool);
len = dbc_kfifo_to_req(port, req->buf);
@@ -77,12 +79,25 @@ static int dbc_start_tx(struct dbc_port *port)
}
}
+ port->tx_running = false;
+
if (do_tty_wake && port->port.tty)
tty_wakeup(port->port.tty);
return status;
}
+/* must be called with port->port_lock held */
+static int dbc_start_tx(struct dbc_port *port)
+{
+ lockdep_assert_held(&port->port_lock);
+
+ if (port->tx_running)
+ return -EBUSY;
+
+ return dbc_do_start_tx(port);
+}
+
static void dbc_start_rx(struct dbc_port *port)
__releases(&port->port_lock)
__acquires(&port->port_lock)
--
2.43.0
A usb device caught behind a link in ss.Inactive error state needs to
be reset to recover. A VDEV_PORT_ERROR flag is used to track this state,
preventing new transfers from being queued until error is cleared.
This flag may be left uncleared if link goes to error state between two
resets, and print the following message:
"xhci_hcd 0000:00:14.0: Can't queue urb, port error, link inactive"
Fix setting and clearing the flag.
The flag is cleared after hub driver has successfully reset the device
when hcd->reset_device is called. xhci-hcd issues an internal "reset
device" command in this callback, and clear all flags once the command
completes successfully.
This command may complete with a context state error if slot was recently
reset and is already in the defauilt state. This is treated as a success
but flag was left uncleared.
The link state field is also unreliable if port is currently in reset,
so don't set the flag in active reset cases.
Also clear the flag immediately when link is no longer in ss.Inactive
state and port event handler detects a completed reset.
This issue was discovered while debugging kernel bugzilla issue 220491.
It is likely one small part of the problem, causing some of the failures,
but root cause remains unknown
Link: https://bugzilla.kernel.org/show_bug.cgi?id=220491
Fixes: b8c3b718087b ("usb: xhci: Don't try to recover an endpoint if port is in error state.")
Cc: stable(a)vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman(a)linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 15 ++++++++++-----
drivers/usb/host/xhci.c | 1 +
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 8e209aa33ea7..5bdcf9ab2b99 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1985,6 +1985,7 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
{
+ struct xhci_virt_device *vdev = NULL;
struct usb_hcd *hcd;
u32 port_id;
u32 portsc, cmd_reg;
@@ -2016,6 +2017,9 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
goto cleanup;
}
+ if (port->slot_id)
+ vdev = xhci->devs[port->slot_id];
+
/* We might get interrupts after shared_hcd is removed */
if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
@@ -2038,10 +2042,11 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
usb_hcd_resume_root_hub(hcd);
}
- if (hcd->speed >= HCD_USB3 &&
- (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
- if (port->slot_id && xhci->devs[port->slot_id])
- xhci->devs[port->slot_id]->flags |= VDEV_PORT_ERROR;
+ if (vdev && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
+ if (!(portsc & PORT_RESET))
+ vdev->flags |= VDEV_PORT_ERROR;
+ } else if (vdev && portsc & PORT_RC) {
+ vdev->flags &= ~VDEV_PORT_ERROR;
}
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
@@ -2099,7 +2104,7 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
* so the roothub behavior is consistent with external
* USB 3.0 hub behavior.
*/
- if (port->slot_id && xhci->devs[port->slot_id])
+ if (vdev)
xhci_ring_device(xhci, port->slot_id);
if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0cb45b95e4f5..a148a1280126 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4007,6 +4007,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
xhci_get_slot_state(xhci, virt_dev->out_ctx));
xhci_dbg(xhci, "Not freeing device rings.\n");
/* Don't treat this as an error. May change my mind later. */
+ virt_dev->flags = 0;
ret = 0;
goto command_cleanup;
case COMP_SUCCESS:
--
2.43.0
If the IMX media pipeline is configured to receive multiple video
inputs, the second input stream may be broken on start. This happens if
the IMX CSI hardware has to be reconfigured for the second stream, while
the first stream is already running.
The IMX CSI driver configures the IMX CSI in the link_validate callback.
The media pipeline is only validated on the first start. Thus, any later
start of the media pipeline skips the validation and directly starts
streaming. This may leave the hardware in an inconsistent state compared
to the driver configuration. Moving the hardware configuration to the
stream start to make sure that the hardware is configured correctly.
Patch 1 removes the caching of the upstream mbus_config in
csi_link_validate and explicitly request the mbus_config in csi_start,
to get rid of this implicit dependency.
Patch 2 actually moves the hardware register setting from
csi_link_validate to csi_start to fix the skipped hardware
reconfiguration.
Signed-off-by: Michael Tretter <michael.tretter(a)pengutronix.de>
---
Changes in v2:
- Document changed locking in commit message
- Link to v1: https://lore.kernel.org/r/20251105-media-imx-fixes-v1-0-99e48b4f5cbc@pengut…
---
Michael Tretter (2):
media: staging: imx: request mbus_config in csi_start
media: staging: imx: configure src_mux in csi_start
drivers/staging/media/imx/imx-media-csi.c | 84 ++++++++++++++++++-------------
1 file changed, 48 insertions(+), 36 deletions(-)
---
base-commit: 27afd6e066cfd80ddbe22a4a11b99174ac89cced
change-id: 20251105-media-imx-fixes-acef77c7ba12
Best regards,
--
Michael Tretter <m.tretter(a)pengutronix.de>
This patch series fixes delayed hw_error handling during SSR.
Patch 1 adds a wakeup to ensure hw_error is processed promptly after coredump collection.
Patch 2 corrects the timeout unit from jiffies to ms.
Changes v3:
- patch2 add Fixes tag
- Link to v2
https://lore.kernel.org/all/20251106140103.1406081-1-quic_shuaz@quicinc.com/
Changes v2:
- Split timeout conversion into a separate patch.
- Clarified commit messages and added test case description.
- Link to v1
https://lore.kernel.org/all/20251104112601.2670019-1-quic_shuaz@quicinc.com/
Shuai Zhang (2):
Bluetooth: qca: Fix delayed hw_error handling due to missing wakeup
during SSR
Bluetooth: hci_qca: Convert timeout from jiffies to ms
drivers/bluetooth/hci_qca.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--
2.34.1
From: Chuck Lever <chuck.lever(a)oracle.com>
Mike noted that when NFSD responds to an NFS_FILE_SYNC WRITE, it
does not also persist file time stamps. To wit, Section 18.32.3
of RFC 8881 mandates:
> The client specifies with the stable parameter the method of how
> the data is to be processed by the server. If stable is
> FILE_SYNC4, the server MUST commit the data written plus all file
> system metadata to stable storage before returning results. This
> corresponds to the NFSv2 protocol semantics. Any other behavior
> constitutes a protocol violation. If stable is DATA_SYNC4, then
> the server MUST commit all of the data to stable storage and
> enough of the metadata to retrieve the data before returning.
Commit 3f3503adb332 ("NFSD: Use vfs_iocb_iter_write()") replaced:
- flags |= RWF_SYNC;
with:
+ kiocb.ki_flags |= IOCB_DSYNC;
which appears to be correct given:
if (flags & RWF_SYNC)
kiocb_flags |= IOCB_DSYNC;
in kiocb_set_rw_flags(). However the author of that commit did not
appreciate that the previous line in kiocb_set_rw_flags() results
in IOCB_SYNC also being set:
kiocb_flags |= (__force int) (flags & RWF_SUPPORTED);
RWF_SUPPORTED contains RWF_SYNC, and RWF_SYNC is the same bit as
IOCB_SYNC. Reviewers at the time did not catch the omission.
Reported-by: Mike Snitzer <snitzer(a)kernel.org>
Closes: https://lore.kernel.org/linux-nfs/20251018005431.3403-1-cel@kernel.org/T/#t
Fixes: 3f3503adb332 ("NFSD: Use vfs_iocb_iter_write()")
Cc: stable(a)vger.kernel.org
Reviewed-by: Jeff Layton <jlayton(a)kernel.org>
Reviewed-by: NeilBrown <neil(a)brown.name>
Reviewed-by: Christoph Hellwig <hch(a)lst.de>
Signed-off-by: Chuck Lever <chuck.lever(a)oracle.com>
---
fs/nfsd/vfs.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f537a7b4ee01..5333d49910d9 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1314,8 +1314,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
stable = NFS_UNSTABLE;
init_sync_kiocb(&kiocb, file);
kiocb.ki_pos = offset;
- if (stable && !fhp->fh_use_wgather)
- kiocb.ki_flags |= IOCB_DSYNC;
+ if (likely(!fhp->fh_use_wgather)) {
+ switch (stable) {
+ case NFS_FILE_SYNC:
+ /* persist data and timestamps */
+ kiocb.ki_flags |= IOCB_DSYNC | IOCB_SYNC;
+ break;
+ case NFS_DATA_SYNC:
+ /* persist data only */
+ kiocb.ki_flags |= IOCB_DSYNC;
+ break;
+ }
+ }
nvecs = xdr_buf_to_bvec(rqstp->rq_bvec, rqstp->rq_maxpages, payload);
iov_iter_bvec(&iter, ITER_SOURCE, rqstp->rq_bvec, nvecs, *cnt);
--
2.51.0
From: Viken Dadhaniya <viken.dadhaniya(a)oss.qualcomm.com>
[ Upstream commit fc6a5b540c02d1ec624e4599f45a17f2941a5c00 ]
GENI UART driver currently supports only non-DFS (Dynamic Frequency
Scaling) mode for source frequency selection. However, to operate correctly
in DFS mode, the GENI SCLK register must be programmed with the appropriate
DFS index. Failing to do so can result in incorrect frequency selection
Add support for Dynamic Frequency Scaling (DFS) mode in the GENI UART
driver by configuring the GENI_CLK_SEL register with the appropriate DFS
index. This ensures correct frequency selection when operating in DFS mode.
Replace the UART driver-specific logic for clock selection with the GENI
common driver function to obtain the desired frequency and corresponding
clock index. This improves maintainability and consistency across
GENI-based drivers.
Signed-off-by: Viken Dadhaniya <viken.dadhaniya(a)oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250903063136.3015237-1-viken.dadhaniya@oss.qual…
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
---
LLM Generated explanations, may be completely bogus:
YES
- Fixes a real bug in DFS mode: The UART driver previously never
programmed the GENI DFS clock selection register, so on platforms
where the GENI core clock runs in Dynamic Frequency Scaling (DFS)
mode, UART could pick the wrong source clock and thus the wrong baud.
This change explicitly programs the DFS index so the selected source
frequency matches the computed divider.
- New write of the DFS index to the hardware register:
drivers/tty/serial/qcom_geni_serial.c:1306
- DFS clock select register and mask exist in the common header:
include/linux/soc/qcom/geni-se.h:85, include/linux/soc/qcom/geni-
se.h:145
- Uses the common GENI clock-matching helper instead of ad‑hoc logic:
The patch replaces driver-local clock rounding/tolerance code with the
GENI core’s frequency matching routine, ensuring consistent clock
selection across GENI-based drivers and improving maintainability.
- New source frequency selection via common helper:
drivers/tty/serial/qcom_geni_serial.c:1270
- Common helper is present and exported in the GENI core:
drivers/soc/qcom/qcom-geni-se.c:720
- Maintains existing divisor programming and adds a safety check: The
driver still computes and programs the serial clock divider, now with
a guard to avoid overflow of the divider field.
- Divider computation and range check:
drivers/tty/serial/qcom_geni_serial.c:1277,
drivers/tty/serial/qcom_geni_serial.c:1279
- Divider write to both M/S clock cfg registers remains as before:
drivers/tty/serial/qcom_geni_serial.c:1303,
drivers/tty/serial/qcom_geni_serial.c:1304
- Consistency with other GENI drivers already using DFS index
programming: Other GENI protocol drivers (e.g., SPI) already program
`SE_GENI_CLK_SEL` with the index returned by the common helper, so
this change aligns UART with established practice and reduces risk.
- SPI uses the same pattern: drivers/spi/spi-geni-qcom.c:383,
drivers/spi/spi-geni-qcom.c:385–386
- Small, contained, and low-risk:
- Touches a single driver file with a localized change in clock setup.
- No ABI or architectural changes; relies on existing GENI core
helpers and headers.
- Additional register write is standard and used by other GENI
drivers; masks index with `CLK_SEL_MSK`
(include/linux/soc/qcom/geni-se.h:145) for safety.
- Includes defensive error handling if no matching clock level is
found and a divider overflow guard
(drivers/tty/serial/qcom_geni_serial.c:1271–1275,
drivers/tty/serial/qcom_geni_serial.c:1279–1281).
- User impact: Without this, UART on DFS-enabled platforms can run at an
incorrect baud, causing broken serial communication (including
console). The fix directly addresses that functional issue.
- Stable backport criteria:
- Fixes an important, user-visible bug (incorrect baud under DFS).
- Minimal and self-contained change, no new features or interfaces.
- Leverages existing, widely used GENI core APIs already present in
stable series.
Note: One minor nit in the debug print includes an extra newline before
`clk_idx`, but it’s harmless and does not affect functionality
(drivers/tty/serial/qcom_geni_serial.c:1284).
drivers/tty/serial/qcom_geni_serial.c | 92 ++++++---------------------
1 file changed, 21 insertions(+), 71 deletions(-)
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 81f385d900d06..ff401e331f1bb 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+/*
+ * Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */
#define __DISABLE_TRACE_MMIO__
@@ -1253,75 +1256,15 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
return 0;
}
-static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk,
- unsigned int *clk_div, unsigned int percent_tol)
-{
- unsigned long freq;
- unsigned long div, maxdiv;
- u64 mult;
- unsigned long offset, abs_tol, achieved;
-
- abs_tol = div_u64((u64)desired_clk * percent_tol, 100);
- maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
- div = 1;
- while (div <= maxdiv) {
- mult = (u64)div * desired_clk;
- if (mult != (unsigned long)mult)
- break;
-
- offset = div * abs_tol;
- freq = clk_round_rate(clk, mult - offset);
-
- /* Can only get lower if we're done */
- if (freq < mult - offset)
- break;
-
- /*
- * Re-calculate div in case rounding skipped rates but we
- * ended up at a good one, then check for a match.
- */
- div = DIV_ROUND_CLOSEST(freq, desired_clk);
- achieved = DIV_ROUND_CLOSEST(freq, div);
- if (achieved <= desired_clk + abs_tol &&
- achieved >= desired_clk - abs_tol) {
- *clk_div = div;
- return freq;
- }
-
- div = DIV_ROUND_UP(freq, desired_clk);
- }
-
- return 0;
-}
-
-static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
- unsigned int sampling_rate, unsigned int *clk_div)
-{
- unsigned long ser_clk;
- unsigned long desired_clk;
-
- desired_clk = baud * sampling_rate;
- if (!desired_clk)
- return 0;
-
- /*
- * try to find a clock rate within 2% tolerance, then within 5%
- */
- ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2);
- if (!ser_clk)
- ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5);
-
- return ser_clk;
-}
-
static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
unsigned long clk_rate;
- unsigned int avg_bw_core;
+ unsigned int avg_bw_core, clk_idx;
unsigned int clk_div;
u32 ver, sampling_rate;
u32 ser_clk_cfg;
+ int ret;
sampling_rate = UART_OVERSAMPLING;
/* Sampling rate is halved for IP versions >= 2.5 */
@@ -1329,17 +1272,22 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
if (ver >= QUP_SE_VERSION_2_5)
sampling_rate /= 2;
- clk_rate = get_clk_div_rate(port->se.clk, baud,
- sampling_rate, &clk_div);
- if (!clk_rate) {
- dev_err(port->se.dev,
- "Couldn't find suitable clock rate for %u\n",
- baud * sampling_rate);
+ ret = geni_se_clk_freq_match(&port->se, baud * sampling_rate, &clk_idx, &clk_rate, false);
+ if (ret) {
+ dev_err(port->se.dev, "Failed to find src clk for baud rate: %d ret: %d\n",
+ baud, ret);
+ return ret;
+ }
+
+ clk_div = DIV_ROUND_UP(clk_rate, baud * sampling_rate);
+ /* Check if calculated divider exceeds maximum allowed value */
+ if (clk_div > (CLK_DIV_MSK >> CLK_DIV_SHFT)) {
+ dev_err(port->se.dev, "Calculated clock divider %u exceeds maximum\n", clk_div);
return -EINVAL;
}
- dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
- baud * sampling_rate, clk_rate, clk_div);
+ dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n",
+ baud * sampling_rate, clk_rate, clk_div, clk_idx);
uport->uartclk = clk_rate;
port->clk_rate = clk_rate;
@@ -1359,6 +1307,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
+ /* Configure clock selection register with the selected clock index */
+ writel(clk_idx & CLK_SEL_MSK, uport->membase + SE_GENI_CLK_SEL);
return 0;
}
--
2.51.0