mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
usb: xhci-mtk: fix a short packet issue of gen1 isoc-in transfer
For Gen1 isoc-in transfer, host still send out unexpected ACK after device
finish the burst with a short packet, this will cause an exception on the
connected device, such as, a usb 4k camera.
It can be fixed by setting rxfifo depth less than 4k bytes, prefer to use
3k here, the side-effect is that may cause performance drop about 10%,
including bulk transfer.
Fixes: 926d60ae64
("usb: xhci-mtk: modify the SOF/ITP interval for mt8195")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/20240104061640.7335-2-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
223b4ef5a3
commit
017dbfc05c
@ -7,6 +7,7 @@
|
||||
* Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -73,6 +74,9 @@
|
||||
#define FRMCNT_LEV1_RANG (0x12b << 8)
|
||||
#define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
|
||||
|
||||
#define HSCH_CFG1 0x960
|
||||
#define SCH3_RXFIFO_DEPTH_MASK GENMASK(21, 20)
|
||||
|
||||
#define SS_GEN2_EOF_CFG 0x990
|
||||
#define SSG2EOF_OFFSET 0x3c
|
||||
|
||||
@ -114,6 +118,8 @@
|
||||
#define SSC_IP_SLEEP_EN BIT(4)
|
||||
#define SSC_SPM_INT_EN BIT(1)
|
||||
|
||||
#define SCH_FIFO_TO_KB(x) ((x) >> 10)
|
||||
|
||||
enum ssusb_uwk_vers {
|
||||
SSUSB_UWK_V1 = 1,
|
||||
SSUSB_UWK_V2,
|
||||
@ -165,6 +171,35 @@ static void xhci_mtk_set_frame_interval(struct xhci_hcd_mtk *mtk)
|
||||
writel(value, hcd->regs + SS_GEN2_EOF_CFG);
|
||||
}
|
||||
|
||||
/*
|
||||
* workaround: usb3.2 gen1 isoc rx hw issue
|
||||
* host send out unexpected ACK afer device fininsh a burst transfer with
|
||||
* a short packet.
|
||||
*/
|
||||
static void xhci_mtk_rxfifo_depth_set(struct xhci_hcd_mtk *mtk)
|
||||
{
|
||||
struct usb_hcd *hcd = mtk->hcd;
|
||||
u32 value;
|
||||
|
||||
if (!mtk->rxfifo_depth)
|
||||
return;
|
||||
|
||||
value = readl(hcd->regs + HSCH_CFG1);
|
||||
value &= ~SCH3_RXFIFO_DEPTH_MASK;
|
||||
value |= FIELD_PREP(SCH3_RXFIFO_DEPTH_MASK,
|
||||
SCH_FIFO_TO_KB(mtk->rxfifo_depth) - 1);
|
||||
writel(value, hcd->regs + HSCH_CFG1);
|
||||
}
|
||||
|
||||
static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk)
|
||||
{
|
||||
/* workaround only for mt8195 */
|
||||
xhci_mtk_set_frame_interval(mtk);
|
||||
|
||||
/* workaround for SoCs using SSUSB about before IPM v1.6.0 */
|
||||
xhci_mtk_rxfifo_depth_set(mtk);
|
||||
}
|
||||
|
||||
static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
|
||||
{
|
||||
struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
|
||||
@ -448,8 +483,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* workaround only for mt8195 */
|
||||
xhci_mtk_set_frame_interval(mtk);
|
||||
xhci_mtk_init_quirk(mtk);
|
||||
}
|
||||
|
||||
ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
|
||||
@ -527,6 +561,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
||||
of_property_read_u32(node, "mediatek,u2p-dis-msk",
|
||||
&mtk->u2p_dis_msk);
|
||||
|
||||
of_property_read_u32(node, "rx-fifo-depth", &mtk->rxfifo_depth);
|
||||
|
||||
ret = usb_wakeup_of_property_parse(mtk, node);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to parse uwk property\n");
|
||||
|
@ -171,6 +171,8 @@ struct xhci_hcd_mtk {
|
||||
struct regmap *uwk;
|
||||
u32 uwk_reg_base;
|
||||
u32 uwk_vers;
|
||||
/* quirk */
|
||||
u32 rxfifo_depth;
|
||||
};
|
||||
|
||||
static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
|
||||
|
Loading…
Reference in New Issue
Block a user