Takashi Iwai 2b6296
From 0d36dede457873404becd7c9cb9d0f2bcfd0dcd9 Mon Sep 17 00:00:00 2001
Takashi Iwai 2b6296
From: Thinh Nguyen <thinh.nguyen@synopsys.com>
Takashi Iwai 2b6296
Date: Wed, 7 Nov 2018 17:55:19 -0800
Takashi Iwai 2b6296
Subject: [PATCH] usb: dwc3: debugfs: Properly print/set link state for HS
Takashi Iwai 2b6296
Git-commit: 0d36dede457873404becd7c9cb9d0f2bcfd0dcd9
Takashi Iwai 2b6296
Patch-mainline: v5.0-rc1
Takashi Iwai 2b6296
References: bsc#1051510
Takashi Iwai 2b6296
Takashi Iwai 2b6296
Highspeed device and below has different state names than superspeed and
Takashi Iwai 2b6296
higher. Add proper checks and printouts of link states for highspeed and
Takashi Iwai 2b6296
below.
Takashi Iwai 2b6296
Takashi Iwai 2b6296
Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
Takashi Iwai 2b6296
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Takashi Iwai 2b6296
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 2b6296
Takashi Iwai 2b6296
---
Takashi Iwai 2b6296
 drivers/usb/dwc3/debug.h   | 29 +++++++++++++++++++++++++++++
Takashi Iwai 2b6296
 drivers/usb/dwc3/debugfs.c | 19 +++++++++++++++++--
Takashi Iwai 2b6296
 2 files changed, 46 insertions(+), 2 deletions(-)
Takashi Iwai 2b6296
Takashi Iwai 2b6296
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
Takashi Iwai 2b6296
index c66d216dcc30..4f75ab3505b7 100644
Takashi Iwai 2b6296
--- a/drivers/usb/dwc3/debug.h
Takashi Iwai 2b6296
+++ b/drivers/usb/dwc3/debug.h
Takashi Iwai 2b6296
@@ -116,6 +116,35 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
Takashi Iwai 2b6296
 	}
Takashi Iwai 2b6296
 }
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
+/**
Takashi Iwai 2b6296
+ * dwc3_gadget_hs_link_string - returns highspeed and below link name
Takashi Iwai 2b6296
+ * @link_state: link state code
Takashi Iwai 2b6296
+ */
Takashi Iwai 2b6296
+static inline const char *
Takashi Iwai 2b6296
+dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
Takashi Iwai 2b6296
+{
Takashi Iwai 2b6296
+	switch (link_state) {
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_U0:
Takashi Iwai 2b6296
+		return "On";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_U2:
Takashi Iwai 2b6296
+		return "Sleep";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_U3:
Takashi Iwai 2b6296
+		return "Suspend";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_SS_DIS:
Takashi Iwai 2b6296
+		return "Disconnected";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_RX_DET:
Takashi Iwai 2b6296
+		return "Early Suspend";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_RECOV:
Takashi Iwai 2b6296
+		return "Recovery";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_RESET:
Takashi Iwai 2b6296
+		return "Reset";
Takashi Iwai 2b6296
+	case DWC3_LINK_STATE_RESUME:
Takashi Iwai 2b6296
+		return "Resume";
Takashi Iwai 2b6296
+	default:
Takashi Iwai 2b6296
+		return "UNKNOWN link state\n";
Takashi Iwai 2b6296
+	}
Takashi Iwai 2b6296
+}
Takashi Iwai 2b6296
+
Takashi Iwai 2b6296
 /**
Takashi Iwai 2b6296
  * dwc3_trb_type_string - returns TRB type as a string
Takashi Iwai 2b6296
  * @type: the type of the TRB
Takashi Iwai 2b6296
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
Takashi Iwai 2b6296
index 1da012f105d7..e613a61ae58a 100644
Takashi Iwai 2b6296
--- a/drivers/usb/dwc3/debugfs.c
Takashi Iwai 2b6296
+++ b/drivers/usb/dwc3/debugfs.c
Takashi Iwai 2b6296
@@ -539,13 +539,17 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
Takashi Iwai 2b6296
 	unsigned long		flags;
Takashi Iwai 2b6296
 	enum dwc3_link_state	state;
Takashi Iwai 2b6296
 	u32			reg;
Takashi Iwai 2b6296
+	u8			speed;
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
 	spin_lock_irqsave(&dwc->lock, flags);
Takashi Iwai 2b6296
 	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
Takashi Iwai 2b6296
 	state = DWC3_DSTS_USBLNKST(reg);
Takashi Iwai 2b6296
-	spin_unlock_irqrestore(&dwc->lock, flags);
Takashi Iwai 2b6296
+	speed = reg & DWC3_DSTS_CONNECTSPD;
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
-	seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
Takashi Iwai 2b6296
+	seq_printf(s, "%s\n", (speed >= DWC3_DSTS_SUPERSPEED) ?
Takashi Iwai 2b6296
+		   dwc3_gadget_link_string(state) :
Takashi Iwai 2b6296
+		   dwc3_gadget_hs_link_string(state));
Takashi Iwai 2b6296
+	spin_unlock_irqrestore(&dwc->lock, flags);
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
 	return 0;
Takashi Iwai 2b6296
 }
Takashi Iwai 2b6296
@@ -563,6 +567,8 @@ static ssize_t dwc3_link_state_write(struct file *file,
Takashi Iwai 2b6296
 	unsigned long		flags;
Takashi Iwai 2b6296
 	enum dwc3_link_state	state = 0;
Takashi Iwai 2b6296
 	char			buf[32];
Takashi Iwai 2b6296
+	u32			reg;
Takashi Iwai 2b6296
+	u8			speed;
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
Takashi Iwai 2b6296
 		return -EFAULT;
Takashi Iwai 2b6296
@@ -583,6 +589,15 @@ static ssize_t dwc3_link_state_write(struct file *file,
Takashi Iwai 2b6296
 		return -EINVAL;
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
 	spin_lock_irqsave(&dwc->lock, flags);
Takashi Iwai 2b6296
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
Takashi Iwai 2b6296
+	speed = reg & DWC3_DSTS_CONNECTSPD;
Takashi Iwai 2b6296
+
Takashi Iwai 2b6296
+	if (speed < DWC3_DSTS_SUPERSPEED &&
Takashi Iwai 2b6296
+	    state != DWC3_LINK_STATE_RECOV) {
Takashi Iwai 2b6296
+		spin_unlock_irqrestore(&dwc->lock, flags);
Takashi Iwai 2b6296
+		return -EINVAL;
Takashi Iwai 2b6296
+	}
Takashi Iwai 2b6296
+
Takashi Iwai 2b6296
 	dwc3_gadget_set_link_state(dwc, state);
Takashi Iwai 2b6296
 	spin_unlock_irqrestore(&dwc->lock, flags);
Takashi Iwai 2b6296
 
Takashi Iwai 2b6296
-- 
Takashi Iwai 2b6296
2.16.4
Takashi Iwai 2b6296