[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen master] drivers/char: fix handling cable re-plug in XHCI console driver



commit 7aadb75e286df576278c20257936e53a348d23ee
Author:     Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
AuthorDate: Mon Sep 26 11:12:39 2022 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Sep 26 11:12:39 2022 +0200

    drivers/char: fix handling cable re-plug in XHCI console driver
    
    When cable is unplugged, dbc_ensure_running() correctly detects this
    situation (DBC_CTRL_DCR flag is clear), and prevent sending data
    immediately to the device. It gets only queued in work ring buffers.
    When cable is plugged in again, subsequent dbc_flush() will send the
    buffered data.
    But there is a corner case, where no subsequent data was buffered in the
    work buffer, but a TRB was still pending. Ring the doorbell to let the
    controller re-send them. For console output it is rare corner case (TRB
    is pending for a very short time), but for console input it is very
    normal case (there is always one pending TRB for input).
    
    Extract doorbell ringing into separate function to avoid duplication.
    
    Signed-off-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/drivers/char/xhci-dbc.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/xen/drivers/char/xhci-dbc.c b/xen/drivers/char/xhci-dbc.c
index 00ab4ae4a2..5f47733c18 100644
--- a/xen/drivers/char/xhci-dbc.c
+++ b/xen/drivers/char/xhci-dbc.c
@@ -546,6 +546,15 @@ static unsigned int dbc_work_ring_space_to_end(const 
struct dbc_work_ring *ring)
     return ring->deq - ring->enq;
 }
 
+static void dbc_ring_doorbell(struct dbc *dbc, int doorbell)
+{
+    uint32_t __iomem *db_reg = &dbc->dbc_reg->db;
+    uint32_t db = (readl(db_reg) & ~DBC_DOORBELL_TARGET_MASK) |
+                  (doorbell << DBC_DOORBELL_TARGET_SHIFT);
+
+    writel(db, db_reg);
+}
+
 static void dbc_push_trb(struct dbc *dbc, struct xhci_trb_ring *ring,
                          uint64_t dma, uint64_t len)
 {
@@ -973,6 +982,8 @@ static bool dbc_ensure_running(struct dbc *dbc)
         writel(ctrl | (1U << DBC_CTRL_DRC), &reg->ctrl);
         writel(readl(&reg->portsc) | (1U << DBC_PSC_PED), &reg->portsc);
         wmb();
+        dbc_ring_doorbell(dbc, dbc->dbc_iring.db);
+        dbc_ring_doorbell(dbc, dbc->dbc_oring.db);
     }
 
     return true;
@@ -990,10 +1001,6 @@ static bool dbc_ensure_running(struct dbc *dbc)
 static void dbc_flush(struct dbc *dbc, struct xhci_trb_ring *trb,
                       struct dbc_work_ring *wrk)
 {
-    struct dbc_reg *reg = dbc->dbc_reg;
-    uint32_t db = (readl(&reg->db) & ~DBC_DOORBELL_TARGET_MASK) |
-                  (trb->db << DBC_DOORBELL_TARGET_SHIFT);
-
     if ( xhci_trb_ring_full(trb) )
         return;
 
@@ -1017,7 +1024,7 @@ static void dbc_flush(struct dbc *dbc, struct 
xhci_trb_ring *trb,
     }
 
     wmb();
-    writel(db, &reg->db);
+    dbc_ring_doorbell(dbc, trb->db);
 }
 
 /**
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.