summaryrefslogtreecommitdiff
path: root/drivers/usb/mtu3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/mtu3')
-rw-r--r--drivers/usb/mtu3/Kconfig2
-rw-r--r--drivers/usb/mtu3/mtu3.h37
-rw-r--r--drivers/usb/mtu3/mtu3_core.c2
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c43
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c4
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c8
-rw-r--r--drivers/usb/mtu3/mtu3_host.c33
-rw-r--r--drivers/usb/mtu3/mtu3_hw_regs.h1
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c21
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.c53
-rw-r--r--drivers/usb/mtu3/mtu3_trace.h8
11 files changed, 140 insertions, 72 deletions
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index bf98fd36341d..d281da1cdbcc 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -21,7 +21,7 @@ config USB_MTU3
if USB_MTU3
choice
- bool "MTU3 Mode Selection"
+ prompt "MTU3 Mode Selection"
default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
default USB_MTU3_HOST if (USB && !USB_GADGET)
default USB_MTU3_GADGET if (!USB && USB_GADGET)
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 2d7b57e07eee..ba5a63669e5f 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -16,6 +16,7 @@
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/list.h>
+#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
#include <linux/usb.h>
@@ -64,7 +65,7 @@ struct mtu3_request;
#define MTU3_U3_IP_SLOT_DEFAULT 2
#define MTU3_U2_IP_SLOT_DEFAULT 1
-/**
+/*
* IP TRUNK version
* from 0x1003 version, USB3 Gen2 is supported, two changes affect driver:
* 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted,
@@ -73,9 +74,9 @@ struct mtu3_request;
*/
#define MTU3_TRUNK_VERS_1003 0x1003
-/**
+/*
* Normally the device works on HS or SS, to simplify fifo management,
- * devide fifo into some 512B parts, use bitmap to manage it; And
+ * divide fifo into some 512B parts, use bitmap to manage it; And
* 128 bits size of bitmap is large enough, that means it can manage
* up to 64KB fifo size.
* NOTE: MTU3_EP_FIFO_UNIT should be power of two
@@ -84,13 +85,13 @@ struct mtu3_request;
#define MTU3_FIFO_BIT_SIZE 128
#define MTU3_U2_IP_EP0_FIFO_SIZE 64
-/**
+/*
* Maximum size of ep0 response buffer for ch9 requests,
* the SET_SEL request uses 6 so far, and GET_STATUS is 2
*/
#define EP0_RESPONSE_BUF 6
-#define BULK_CLKS_CNT 4
+#define BULK_CLKS_CNT 6
/* device operated link and speed got from DEVICE_CONF register */
enum mtu3_speed {
@@ -102,6 +103,7 @@ enum mtu3_speed {
};
/**
+ * enum mtu3_g_ep0_state - endpoint 0 states
* @MU3D_EP0_STATE_SETUP: waits for SETUP or received a SETUP
* without data stage.
* @MU3D_EP0_STATE_TX: IN data stage
@@ -120,11 +122,12 @@ enum mtu3_g_ep0_state {
};
/**
- * MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
+ * enum mtu3_dr_force_mode - indicates host/OTG operating mode
+ * @MTU3_DR_FORCE_NONE: automatically switch host and peripheral mode
* by IDPIN signal.
- * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
+ * @MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
* IDPIN signal.
- * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
+ * @MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
*/
enum mtu3_dr_force_mode {
MTU3_DR_FORCE_NONE = 0,
@@ -133,6 +136,7 @@ enum mtu3_dr_force_mode {
};
/**
+ * struct mtu3_fifo_info - HW FIFO description and management data
* @base: the base address of fifo
* @limit: the bitmap size in bits
* @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
@@ -144,7 +148,7 @@ struct mtu3_fifo_info {
};
/**
- * General Purpose Descriptor (GPD):
+ * struct qmu_gpd - General Purpose Descriptor (GPD):
* The format of TX GPD is a little different from RX one.
* And the size of GPD is 16 bytes.
*
@@ -178,11 +182,13 @@ struct qmu_gpd {
} __packed;
/**
-* dma: physical base address of GPD segment
-* start: virtual base address of GPD segment
-* end: the last GPD element
-* enqueue: the first empty GPD to use
-* dequeue: the first completed GPD serviced by ISR
+* struct mtu3_gpd_ring - GPD ring descriptor
+* @dma: physical base address of GPD segment
+* @start: virtual base address of GPD segment
+* @end: the last GPD element
+* @enqueue: the first empty GPD to use
+* @dequeue: the first completed GPD serviced by ISR
+*
* NOTE: the size of GPD ring should be >= 2
*/
struct mtu3_gpd_ring {
@@ -194,6 +200,7 @@ struct mtu3_gpd_ring {
};
/**
+* struct otg_switch_mtk - OTG/dual-role switch management
* @vbus: vbus 5V used by host mode
* @edev: external connector used to detect vbus and iddig changes
* @id_nb : notifier for iddig(idpin) detection
@@ -221,6 +228,7 @@ struct otg_switch_mtk {
};
/**
+ * struct ssusb_mtk - SuperSpeed USB descriptor (MTK)
* @mac_base: register base address of device MAC, exclude xHCI's
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
@@ -267,6 +275,7 @@ struct ssusb_mtk {
};
/**
+ * struct mtu3_ep - common mtu3 endpoint description
* @fifo_size: it is (@slot + 1) * @fifo_seg_size
* @fifo_seg_size: it is roundup_pow_of_two(@maxp)
*/
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index a3a6282893d0..3a25ee18f144 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -290,7 +290,7 @@ static void mtu3_csr_init(struct mtu3 *mtu)
/* delay about 0.1us from detecting reset to send chirp-K */
mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
- /* enable automatical HWRW from L1 */
+ /* enable automatic HWRW from L1 */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE);
}
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index f0de99858353..c003049bafbf 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -7,6 +7,7 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
+#include <linux/string_choices.h>
#include <linux/uaccess.h>
#include "mtu3.h"
@@ -256,16 +257,7 @@ static const struct mtu3_file_map mtu3_ep_files[] = {
static int mtu3_ep_open(struct inode *inode, struct file *file)
{
- const char *file_name = file_dentry(file)->d_iname;
- const struct mtu3_file_map *f_map;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
- f_map = &mtu3_ep_files[i];
-
- if (strcmp(f_map->name, file_name) == 0)
- break;
- }
+ const struct mtu3_file_map *f_map = debugfs_get_aux(file);
return single_open(file, f_map->show, inode->i_private);
}
@@ -288,17 +280,8 @@ static const struct debugfs_reg32 mtu3_prb_regs[] = {
static int mtu3_probe_show(struct seq_file *sf, void *unused)
{
- const char *file_name = file_dentry(sf->file)->d_iname;
struct mtu3 *mtu = sf->private;
- const struct debugfs_reg32 *regs;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
- regs = &mtu3_prb_regs[i];
-
- if (strcmp(regs->name, file_name) == 0)
- break;
- }
+ const struct debugfs_reg32 *regs = debugfs_get_aux(sf->file);
seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset,
mtu3_readl(mtu->ippc_base, (u32)regs->offset));
@@ -314,13 +297,11 @@ static int mtu3_probe_open(struct inode *inode, struct file *file)
static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- const char *file_name = file_dentry(file)->d_iname;
struct seq_file *sf = file->private_data;
struct mtu3 *mtu = sf->private;
- const struct debugfs_reg32 *regs;
+ const struct debugfs_reg32 *regs = debugfs_get_aux(file);
char buf[32];
u32 val;
- int i;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
@@ -328,12 +309,6 @@ static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf,
if (kstrtou32(buf, 0, &val))
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
- regs = &mtu3_prb_regs[i];
-
- if (strcmp(regs->name, file_name) == 0)
- break;
- }
mtu3_writel(mtu->ippc_base, (u32)regs->offset, val);
return count;
@@ -358,8 +333,8 @@ static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu)
for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
regs = &mtu3_prb_regs[i];
- debugfs_create_file(regs->name, 0644, dir_prb,
- mtu, &mtu3_probe_fops);
+ debugfs_create_file_aux(regs->name, 0644, dir_prb,
+ mtu, regs, &mtu3_probe_fops);
}
mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs,
@@ -379,8 +354,8 @@ static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep,
for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
files = &mtu3_ep_files[i];
- debugfs_create_file(files->name, 0444, dir_ep,
- mep, &mtu3_ep_fops);
+ debugfs_create_file_aux(files->name, 0444, dir_ep,
+ mep, files, &mtu3_ep_fops);
}
}
@@ -479,7 +454,7 @@ static int ssusb_vbus_show(struct seq_file *sf, void *unused)
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
- regulator_is_enabled(otg_sx->vbus) ? "on" : "off");
+ str_on_off(regulator_is_enabled(otg_sx->vbus)));
return 0;
}
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 9b8aded3d95e..ffa5b9401dad 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -7,6 +7,7 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
+#include <linux/string_choices.h>
#include "mtu3.h"
#include "mtu3_dr.h"
#include "mtu3_debug.h"
@@ -109,7 +110,7 @@ int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
if (!vbus)
return 0;
- dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off");
+ dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, str_on_off(is_on));
if (is_on) {
ret = regulator_enable(vbus);
@@ -294,6 +295,7 @@ static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
role_sx_desc.get = ssusb_role_sw_get;
role_sx_desc.fwnode = dev_fwnode(dev);
role_sx_desc.driver_data = ssusb;
+ role_sx_desc.allow_userspace_control = true;
otg_sx->role_sw = usb_role_switch_register(dev, &role_sx_desc);
if (IS_ERR(otg_sx->role_sw))
return PTR_ERR(otg_sx->role_sw);
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 80236e7b0895..bf73fbc29976 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -7,6 +7,7 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
+#include <linux/string_choices.h>
#include "mtu3.h"
#include "mtu3_trace.h"
@@ -23,7 +24,6 @@ __acquires(mep->mtu->lock)
req->status = status;
trace_mtu3_req_complete(mreq);
- spin_unlock(&mtu->lock);
/* ep0 makes use of PIO, needn't unmap it */
if (mep->epnum)
@@ -32,6 +32,7 @@ __acquires(mep->mtu->lock)
dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
mep->name, req, req->status, req->actual, req->length);
+ spin_unlock(&mtu->lock);
usb_gadget_giveback_request(&mep->ep, req);
spin_lock(&mtu->lock);
}
@@ -133,10 +134,9 @@ static int mtu3_ep_disable(struct mtu3_ep *mep)
{
struct mtu3 *mtu = mep->mtu;
- mtu3_qmu_stop(mep);
-
/* abort all pending requests */
nuke(mep, -ESHUTDOWN);
+ mtu3_qmu_stop(mep);
mtu3_deconfig_ep(mtu, mep);
mtu3_gpd_ring_free(mep);
@@ -491,7 +491,7 @@ static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
unsigned long flags;
dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__,
- is_on ? "on" : "off", mtu->is_active ? "" : "in");
+ str_on_off(is_on), mtu->is_active ? "" : "in");
pm_runtime_get_sync(mtu->dev);
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index f3903367a6a0..7c657ea2dabd 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -11,7 +11,8 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/regmap.h>
#include "mtu3.h"
@@ -33,6 +34,18 @@
#define WC0_SSUSB0_CDEN BIT(6)
#define WC0_IS_SPM_EN BIT(1)
+/* mt8195 */
+#define PERI_WK_CTRL0_8195 0x04
+#define WC0_IS_P_95 BIT(30) /* polarity */
+#define WC0_IS_C_95(x) ((u32)(((x) & 0x7) << 27))
+#define WC0_IS_EN_P3_95 BIT(26)
+#define WC0_IS_EN_P2_95 BIT(25)
+
+#define PERI_WK_CTRL1_8195 0x20
+#define WC1_IS_C_95(x) ((u32)(((x) & 0xf) << 28))
+#define WC1_IS_P_95 BIT(12)
+#define WC1_IS_EN_P0_95 BIT(6)
+
/* mt2712 etc */
#define PERI_SSUSB_SPM_CTRL 0x0
#define SSC_IP_SLEEP_EN BIT(4)
@@ -43,6 +56,9 @@ enum ssusb_uwk_vers {
SSUSB_UWK_V2,
SSUSB_UWK_V1_1 = 101, /* specific revision 1.01 */
SSUSB_UWK_V1_2, /* specific revision 1.02 */
+ SSUSB_UWK_V1_3, /* mt8195 IP0 */
+ SSUSB_UWK_V1_5 = 105, /* mt8195 IP2 */
+ SSUSB_UWK_V1_6, /* mt8195 IP3 */
};
/*
@@ -69,6 +85,21 @@ static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN;
val = enable ? msk : 0;
break;
+ case SSUSB_UWK_V1_3:
+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL1_8195;
+ msk = WC1_IS_EN_P0_95 | WC1_IS_C_95(0xf) | WC1_IS_P_95;
+ val = enable ? (WC1_IS_EN_P0_95 | WC1_IS_C_95(0x1)) : 0;
+ break;
+ case SSUSB_UWK_V1_5:
+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8195;
+ msk = WC0_IS_EN_P2_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+ val = enable ? (WC0_IS_EN_P2_95 | WC0_IS_C_95(0x1)) : 0;
+ break;
+ case SSUSB_UWK_V1_6:
+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8195;
+ msk = WC0_IS_EN_P3_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+ val = enable ? (WC0_IS_EN_P3_95 | WC0_IS_C_95(0x1)) : 0;
+ break;
case SSUSB_UWK_V2:
reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 519a58301f45..ee30ae0a4b54 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -128,6 +128,7 @@
#define TX_FIFOEMPTY BIT(24)
#define TX_SENTSTALL BIT(22)
#define TX_SENDSTALL BIT(21)
+#define TX_FLUSHFIFO BIT(20)
#define TX_TXPKTRDY BIT(16)
#define TX_TXMAXPKTSZ_MSK GENMASK(10, 0)
#define TX_TXMAXPKTSZ(x) ((x) & TX_TXMAXPKTSZ_MSK)
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index d78ae52b4e26..cc8a864dbd63 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -234,6 +234,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
clks[1].id = "ref_ck";
clks[2].id = "mcu_ck";
clks[3].id = "dma_ck";
+ clks[4].id = "xhci_ck";
+ clks[5].id = "frmcnt_ck";
ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks);
if (ret)
return ret;
@@ -305,7 +307,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled)
goto out;
- if (of_property_read_bool(node, "extcon")) {
+ if (of_property_present(node, "extcon")) {
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) {
return dev_err_probe(dev, PTR_ERR(otg_sx->edev),
@@ -429,7 +431,6 @@ static int mtu3_probe(struct platform_device *pdev)
}
device_enable_async_suspend(dev);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
pm_runtime_forbid(dev);
@@ -449,7 +450,7 @@ comm_init_err:
return ret;
}
-static int mtu3_remove(struct platform_device *pdev)
+static void mtu3_remove(struct platform_device *pdev)
{
struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
@@ -467,8 +468,16 @@ static int mtu3_remove(struct platform_device *pdev)
ssusb_gadget_exit(ssusb);
ssusb_host_exit(ssusb);
break;
- default:
- return -EINVAL;
+ case USB_DR_MODE_UNKNOWN:
+ /*
+ * This cannot happen because with dr_mode ==
+ * USB_DR_MODE_UNKNOWN, .probe() doesn't succeed and so
+ * .remove() wouldn't be called at all. However (little
+ * surprising) the compiler isn't smart enough to see that, so
+ * we explicitly have this case item to not make the compiler
+ * wail about an unhandled enumeration value.
+ */
+ break;
}
ssusb_rscs_exit(ssusb);
@@ -476,8 +485,6 @@ static int mtu3_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
-
- return 0;
}
static int resume_ip_and_ports(struct ssusb_mtk *ssusb, pm_message_t msg)
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
index 2ea3157ddb6e..03f26589b056 100644
--- a/drivers/usb/mtu3/mtu3_qmu.c
+++ b/drivers/usb/mtu3/mtu3_qmu.c
@@ -210,6 +210,7 @@ static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring)
return ring->enqueue;
}
+/* @dequeue may be NULL if ring is unallocated or freed */
static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
{
if (ring->dequeue < ring->end)
@@ -220,8 +221,8 @@ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring)
return ring->dequeue;
}
-/* check if a ring is emtpy */
-static int gpd_ring_empty(struct mtu3_gpd_ring *ring)
+/* check if a ring is empty */
+static bool gpd_ring_empty(struct mtu3_gpd_ring *ring)
{
struct qmu_gpd *enq = ring->enqueue;
struct qmu_gpd *next;
@@ -388,6 +389,9 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
}
mtu3_writel(mbase, qcsr, QMU_Q_STOP);
+ if (mep->is_in)
+ mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
ret = readl_poll_timeout_atomic(mbase + qcsr, value,
!(value & QMU_Q_ACTIVE), 1, 1000);
if (ret) {
@@ -395,6 +399,10 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
return;
}
+ /* flush fifo again to make sure the fifo is empty */
+ if (mep->is_in)
+ mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
}
@@ -460,6 +468,37 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
}
/*
+ * when rx error happens (except zlperr), QMU will stop, and RQCPR saves
+ * the GPD encountered error, Done irq will arise after resuming QMU again.
+ */
+static void qmu_error_rx(struct mtu3 *mtu, u8 epnum)
+{
+ struct mtu3_ep *mep = mtu->out_eps + epnum;
+ struct mtu3_gpd_ring *ring = &mep->gpd_ring;
+ struct qmu_gpd *gpd_current = NULL;
+ struct mtu3_request *mreq;
+ dma_addr_t cur_gpd_dma;
+
+ cur_gpd_dma = read_rxq_cur_addr(mtu->mac_base, epnum);
+ gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
+
+ mreq = next_request(mep);
+ if (!mreq || mreq->gpd != gpd_current) {
+ dev_err(mtu->dev, "no correct RX req is found\n");
+ return;
+ }
+
+ mreq->request.status = -EAGAIN;
+
+ /* by pass the current GDP */
+ gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO);
+ mtu3_qmu_resume(mep);
+
+ dev_dbg(mtu->dev, "%s EP%d, current=%p, req=%p\n",
+ __func__, epnum, gpd_current, mreq);
+}
+
+/*
* NOTE: request list maybe is already empty as following case:
* queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)-->
* queue_tx --> process_tasklet(meanwhile, the second one is transferred,
@@ -484,7 +523,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
+ while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -523,7 +562,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
- while (gpd != gpd_current && !GET_GPD_HWO(gpd)) {
+ while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) {
mreq = next_request(mep);
@@ -564,14 +603,18 @@ static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status)
if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) {
errval = mtu3_readl(mbase, U3D_RQERRIR0);
+ mtu3_writel(mbase, U3D_RQERRIR0, errval);
+
for (i = 1; i < mtu->num_eps; i++) {
if (errval & QMU_RX_CS_ERR(i))
dev_err(mtu->dev, "Rx %d CS error!\n", i);
if (errval & QMU_RX_LEN_ERR(i))
dev_err(mtu->dev, "RX %d Length error\n", i);
+
+ if (errval & (QMU_RX_CS_ERR(i) | QMU_RX_LEN_ERR(i)))
+ qmu_error_rx(mtu, i);
}
- mtu3_writel(mbase, U3D_RQERRIR0, errval);
}
if (qmu_status & RXQ_ZLPERR_INT) {
diff --git a/drivers/usb/mtu3/mtu3_trace.h b/drivers/usb/mtu3/mtu3_trace.h
index 03d2a9bac27e..89870175d635 100644
--- a/drivers/usb/mtu3/mtu3_trace.h
+++ b/drivers/usb/mtu3/mtu3_trace.h
@@ -26,7 +26,7 @@ TRACE_EVENT(mtu3_log,
__vstring(msg, vaf->fmt, vaf->va)
),
TP_fast_assign(
- __assign_str(name, dev_name(dev));
+ __assign_str(name);
__assign_vstr(msg, vaf->fmt, vaf->va);
),
TP_printk("%s: %s", __get_str(name), __get_str(msg))
@@ -127,7 +127,7 @@ DECLARE_EVENT_CLASS(mtu3_log_request,
__field(int, no_interrupt)
),
TP_fast_assign(
- __assign_str(name, mreq->mep->name);
+ __assign_str(name);
__entry->mreq = mreq;
__entry->gpd = mreq->gpd;
__entry->actual = mreq->request.actual;
@@ -182,7 +182,7 @@ DECLARE_EVENT_CLASS(mtu3_log_gpd,
__field(u32, dw3)
),
TP_fast_assign(
- __assign_str(name, mep->name);
+ __assign_str(name);
__entry->gpd = gpd;
__entry->dw0 = le32_to_cpu(gpd->dw0_info);
__entry->dw1 = le32_to_cpu(gpd->next_gpd);
@@ -226,7 +226,7 @@ DECLARE_EVENT_CLASS(mtu3_log_ep,
__field(struct mtu3_gpd_ring *, gpd_ring)
),
TP_fast_assign(
- __assign_str(name, mep->name);
+ __assign_str(name);
__entry->type = mep->type;
__entry->slot = mep->slot;
__entry->maxp = mep->ep.maxpacket;